我有一个非常简单的数据库模式,它在以下列上有一个多列b-tree索引:
PersonId, Amount, Commission
现在,如果我尝试使用以下查询选择表:
explain select * from "Order" where "PersonId" = 2 AND "Commission" > 3
Pg正在扫描索引并且查询非常快,但是如果我尝试以下查询:
explain select * from "Order" where "PersonId" > 2 AND "Commission" > 3
即使存在索引,它也会执行顺序扫描。甚至这个查询
explain select * from "Order" where "Commission" > 3
执行顺序扫描。 有人在乎解释原因吗? : - )
非常感谢。
更新
该表包含1亿行。我创建它只是为了测试PostgreSQL对MS SQL的性能。该表已经是VACUUMED。我正在运行Core I5 2500k四核CPU和8 GB内存。
以下是此查询的解释分析结果:
explain ANALYZE select * from "Order" where "Commission" BETWEEN 3000000 AND 3000010 LIMIT 20
Limit (cost=0.00..2218328.00 rows=1 width=24) (actual time=28043.249..28043.249 rows=0 loops=1)
-> Seq Scan on "Order" (cost=0.00..2218328.00 rows=1 width=24) (actual time=28043.247..28043.247 rows=0 loops=1)
Filter: (("Commission" >= 3000000::numeric) AND ("Commission" <= 3000010::numeric))
Total runtime: 28043.278 ms
答案 0 :(得分:6)
简短的回答是,在比较各种可用计划时,根据您配置的成本核算因素和可用的最新统计数据,预计顺序扫描最快。根据您提供的少量信息,计划员似乎很可能做出了正确的选择。如果您有三个单列索引,则可能能够使用位图索引扫描,尤其是当要选择的行少于表中行的10%时。
请注意,对于您描述的索引,需要从"PersonId" > 2
的所有行扫描整个索引;除非你有很多"PersonId"
的负值,否则很可能是表格的大部分内容。
另请注意,如果您有一个小表 - 比如几千行或更少,通过索引访问行很少比扫描那几行快。计划对数据量敏感,而您使用少量行获得的计划不太可能与您获得大量行的计划相同。
如果实际上没有选择最快的计划,那么您需要调整成本因素以更好地模拟机器成本的可能性很大。另一种可能性是您需要在autovacuum设置中更积极,以确保可以获得最新的统计信息,或者您可能需要配置更细粒度的统计信息。
如果您显示表格描述(包括索引),查询的EXPLAIN ANALYZE
输出以及硬件描述,人们将能够提供更具体的建议。