SQL执行计划是数据库优化过程中非常重要的参考依据,它记录了数据库引擎执行一条SQL语句时的完整逻辑和物理操作步骤,通过分析这些步骤可以明确查询的性能瓶颈所在,进而针对性地调整SQL语句或者数据库结构来提升执行效率。

什么是SQL执行计划
当我们在数据库中执行一条查询语句时,数据库优化器会先生成多个可能的执行方案,然后选择成本最低的一个方案来执行,这个最终被选中的方案就是执行计划。执行计划会展示查询的访问路径、连接方式、排序方式等关键信息,是判断查询是否高效的核心依据。
如何获取SQL执行计划
不同的数据库获取执行计划的方式略有差异,以下是常见数据库的获取方法:
MySQL获取执行计划
在查询语句前加上EXPLAIN关键字即可获取执行计划,示例代码如下:
-- 分析查询用户表中年龄大于20的记录的执行计划 EXPLAIN SELECT * FROM user WHERE age > 20;
PostgreSQL获取执行计划
使用EXPLAIN或者EXPLAIN ANALYZE命令,后者还会返回实际的执行时间和行数,示例代码如下:
-- 分析查询订单表中状态为已支付的记录的执行计划 EXPLAIN ANALYZE SELECT * FROM orders WHERE status = 'paid';
Oracle获取执行计划
可以先执行EXPLAIN PLAN FOR语句,再通过SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY)查看执行计划,示例代码如下:
-- 生成执行计划 EXPLAIN PLAN FOR SELECT * FROM employee WHERE dept_id = 10; -- 查看执行计划 SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
执行计划核心指标解读
不同数据库的执行计划输出字段略有不同,但核心指标的含义基本一致,以下是最需要关注的几个指标:
| 指标名称 | 含义说明 |
|---|---|
| id | 查询的序列号,值越大越先执行,相同值则从上到下执行 |
| select_type | 查询类型,比如SIMPLE(简单查询)、PRIMARY(主查询)、SUBQUERY(子查询)等 |
| table | 当前步骤操作的表名 |
| type | 访问类型,性能从好到坏依次为system>const>eq_ref>ref>range>index>ALL |
| possible_keys | 可能使用的索引列表 |
| key | 实际使用的索引,如果为NULL则表示没有使用索引 |
| rows | 预估需要扫描的行数,数值越小越好 |
| Extra | 额外信息,比如Using index(覆盖索引)、Using where(使用了where过滤)、Using filesort(文件排序)、Using temporary(使用临时表)等 |
其中type字段是判断查询性能的核心,如果出现ALL类型,说明进行了全表扫描,在数据量大的情况下性能会非常差,需要优先优化。Extra字段中的Using filesort和Using temporary也说明查询存在性能问题,需要针对性调整。
常见执行计划优化思路
1. 优化索引使用
如果执行计划中key为NULL或者type为ALL,说明没有使用索引或者使用了低效的索引,此时可以根据查询条件添加合适的索引。需要注意索引的创建要符合最左前缀原则,比如查询条件为WHERE a=1 AND b=2,那么创建(a,b)的联合索引比单独创建两个单列索引效果更好。
添加索引的示例代码如下:
-- 给user表的age字段添加索引 CREATE INDEX idx_user_age ON user(age); -- 给orders表的user_id和create_time字段添加联合索引 CREATE INDEX idx_orders_user_time ON orders(user_id, create_time);
2. 避免索引失效场景
即使创建了索引,也可能因为SQL写法问题导致索引失效,常见的索引失效场景包括:
- 在索引字段上使用函数或者运算,比如
WHERE YEAR(create_time)=2023,可以改成WHERE create_time >= '2023-01-01' AND create_time < '2024-01-01' - 使用
LIKE以通配符开头,比如WHERE name LIKE '%张三',可以改成WHERE name LIKE '张三%'如果业务允许 - 查询条件中使用
OR连接,且其中有一个字段没有索引,此时整个查询可能不会使用索引,可以拆分成多个查询用UNION连接 - 索引字段参与类型转换,比如索引字段是字符串类型,查询时用了数字,比如
WHERE phone = 13800138000,应该改成WHERE phone = '13800138000'
3. 优化查询语句逻辑
如果执行计划中出现Using filesort或者Using temporary,可以通过调整查询逻辑来优化:
- 排序字段尽量使用索引字段,避免数据库额外进行排序操作
- 减少
SELECT *的使用,只查询需要的字段,尽量使用覆盖索引,减少回表操作 - 子查询尽量改成连接查询,连接查询的性能通常优于子查询
- 大分页查询可以改成基于主键的游标分页,比如
WHERE id > 上一页最后一条id LIMIT 10,避免LIMIT 100000,10这种大偏移量的查询
优化大分页查询的示例代码如下:
-- 低效的大分页查询 SELECT * FROM article ORDER BY id LIMIT 100000, 10; -- 优化后的游标分页查询 SELECT * FROM article WHERE id > 100000 ORDER BY id LIMIT 10;
4. 调整数据库表结构
如果表结构本身存在问题,也会影响执行计划的效率:
- 对于大表可以进行分库分表,减少单表的数据量
- 对于频繁查询的字段可以冗余存储,避免多表连接查询
- 选择合适的数据类型,比如用
INT存储状态码而不是VARCHAR,减少存储空间和比较成本
执行计划分析实践案例
假设我们有一个订单表orders,包含字段id(主键)、user_id、status、create_time,现在需要查询用户ID为1001且状态为已支付的订单,原始SQL如下:
SELECT * FROM orders WHERE user_id = 1001 AND status = 'paid';
执行EXPLAIN后得到的执行计划中type为ALL,rows为100000,说明进行了全表扫描。此时我们可以给orders表添加(user_id, status)的联合索引:
CREATE INDEX idx_orders_user_status ON orders(user_id, status);
再次执行EXPLAIN,可以看到type变成了ref,key为idx_orders_user_status,rows变成了10,查询性能得到了大幅提升。
总结
分析SQL执行计划是数据库优化的核心步骤,首先要学会获取不同数据库的执行计划,然后重点解读type、key、rows、Extra等核心指标,定位性能瓶颈。优化时优先从索引入手,避免索引失效,再调整查询逻辑和表结构,逐步提升查询效率。平时开发中遇到慢查询时,先查看执行计划再调整,能避免很多盲目的优化操作,让数据处理效率得到稳定提升。