Ash*_*Ash 3 postgresql sql-execution-plan
我有一个带2个外键的表,让我们称它们为fk1和fk2.两者都有相同的类型和相同的索引.但是当我"解释"一个简单的选择查询时,我得到完全不同的查询计划.对于fk1:
explain select * from mytable where fk1 = 1;
Run Code Online (Sandbox Code Playgroud)
结果
Index Scan using fk1_idx on mytable (cost=0.00..9.32 rows=2 width=4)
Index Cond: (fk1 = 1)
Run Code Online (Sandbox Code Playgroud)
对于fk2
explain select * from mytable where fk2 = 1;
Run Code Online (Sandbox Code Playgroud)
结果:
Bitmap Heap Scan on mytable (cost=5.88..659.18 rows=208 width=4)
Recheck Cond: (fk2 = 1)
-> Bitmap Index Scan on fk2_idx (cost=0.00..5.83 rows=208 width=0)
Index Cond: (fk2 = 1)
Run Code Online (Sandbox Code Playgroud)
第二个似乎效率更低.是否因为它可能会返回更多结果,因此更复杂的查询得到回报?
是的,这归结为谓词的"选择性"("where ..."子句).
如果谓词只选择表中的一小部分行,则通过对表数据的任意排序访问来单独获取每个行是有意义的,因为只会提取几页.
随着要选择的行数增加,位图扫描变得更合适:索引用于确定表中的哪些页面是"有趣的",然后按照它们放置在表数据文件中的顺序扫描这些页面.这具有可以一起请求相邻页面的优点,这可能由文件系统/磁盘系统更有效地服务.(当然,这取决于表数据文件是否合理地未分段).由于不保留每个页面中的实际有趣元组集合,只是页面集合本身,必须为检索到的页面中的每个元组重新评估谓词:因此在查询中"重新检查cond".(该策略的一个优点是它允许组合多个独立索引中的查找,
随着要选择的行数进一步增长,扫描索引的优势逐渐减少,因为可能的结果是大多数表将被标记为"有趣".因此,最终一个简单的顺序扫描变得合适:所有页面按顺序遍历,并且忽略索引.
IIRC这可能会导致请求不到15%的表可能是索引扫描,15-50%是位图扫描,50%+ seq扫描.非常粗略.这受到random_page_cost和seq_page_cost等相关设置的影响很大(例如effective_cache_size).
Postgresql收集有关公共值及其频率的统计信息,以及数据库中每列的其他值的直方图 - 这用于估计选择性并填充您在EXPLAIN输出中看到的"行"估计值.该文档包含如何完成此操作的说明:http://www.postgresql.org/docs/current/static/planner-stats-details.html
| 归档时间: |
|
| 查看次数: |
360 次 |
| 最近记录: |