运行Heroku“Crane”PostgreSQL实例(版本9.1.6)
我有一张带销售点的桌子;货币金额以当地货币计算。我有一个货币换算表,其中包含每种货币和欧元之间的转换因子。我想总结给定书籍(产品)的销售额,退货,赠品和收入(以美元计)。所以我加入货币转换表一次将当地货币兑换成欧元,然后再将欧元转换成美元(请记住,根据销售的结算日期,费率会有所不同)。因此,要考虑的每个销售点将与货币转换两次加入;实验告诉我,这是主要的减速因素。
所以我正在尝试优化以下查询:
SELECT
sum(paid_sales - paid_returns) as paid_units,
sum(royalty_amt*(uu_cc.rate / sp_cc.rate)) as royalty_amt,
sum(free_sales - free_returns) as free_units,
sum(lent_units) as lent_units
FROM "sales_points"
join currency_conversions sp_cc
on sp_cc.date = sales_points.settlement_date
and sp_cc.currency = sales_points.currency
join currency_conversions uu_cc
on uu_cc.date = sales_points.settlement_date
and uu_cc.currency = 'USD'
WHERE "sales_points"."book_id" = 234
LIMIT 1
我创建了以下索引:
CREATE INDEX index_currency_conversions_on_date_and_currency
ON currency_conversions
USING btree (date, currency COLLATE pg_catalog."default");
然而EXPLAIN(在运行ANALYZE之后)告诉我它正在对货币转换表进行顺序扫描。如果重要,date
的类型为'date',currency
的类型为'char var(255)'。
以下是查询计划:
Limit (cost=7285.04..7285.04 rows=1 width=39) (actual time=103.166..103.167 rows=1 loops=1)
Buffers: shared hit=916
-> Aggregate (cost=7285.04..7285.04 rows=1 width=39) (actual time=103.163..103.163 rows=1 loops=1)
Buffers: shared hit=916
-> Hash Join (cost=584.15..7256.29 rows=6388 width=39) (actual time=60.513..92.084 rows=5840 loops=1)
Hash Cond: (sp_cc.date = uu_cc.date)
Buffers: shared hit=916
-> Hash Join (cost=351.63..6985.45 rows=6388 width=39) (actual time=52.454..72.418 rows=5840 loops=1)
Hash Cond: ((sales_points.settlement_date = sp_cc.date) AND ((sales_points.currency)::text = (sp_cc.currency)::text))
Buffers: shared hit=763
-> Bitmap Heap Scan on sales_points (cost=54.09..6630.06 rows=6446 width=30) (actual time=0.912..7.020 rows=5840 loops=1)
Recheck Cond: (book_id = 234)
Buffers: shared hit=610
-> Bitmap Index Scan on index_sales_points_on_book_id (cost=0.00..53.77 rows=6446 width=0) (actual time=0.809..0.809 rows=6521 loops=1)
Index Cond: (book_id = 234)
Buffers: shared hit=22
-> Hash (cost=214.95..214.95 rows=20649 width=16) (actual time=51.502..51.502 rows=20649 loops=1)
Buckets: 4096 Batches: 1 Memory Usage: 968kB
Buffers: shared hit=153
-> Seq Scan on currency_conversions sp_cc (cost=0.00..214.95 rows=20649 width=16) (actual time=0.007..21.153 rows=20649 loops=1)
Buffers: shared hit=153
-> Hash (cost=225.27..225.27 rows=2071 width=12) (actual time=8.040..8.040 rows=2071 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 89kB
Buffers: shared hit=153
-> Seq Scan on currency_conversions uu_cc (cost=0.00..225.27 rows=2071 width=12) (actual time=0.021..5.963 rows=2071 loops=1)
Filter: ((currency)::text = 'USD'::text)
Buffers: shared hit=153
Total runtime: 103.306 ms
有谁知道为什么它没有使用我的索引?
答案 0 :(得分:0)
多列索引在这里是个错误。您可能希望在两列上有两个单独的索引,因为这为计划程序提供了更大的灵活性。
您当前的索引不能与您的查询一起使用,因为它需要从表中查询日期(btree是第一个日期,其次是货币)。如果列以其他顺序排列,则可能有用,但在日期更具选择性的情况下无法使用。
您最好的选择是为这两个字段分别设置索引。通过这种方式,规划器可以选择哪个索引对于手头的查询更具选择性,而不是必须接受或留下对于给定查询可能具有可疑值的索引。
另请注意,PostgreSQL可以跨多个索引进行位图索引扫描,允许它在必要时同时使用这两个索引。