由于索引的顺序扫描引起的PostgreSQL 9.6性能问题

时间:2017-06-15 08:55:07

标签: performance postgresql indexing

我遇到了PostgreSQL 9.6的性能问题 我有一张桌子:

CREATE TABLE public.cdrsinfo (
  recordid bigint NOT NULL,
  billid integer,
  CONSTRAINT cdrsinfo_pkey PRIMARY KEY (recordid) );

并在其上创建索引,如:

CREATE UNIQUE INDEX cdrsinfo_pkey ON cdrsinfo USING btree (recordid)

CREATE INDEX indx_cdrsinfo_billid ON cdrsinfo USING btree (billid)

该表有3M记录,我已对其进行了分析,当使用EXPLAIN运行以下查询时,我得到了一些奇怪的结果:

SELECT max(recordid) FROM example WHERE billid = 535;

Result  (cost=26631.27..26631.28 rows=1 width=8)
  InitPlan 1 (returns $0)
    ->  Limit  (cost=0.57..26631.27 rows=1 width=8)
          ->  Index Scan Backward using cdrsinfo_pkey on cdrsinfo  (cost=0.57..2291944283.82 rows=86064 width=8)
                Index Cond: (recordid IS NOT NULL)
                Filter: (billid = 535)


SELECT max(recordid) FROM example WHERE billid < 535;

Aggregate  (cost=725.85..725.86 rows=1 width=8)
  ->  Index Scan using indx_cdrsinfo_billid on cdrsinfo  (cost=0.57..725.37 rows=192 width=8)
        Index Cond: (billid < 535)

如果我计算了billid = 535的所有行,我得到44。我的问题是为什么查询规划器在第一个例子中没有使用indx_cdrsinfo_billid? 因此,我遇到了巨大的性能问题,第一个SQL需要大约2个小时才能完成,第二个SQL大约需要170毫秒。

我忘了提及我在桌子上的第三个索引:

CREATE INDEX indx_cdrsinfo_billid_recordid ON cdrsinfo USING btree (recordid,billid)

正如我所提到的,在运行查询之前对表进行了分析。现在,当我使用analyze verbose和buffers执行解释时,我在同一个查询中得到了非常好的时间,其中billid = 535:

Result  (cost=0.85..0.86 rows=1 width=8) (actual time=0.034..0.034 rows=1 loops=1)
  Output: $0
  Buffers: shared hit=5
  InitPlan 1 (returns $0)
    ->  Limit  (cost=0.57..0.85 rows=1 width=8) (actual time=0.031..0.031 rows=1 loops=1)
          Output: cdrsinfo.recordid
          Buffers: shared hit=5
          ->  Index Only Scan Backward using indx_cdrsinfo_billid_recordid on public.cdrsinfo  (cost=0.57..24041.88 rows=89007 width=8) (actual  time=0.022..0.022 rows=1 loops=1)
                Output: cdrsinfo.recordid
                Index Cond: ((cdrsinfo.billid = 535) AND (cdrsinfo.recordid IS NOT NULL))
                Heap Fetches: 0
                Buffers: shared hit=5
Planning time: 0.177 ms
Execution time: 0.056 ms

索引也在过去,我不明白为什么Query Planner现在决定使用它而不是今天早上。

另一个奇怪的事情是,当我得到非常糟糕的执行时间时,我试图在几种模式下重新编写该查询以查看解释计划,当我这样做时:

SELECT max(recordid) FROM cdrsinfo WHERE recordid IN (SELECT recordid FROM cdrsinfo WHERE billid = 535 OFFSET 0)

由于OFFSET 0,查询规划器使用了indx_cdrsinfo_billid,这是我期望使用的那个。

0 个答案:

没有答案