当你写了个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命令更新统计信息。这个我们下节课会详细讲。
还有,索引要用在该用的地方,但别滥用:索引会占空间,还会拖慢写入操作。
GO TO FULL VERSION