我遇到了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,这是我期望使用的那个。