Mysql执行计划

171 阅读4分钟

MySQL 执行计划(Execution Plan)是用于了解 SQL 查询在数据库中实际执行方式的工具。通过分析执行计划,可以诊断查询的性能瓶颈并进行优化。

在 MySQL 中,通过 EXPLAINEXPLAIN ANALYZE 查看查询的执行计划。以下是执行计划的详细解析:


1. EXPLAIN 查询执行计划

执行以下命令获取查询执行计划:

EXPLAIN SELECT * FROM table_name WHERE condition;

执行结果包含以下字段:

字段名描述
id查询中每个 SELECT 子句的标识符,表示执行顺序。
select_type查询的类型(简单查询、联合查询、子查询等)。
table查询涉及的表名。
partitions查询中扫描的分区(如果使用分区表)。
type访问类型,表示查询访问数据的方法。
possible_keys查询可能使用的索引。
key实际使用的索引。
key_len索引的长度。
ref索引中被使用的列或常量。
rows预计需要读取的行数。
filtered按过滤条件保留的行的百分比。
Extra额外的信息,例如使用临时表或排序等。

2. 常见字段详解

(1) id

  • 每个 id 代表一个子查询或查询块。
  • 数字越大,优先执行。
  • 同一个 id 的语句按顺序执行。

(2) select_type

描述当前查询的类型:

  • SIMPLE:简单查询,没有子查询或联合查询。
  • PRIMARY:主查询(最外层的 SELECT)。
  • UNION:联合查询的第二个或后续 SELECT。
  • SUBQUERY:子查询。
  • DEPENDENT SUBQUERY:依赖于外部查询的子查询。
  • DERIVED:派生表(子查询作为 FROM 的一部分)。

(3) type(访问类型)

访问类型表示 MySQL 检索数据的效率,从最优到最差排序如下:

  1. system:表仅有一行记录。
  2. const:表仅返回一行结果,通常用于主键或唯一索引的等值查询。
  3. eq_ref:通过索引匹配单行记录,常用于主键和唯一索引。
  4. ref:使用非唯一索引或前缀索引扫描匹配记录。
  5. range:索引范围扫描,常见于 BETWEEN<>IN 等条件。
  6. index:全索引扫描,扫描整个索引树而不是表数据。
  7. ALL:全表扫描,性能最差。

(4) possible_keyskey

  • possible_keys:查询中可能使用的索引。
  • key:查询实际使用的索引。如果为空,则未使用索引。

(5) rows

预计需要扫描的行数。行数越少,查询性能越高。

(6) Extra

额外的信息,包括查询优化的提示:

  • Using index:覆盖索引查询,仅从索引中读取数据,不需要回表。
  • Using where:查询过滤了数据,需要通过 WHERE 条件筛选。
  • Using temporary:使用临时表(通常因分组或排序)。
  • Using filesort:未使用索引排序,可能导致性能下降。

3. EXPLAIN ANALYZE

EXPLAIN ANALYZE 不仅展示查询计划,还提供查询的实际执行时间和行数。示例如下:

EXPLAIN ANALYZE SELECT * FROM users WHERE id = 10;

结果包含以下额外信息:

  • Actual Rows:查询实际返回的行数。
  • Filtered:实际数据过滤比例。
  • Execution Time:每个步骤的执行耗时。

4. 查询优化建议

  1. 使用索引

    • 对查询中频繁使用的字段添加索引。
    • 避免全表扫描(ALL),尽量使用 typerefrange 的访问方式。
  2. 优化 WHERE 条件

    • 使用等值条件替代范围条件。
    • 避免在索引字段上使用函数或表达式。
  3. 避免临时表和排序

    • 避免 Using temporaryUsing filesort
    • 尽量使用覆盖索引(Using index)。
  4. 拆分复杂查询

    • 将多表关联、子查询分解为多个简单查询。
  5. 更新统计信息

    • 定期运行 ANALYZE TABLEOPTIMIZE TABLE,确保优化器拥有最新的统计信息。
  6. 检查慢查询日志

    • 启用慢查询日志,定位耗时较高的查询。

示例:执行计划分析

查询:

EXPLAIN SELECT * FROM orders WHERE user_id = 1001 AND order_date > '2025-01-01';

结果:

idselect_typetabletypepossible_keyskeykey_lenrowsExtra
1SIMPLEordersrangeuser_id_indexuser_id_idx4500Using where; Using index

分析:

  • typerange,使用索引进行范围扫描。
  • keyuser_id_idx 索引被使用。
  • ExtraUsing where 表示使用了索引,但仍需过滤数据。
  • 优化建议:该查询已使用索引,性能较好,无需优化。

执行计划的选择规则

MySQL 优化器会根据以下因素决定采用哪种扫描方式:

  1. 索引是否存在:没有索引的列只能通过全表扫描查询。
  2. 索引选择性:选择性越高的索引,优化器越倾向使用。(有时候优化器选择不对,就要选择force_index强制选择走某个索引)
  3. 查询条件的范围:范围越大,范围扫描的成本越高。
  4. 返回结果的数量:优化器会衡量扫描的开销和返回结果集的大小。
  5. 表的数据量:对于小表,全表扫描可能比索引扫描更快。