0

运行 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则为“日期”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

有谁知道为什么它不使用我的索引?

4

1 回答 1

0

多列索引在这里有些错误。您可能希望两列上有两个单独的索引,因为这为规划器提供了更大的灵活性。

您当前的索引不能与您的查询一起使用,因为它需要从表中查询日期(btree 首先是日期,其次是货币)。如果列按其他顺序排列,它可能有用,但不能在日期更具选择性的情况下使用。

您最好的选择是为这两个字段设置单独的索引。通过这种方式,规划器可以选择预期哪个索引对手头的查询更具选择性,而不必采用或保留对给定查询可能具有可疑价值的索引。

另请注意,PostgreSQL 可以跨多个索引进行位图索引扫描,允许它在必要时同时使用两个索引。

于 2013-04-23T13:11:29.773 回答