CodeGym /课程 /SQL SELF /查询执行计划的基本概念: cost、 rows、

查询执行计划的基本概念: cost、 rows、 width

SQL SELF
第 41 级, 课程 1
可用

当你写了个SQL查询,PostgreSQL可不会立马就跑。它先会启动自己的“大脑”——查询优化器,生成一个执行计划。这个计划就像地图上的路线:PostgreSQL会算清楚要做哪些操作、按什么顺序做,才能顺利拿到数据。

查询优化器会评估你这个查询所有可能的执行路径:比如顺序扫描表、用不用索引、要不要做过滤和排序等等。它会尽量找一个最省资源的执行方式。也就是说,它会在执行时间和服务器资源之间找个平衡点。

执行计划的关键参数

好了,现在我们来点“硬核”的——拆解一下PostgreSQL在你执行EXPLAIN命令后给你看的那些参数。先看个简单例子:

EXPLAIN
SELECT * FROM students WHERE age > 20;

你会看到类似这样的结果:

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

来,咱们把这些神秘的词和数字都拆开讲讲。

1. cost(执行消耗)

cost——就是PostgreSQL估算执行这个查询要花多少资源。它分两部分:

  • Startup Cost:开始执行操作的消耗(比如准备索引啥的)。
  • Total Cost:整个操作执行完的总消耗。

举个例子:

cost=0.00..35.00
  • 0.00——就是Startup Cost。
  • 35.00——就是Total Cost。

cost越低,这个计划对PostgreSQL来说就越有吸引力。不过要记住,cost只是个相对值,不是秒也不是毫秒,更像是PostgreSQL内部的打分。

2. rows(预计行数)

rows表示PostgreSQL觉得在这个执行阶段会返回或处理多少行。比如我们这个例子:

rows=7

意思就是PostgreSQL觉得age > 20这个过滤条件能返回7行。这数据是PostgreSQL根据表的统计信息算出来的。如果统计信息过时了,估算就可能不准,导致执行计划也不理想。

3. width(每行宽度,单位字节)

width——就是每行平均占多少字节。比如我们这个例子:

width=72

意思是每行平均72字节。width会考虑列的数据大小,还有一些额外的开销,比如行ID或者系统信息。

这有点像你下载App。如果App“体积”(也就是width)很大,即使你网速快(cost低),下载也得花不少时间。

执行计划分析实例

来,咱们看个实际例子。假设有个表students:

CREATE TABLE students (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    age INTEGER,
    major VARCHAR(50)
);

我们执行下面这个查询:

EXPLAIN
SELECT * FROM students WHERE age > 20 AND major = 'CS';

结果可能是这样:

Seq Scan on students  (cost=0.00..42.50 rows=3 width=164)
  Filter: ((age > 20) AND (major = 'CS'))
  • Seq Scan:PostgreSQL对students表做了顺序扫描,也就是一行一行全都过一遍。
  • cost=0.00..42.50:执行消耗。Startup Cost是0.00,总消耗42.50。
  • rows=3:PostgreSQL觉得age > 20 AND major = 'CS'能返回3行。
  • width=164:每行平均164字节。

现在你应该明白PostgreSQL是怎么做决策的,也能找出查询里的瓶颈了。比如你看到cost很高,说明这个查询挺重的;或者rows很多,可能要优化下过滤条件。

cost实际是怎么影响执行的?

来,我们给age列加个索引:

CREATE INDEX idx_age ON students(age);

再跑一次查询:

EXPLAIN
SELECT * FROM students WHERE age > 20 AND major = 'CS';

结果可能变成这样:

Bitmap Heap Scan on students  (cost=4.37..20.50 rows=3 width=164)
  Recheck Cond: (age > 20)
  Filter: (major = 'CS')
  ->  Bitmap Index Scan on idx_age  (cost=0.00..4.37 rows=20 width=0)
        Index Cond: (age > 20)

发生了什么变化?

  • 不再是Seq Scan,而是Bitmap Heap Scan:PostgreSQL先用idx_age索引找出符合条件的行,再从表里取出来。
  • cost大大降低了:Startup Cost变成4.37,Total Cost是20.50。
  • 有了索引,操作效率提升了。

可视化:Seq Scan和Index Scan的区别

来个小对比表,看得更直观:

操作 简介 例子
Seq Scan 全表扫描 把所有行都过一遍
Index Scan 用索引 通过索引快速查找行

坑点和常见错误

用执行计划参数的时候,得注意有些坑。比如cost低不一定就真快。如果数据库统计信息过时了(比如你刚批量更新了表),计划可能就不准。记得用ANALYZE命令更新统计信息。这个我们下节课会详细讲。

还有,索引要用在该用的地方,但别滥用:索引会占空间,还会拖慢写入操作。

2
任务
SQL SELF, 第 41 级, 课程 1
已锁定
解析使用顺序扫描的 `EXPLAIN` 执行计划
解析使用顺序扫描的 `EXPLAIN` 执行计划
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION