解析PostgreSQL explain执行计划
PostgreSQL执行计划分析摘要(145字): 两条查询分别针对orders表的billed字段不同状态做分析。第一条(billed is not true)有效利用了部分索引orders_unbilled_index,执行计划显示优化器选择了成本较低的位图索引扫描(总成本3880.78)。第二条(billed is true)因不满足部分索引条件且数据量大,被迫采用全表扫描(成本8462.4
·
根据以下SQL内容,解析两条PostgreSQL explain执行计划:
- CREATE TABLE orders( order_nr int, amount decimal(12,2), billed boolean );
- CREATE INDEX orders_unbilled_index ON orders (order_nr) WHERE billed is not true;
- insert into orders select t.seq, t.seq*2.44, true from generate_series(1,500000) as t(seq);
- insert into orders select t.seq, t.seq*2.44, false from generate_series(500001,509000) as t(seq);
------------------------------------------------------------------------------------------
- explain SELECT * FROM orders WHERE billed is not true AND order_nr < 10000;
QUERY PLAN
------------------------------------------------------------------------------------------
Bitmap Heap Scan on orders (cost=177.04..3880.78 rows=76139 width=21)
Recheck Cond: ((order_nr < 10000) AND (billed IS NOT TRUE))
-> Bitmap Index Scan on orders_unbilled_index (cost=0.00..158.01 rows=76139 width=0)
Index Cond: (order_nr < 10000)
(4 rows)
------------------------------------------------------------------------------------------
- explain SELECT * FROM orders WHERE billed is true AND order_nr < 10000;
QUERY PLAN
--------------------------------------------------------------
Seq Scan on orders (cost=0.00..8462.40 rows=76139 width=21)
Filter: ((billed IS TRUE) AND (order_nr < 10000))
(2 rows)
根据提供的实际EXPLAIN执行计划,来进行详细解析:
一、第一条查询解析
EXPLAIN SELECT * FROM orders WHERE billed is not true AND order_nr < 10000;
执行计划:
Bitmap Heap Scan on orders (cost=177.04..3880.78 rows=76139 width=21)
Recheck Cond: ((order_nr < 10000) AND (billed IS NOT TRUE))
-> Bitmap Index Scan on orders_unbilled_index (cost=0.00..158.01 rows=76139 width=0)
Index Cond: (order_nr < 10000)
深度解析:
- Bitmap Index Scan:首先使用部分索引
orders_unbilled_index
进行位图索引扫描 - 索引条件:
order_nr < 10000
- 在索引层面过滤 - Bitmap Heap Scan:将索引扫描结果转换为位图,然后在堆中进行精确查找
- Recheck Cond:需要重新检查条件,确保数据准确性
- 成本分析:总成本3880.78,索引扫描成本仅158.01,效率很高
- 行数估计:优化器估计返回76,139行(实际应该很少,这是估计错误)
二、第二条查询解析
EXPLAIN SELECT * FROM orders WHERE billed is true AND order_nr < 10000;
执行计划:
Seq Scan on orders (cost=0.00..8462.40 rows=76139 width=21)
Filter: ((billed IS TRUE) AND (order_nr < 10000))
深度解析:
- Seq Scan:选择全表顺序扫描
- 原因:
- 部分索引
orders_unbilled_index
不包含billed = true
的记录 billed = true
的记录占98.2%,选择性很差- 没有其他合适的索引可用
- 部分索引
- Filter:在扫描过程中应用过滤条件
- 成本分析:总成本8462.40,比第一条查询高很多
- 行数估计:同样估计76,139行(估计不准确)
关键发现和优化器行为分析
1. 行数估计问题
- 两条查询都估计返回76,139行,但实际:
- 第一条:实际应该很少(只有
billed is not true
且order_nr < 10000
的记录) - 第二条:实际应该有约10,000行(所有
order_nr < 10000
的记录,因为前10,000条都是billed = true
)
- 第一条:实际应该很少(只有
2. 索引使用有效性
- 第一条查询:完美命中部分索引,使用
Bitmap Index Scan
效率很高 - 第二条查询:无法使用部分索引,只能全表扫描
3. 执行计划选择合理性
- 优化器做出了正确选择:
- 对稀疏条件(billed is not true)使用索引
- 对稠密条件(billed is true)使用全表扫描
4. 潜在优化建议
-- 如果需要频繁查询 billed = true 的记录,可以创建另一个部分索引
CREATE INDEX orders_billed_index ON orders (order_nr) WHERE billed is true;
总结
执行计划显示PostgreSQL优化器能够:
- 正确识别和使用部分索引
- 根据数据分布选择最优访问路径
- 对选择性好的条件使用索引扫描
- 对选择性差的条件使用顺序扫描
虽然行数估计有偏差,但执行计划的选择是完全合理的。
需要注意:
- PostgreSQL⽀持带任意谓词的部分索引,条件是只涉及被索引表的字段,但是,谓词必须和那些希望从该索引中获益的查询中的WHERE条件相匹配,
- 准确地说,只有在系统能够识别出该查询的WHERE条件简单地包含了该索引的谓词时,这个部分索引才能⽤于该查询。
- PostgreSQL还没有智能到可以完全识别那些形式不同但数学上意义相等的谓词。
更多推荐
所有评论(0)