我有两个表(为简单起见省略了外键):
CREATE TABLE timetables (
"ttid" SERIAL4 NOT NULL,
"bioid" int4 NOT NULL,
"component" int4,
"route" int2,
"time_num" numeric,
"time_unit" char(1) COLLATE "default",
"time_shift" int2,
"time_devstage" int2,
"times_total" int2,
"every_num" numeric,
"every_unit" char(1) COLLATE "default",
"duration_num" numeric,
"duration_unit" char(1) COLLATE "default",
"doseid" int4 NOT NULL,
CONSTRAINT "timetables_pkey" PRIMARY KEY ("ttid"),
CONSTRAINT "timetables_doseid_fkey" FOREIGN KEY ("doseid") REFERENCES doses(doseid) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE INDEX "timetables_bioid_idx" ON "timetables" USING btree (bioid);
CREATE INDEX "timetables_doseid_idx" ON "timetables" USING btree (doseid);
和
CREATE TABLE doses (
"doseid" SERIAL4 NOT NULL,
"ai" numeric,
"conc" numeric,
"conc_unit" varchar COLLATE "default",
"vol" numeric,
"vol_unit" varchar COLLATE "default",
"amount" numeric,
"amount_unit" varchar COLLATE "default",
"area" numeric,
"area_unit" varchar COLLATE "default",
"numplants" numeric,
CONSTRAINT "doses_pkey" PRIMARY KEY ("doseid")
);
以下查询无法使用“bioid”列上的索引:
SELECT bioid, json_agg (doses) jtd
FROM timetables
LEFT JOIN doses USING (doseid)
GROUP BY bioid
EXPLAIN返回以下内容:
GroupAggregate (cost=391.88..440.10 rows=2251 width=75)
-> Sort (cost=391.88..398.57 rows=2677 width=75)
Sort Key: timetables.bioid
-> Merge Right Join (cost=0.56..239.47 rows=2677 width=75)
Merge Cond: (doses.doseid = timetables.doseid)
-> Index Scan using doses_pkey on doses (cost=0.28..93.79 rows=2367 width=75)
-> Index Scan using timetables_doseid_idx on timetables (cost=0.28..106.43 rows=2677 width=8)
因此,尽管将“timetables.bioid”键声明为索引,但SORT仍然是明确的。 如果我将汇总“时间表”表而不是“剂量”,那么查询变得非常快:
GroupAggregate (cost=0.28..147.96 rows=2251 width=77)
-> Index Scan using timetables_bioid_idx on timetables (cost=0.28..106.43 rows=2677 width=77)
我应该如何优化查询以使用索引或我应该添加哪些索引?其实我需要整个输出的json_agg():
SELECT bioid,json_agg(td)jtd
FROM(时间表LEFT JOIN剂量使用(剂量))td
GROUP BY bioid
我正在使用Postgres 9.3
答案 0 :(得分:0)
但查询 使用索引,它只是不使用您期望的索引。
PostgreSQL估计它通过使用合并连接变得最便宜。为此,两个表中的数据必须按连接条件排序,连接条件使用索引doses_pkey
和timetables_doseid_idx
完成。
在连接之后,条目按doseid
排序,因此必须按bioid
对GROUP BY
子句进行排序。索引不能用于此,因为它不是表,而是排序的连接结果。
我认为没有什么可担心的。
如果您认为PostgreSQL没有使用正确的连接方法,您可以尝试SET enable_mergejoin=off
并比较当时生成的计划。使用EXPLAIN (ANALYZE)
查看优化程序是否正确估算;糟糕的计划者选择通常是由错误估计引起的。