使用 EXPLAIN 解读执行计划

SQL 是一种声明性语言,因此无法通过 SQL 语句直接判断一条查询的执行是否有效率,但是可以使用 EXPLAIN 语句查看当前的执行计划。

示例

我们这里准备一个简单的示例,帮助你理解使用 EXPLAIN 解读执行计划。

  1. > drop table if exists a;
  2. > create table a(a int);
  3. > insert into a values(1),(2),(3),(4),(5),(6),(7),(8);
  4. > select count(*) from a where a>=2 and a<=8;
  5. +----------+
  6. | count(*) |
  7. +----------+
  8. | 7 |
  9. +----------+
  10. 1 row in set (0.00 sec)
  11. > explain select count(*) from a where a>=2 and a<=8;
  12. +-----------------------------------------------------------------------------------+
  13. | QUERY PLAN |
  14. +-----------------------------------------------------------------------------------+
  15. | Project |
  16. | -> Aggregate |
  17. | Aggregate Functions: starcount(1) |
  18. | -> Table Scan on aab.a |
  19. | Filter Cond: (CAST(a.a AS BIGINT) >= 2), (CAST(a.a AS BIGINT) <= 8) |
  20. +-----------------------------------------------------------------------------------+
  21. 5 rows in set (0.00 sec)

以上是该查询的执行计划结果。从 Filter Cond 算子开始向上看,查询的执行过程如下:

  1. 先执行过滤条件 Filter Cond:即过滤出数据类型为 BIGINT 且大于等于 2,小于等于 8 的整数,按照计算推理,应该为 (2),(3),(4),(5),(6),(7),(8)
  2. 扫描数据库 aab 中的表 a。
  3. 聚合计算满足条件整数的个数,为 7 个。

最终,得到查询结果为 7,即 count(*) = 7。

评估当前的性能

EXPLAIN 语句只返回查询的执行计划,并不执行该查询。若要获取实际的执行时间,可执行该查询,或使用 EXPLAIN ANALYZE 语句。

什么是 EXPLAIN ANALYZE

EXPLAIN ANALYZE 是一个用于查询的分析工具,它将向你显示 SQL 在查询上花费的时间以及原因。它将计划查询、检测它并执行它,同时计算行数并测量在执行计划的各个点花费的时间。执行完成后,EXPLAIN ANALYZE 将打印计划和测量结果,而不是查询结果。

除了正常 EXPLAIN 将打印的查询计划和估计成本之外,EXPLAIN ANALYZE 还打印执行计划中各个迭代器的实际成本。

如何使用它?

这里还是继续使用上述示例,你可以执行下面的代码:

  1. > explain analyze select count(*) from a where a>=2 and a<=8;
  2. +-------------------------------------------------------------------------------------------------------------------------------+
  3. | QUERY PLAN |
  4. +-------------------------------------------------------------------------------------------------------------------------------+
  5. | Project |
  6. | Analyze: timeConsumed=0us inputRows=1 outputRows=1 inputSize=8bytes outputSize=8bytes memorySize=8bytes |
  7. | -> Aggregate |
  8. | Analyze: timeConsumed=3317us inputRows=2 outputRows=2 inputSize=8bytes outputSize=16bytes memorySize=16bytes |
  9. | Aggregate Functions: starcount(1) |
  10. | -> Table Scan on aab.a |
  11. | Analyze: timeConsumed=6643us inputRows=31 outputRows=24 inputSize=96bytes outputSize=64bytes memorySize=64bytes |
  12. | Filter Cond: (CAST(a.a AS BIGINT) >= 2), (CAST(a.a AS BIGINT) <= 8) |
  13. +-------------------------------------------------------------------------------------------------------------------------------+
  14. 8 rows in set (0.00 sec)

从打印的执行结果来看,当分别执行聚合计算和扫描表时,都会得出以下几个测量值,这些测量值可以作为参考项:

  • 总耗时 timeConsumed
  • 读取的行数
  • 读取的容量大小
  • 内存大小

通过在这些信息,你可以分析查询并理解它们为何是这样的表现,可以从以下几个方面进行探索:

  • 执行这些查询,需要花费多久?你可以查看总耗时。

  • 为什么执行当前的查询计划,而不是其他的执行计划?你可以查看行计数器。当估计行数与实际行数之间的巨大差异(即,几个数量级或更多)时,说明优化器根据估计选择计划,但查看实际执行可以方便你得知到底哪个执行计划更好。

所以使用 EXPLAIN ANALYZE 就是分析查询执行。

从上面的输出结果来看,执行以上示例查询耗时 0.00 秒,说明执行性能较为理想。也由于我们这次示例中执行的查询简单,满足较高的执行性能。

更多关于 EXPLAIN ANALYZE 的信息,请参见 EXPLAIN ANALYZE