【问题标题】:Indexing with joins使用连接索引
【发布时间】:2021-01-02 12:05:43
【问题描述】:

我是索引概念的新手,但我正试图弄清楚它是如何工作的。

我想提高以下查询的性能。

explain analyze select to_char(rental_date, 'month') as month, count(*) count
from rental
join instrument on rental.instrument_id = instrument.instrument_id
where extract(year from rental_date) = 2020
group by month, extract(month from rental_date)
order by extract(month from rental_date) asc
;

执行计划

       QUERY PLAN                                                                                 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 GroupAggregate  (cost=75.10..75.55 rows=15 width=48) (actual time=14.204..14.821 rows=12 loops=1)
   Group Key: (date_part('month'::text, (rental.rental_date)::timestamp without time zone)), (to_char((rental.rental_date)::timestamp with time zone, 'month'::text))
   ->  Sort  (cost=75.10..75.14 rows=15 width=40) (actual time=14.121..14.298 rows=1540 loops=1)
         Sort Key: (date_part('month'::text, (rental.rental_date)::timestamp without time zone)), (to_char((rental.rental_date)::timestamp with time zone, 'month'::text))
         Sort Method: quicksort  Memory: 169kB
         ->  Hash Join  (cost=1.20..74.81 rows=15 width=40) (actual time=7.912..13.166 rows=1540 loops=1)
               Hash Cond: (rental.instrument_id = instrument.instrument_id)
               ->  Seq Scan on rental  (cost=0.00..73.39 rows=15 width=8) (actual time=0.061..2.027 rows=1540 loops=1)
                     Filter: (date_part('year'::text, (rental_date)::timestamp without time zone) = '2020'::double precision)
                     Rows Removed by Filter: 1511
               ->  Hash  (cost=1.09..1.09 rows=9 width=4) (actual time=0.046..0.047 rows=9 loops=1)
                     Buckets: 1024  Batches: 1  Memory Usage: 9kB
                     ->  Seq Scan on instrument  (cost=0.00..1.09 rows=9 width=4) (actual time=0.012..0.016 rows=9 loops=1)
 Planning Time: 3.908 ms
 Execution Time: 15.072 ms
(15 rows)

我的想法是在instrument_id 和rental_date 上建立索引,因为intrument_id 是外键,而rental_date 在where 子句中。

create index isx_rental ON rental(instrument_id);
create index isx_date ON rental(rental_date);

但这根本不影响运行时。

为什么这对我的性能没有帮助?

【问题讨论】:

  • 15 毫秒秒似乎很快。你需要多快?

标签: postgresql indexing


【解决方案1】:

条件extract(year from rental_date) = 2020 不能在rental_date 上使用索引,因为索引不存储表达式的结果,只存储原始列值。

您至少需要将该条件更改为:

where rental_date >= date '2020-01-01'
  and rental_date < date '2021-01-01'

为了完全考虑索引。如果不看执行计划,很难说这是否提高了性能。

【讨论】:

    【解决方案2】:

    extract(year from rental_date) = 2020 开始不能使用索引,因为在进行比较之前需要对每一行应用该函数。您应该尽可能不要提取日期的一部分,而是使用范围。在这种情况下,您可以使用rental_date &gt;= '2020-01-01' AND rental_date &lt; '2021-01-01'

    然后你按别名 month 分组有点奇怪,这是月份(作为名称),然后又是 extract(month from rental_date),也是月份(但数字)。这些可以被双射映射。我不知道优化器是否能做到这一点,所以你最好只按其中一个分组。如果您按您订购的相同表达式进行分组,它也可能会有所帮助。所以GROUP BY extract(month from rental_date) 似乎更有希望。

    简而言之,您可以尝试将查询重写为:

    SELECT to_char(rental_date, 'month') month,
           count(*) count
           FROM rental
                INNER JOIN instrument
                           ON rental.instrument_id = instrument.instrument_id
           WHERE rental_date >= '2020-01-01'
                 AND rental_date < '2021-01-01'
           GROUP BY extract(month from rental_date)
           ORDER BY extract(month from rental_date) ASC;
    

    对于instrument,只涉及一列instrument_id,这可能是一个主键,即它已经被索引。如果没有,请将其编入索引,它可能会对JOIN 有所帮助。

    接下来的事情是,SELECT 中的表只能使用一个索引(除非它更频繁地出现在 FROM 子句中,但这里不是这种情况)。所以你在rental 上的两个索引太多了。你需要一个复合索引。

    现在对于rental,您可以尝试在(rental_date, instrument_id) 上建立索引以支持WHEREJOIN。要同时支持GROUP BYORDER BY,您也可以尝试将extract(month from rental_date) 添加到索引中,使其成为(rental_date, instrument_id, extract(month from rental_date)) 上的索引。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-23
      • 2021-12-20
      • 2016-01-08
      • 2017-11-25
      • 1970-01-01
      相关资源
      最近更新 更多