CodeGym /课程 /SQL SELF /啥是 EXPLAIN,怎么用它分析查询

啥是 EXPLAIN,怎么用它分析查询

SQL SELF
第 41 级, 课程 2
可用

想象一下,你在开发一个应用,结果有个查询突然成了数据库里最耗资源的。你开始发现应用卡顿、出错。这时候 EXPLAIN 就登场了,它能帮你搞清楚到底哪里出问题了。基于 EXPLAIN 的分析来优化查询,可以帮你省资源、省时间,还能让用户用你的应用更爽。

EXPLAIN 就是让你能“透视” PostgreSQL,看看数据库到底打算怎么执行你的查询。它会告诉你会不会用到索引,还是直接全表扫描,优化器会做哪些步骤,顺序是啥,中间结果大概有多大。

换句话说,EXPLAIN 能让你知道执行查询时会发生啥:这个查询“重不重”,大概要处理多少行,会用到哪些资源。遇到查询突然变慢,用它查原因特别香。

EXPLAIN 就像黑暗里的手电筒:有了它你能看到底层发生了啥,哪里出岔子一目了然。

EXPLAIN 命令语法

来看看 EXPLAIN 的基本语法:

EXPLAIN 你的_SQL_查询;

查询示例:

EXPLAIN SELECT * FROM students WHERE age > 20;

你运行这个命令时,PostgreSQL 不会真的执行查询。它只会给你看执行计划。就像盖房子前先看草图——提前知道会发生啥,避免踩坑。

输出示例:

Seq Scan on students  (cost=0.00..35.00 rows=7 width=37)
  Filter: (age > 20)

这个输出看着有点吓人,别慌——我们马上拆解下它的主要部分。

基础执行计划解析

来拆解下刚才的结果:

  1. Seq Scan on students —— 这意思是 PostgreSQL 会把 students 表全表扫描(顺序扫描)。这不一定是坏事,但表大了 Seq Scan 就慢了。

  2. cost=0.00..35.00 —— 这是操作的成本估算:

    • Startup Cost:操作的起始成本(这里是 0.00)。
    • Total Cost:操作完成的总成本(这里 35.00)。
  3. rows=7 —— PostgreSQL 估计 age > 20 这个条件能查出 7 行。这叫“基数”(cardinality)。如果你看到估算很离谱,可能是表统计信息过时了。

  4. width=37 —— 这是一行的平均字节数。

  5. Filter: (age > 20) —— PostgreSQL 会对每行都用这个过滤条件。

所以 EXPLAIN 的输出能让你了解 PostgreSQL 的策略和假设。你可以用这些信息来优化查询。

EXPLAIN 命令选项

虽然基础 EXPLAIN 已经很有用,你还可以加这些选项让它更强:

ANALYZE

加上这个选项,PostgreSQL 不光给你看计划,还会真的执行查询,给你实际数据。比如:

EXPLAIN ANALYZE SELECT * FROM students WHERE age > 20;

这样你能对比 PostgreSQL 的估算和实际执行,看看准不准。

VERBOSE

显示更多细节,适合深度分析。比如:

EXPLAIN VERBOSE SELECT * FROM students WHERE age > 20;

BUFFERS

显示查询执行时内存缓冲区的使用情况。要和 ANALYZE 一起用:

EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM students WHERE age > 20;

COSTS

你可以用这个选项隐藏或显示成本信息(cost):

EXPLAIN (COSTS OFF) SELECT * FROM students WHERE age > 20;

FORMAT

计划输出还能用别的格式,比如 JSON 或 XML。比如:

EXPLAIN (FORMAT JSON) SELECT * FROM students WHERE age > 20;

EXPLAIN 使用示例

假设你有个 university 数据库,里面有 students 表。你想查所有年龄大于 20 岁的学生:

EXPLAIN SELECT * FROM students WHERE age > 20;

输出可能是:

Seq Scan on students  (cost=0.00..35.00 rows=7 width=37)
  Filter: (age > 20)

就像前面说的,这是顺序扫描 Seq Scan,表大时效率低。

现在我们给 age 列建个索引,看看计划会不会变:

CREATE INDEX age_index ON students(age);

EXPLAIN SELECT * FROM students WHERE age > 20;

输出:

Index Scan using age_index on students  (cost=0.15..4.23 rows=7 width=37)
  Index Cond: (age > 20)

现在 PostgreSQL 用了索引扫描(Index Scan),通常比全表扫描快,尤其表大的时候。

常见问题和坑

为啥有索引查询还是慢?

可能是查询返回的行太多,导致用索引没啥优势。也可能索引本身不优或者没更新。

如果 EXPLAIN 输出看不懂咋办?

先从简单查询入手,一步步看执行计划的每个节点。

怎么知道表统计信息是不是过时了?

执行 ANALYZE students

啥时候用不带 ANALYZE 的 EXPLAIN?

当你只想看计划,不想真的执行(比如那些会改数据的查询)。

2
任务
SQL SELF, 第 41 级, 课程 2
已锁定
使用 `EXPLAIN` 和索引
使用 `EXPLAIN` 和索引
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION