2010-07-01 83 views
2

我有一个带有2个外键的表,我们称它们为fk1和fk2。两者具有相同的类型和相同的指数。但是当我“解释”一个简单的选择查询时,我会得到完全不同的查询计划。对于FK1:PostgreSql:具有相同列的不同查询计划

explain select * from mytable where fk1 = 1; 

结果

Index Scan using fk1_idx on mytable (cost=0.00..9.32 rows=2 width=4) 
    Index Cond: (fk1 = 1) 

对于FK2

explain select * from mytable where fk2 = 1; 

结果:

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) 

第二个似乎更加低效。这是否是由于它可能会返回更多结果,因此更复杂的查询会得到回报?

回答

5

是的,这归结于所谓谓词的“选择性”(“where ...”从句)。

如果谓词仅选择表中的一小部分行,那么通过随意访问表数据来单独获取每一行是有意义的,因为只会获取几个页面。

随着要选择的行数增加,位图扫描变得更合适:索引用于确定表中哪些页面是“有趣的”,然后按照它们放置的顺序扫描这些页面表格数据文件。这具有可以一起请求相邻页面的优点,这可能由文件系统/磁盘系统更有效地服务。 (当然,这取决于表格数据文件被合理地分解)。由于每个页面中实际感兴趣的元组集合并没有被保留,只是一组页面本身,所以必须为检索到的页面中的每个元组重新评估谓词:因此查询中的“重新检查cond”。 (这种策略的一个优点是它允许将多个独立索引中的查找组合在一起,只需将(或ORing)来自多个索引查找的“感兴趣的页面”位图结合起来)

由于要选择的行数进一步增长,扫描索引的优势缩小,因为可能的结果是大多数表格将被标记为“有趣”。所以最终一个简单的顺序扫描就变得合适了:所有的页面都按顺序走过,索引被忽略。

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

2

是的,查询计划将基于有关表中内容的统计数据。记得运行“真空分析”;不时地将统计数据保存至数据。

相关问题