我正在使用 Postgres 12.10 AWS RDS。我使用 group by 查找最小日期的查询比日期上的常规最小值要快。我希望常规 min 也一样快,但不确定我是否输入了错误的索引或者我需要调整另一个参数。
我有一张桌子
CREATE TABLE IF NOT EXISTS public.ed
(
isd character varying(90) COLLATE pg_catalog."default" NOT NULL,
e_id character varying(32) COLLATE pg_catalog."default" NOT NULL,
d_date timestamp with time zone NOT NULL,
CONSTRAINT ed_pkey PRIMARY KEY (isd, e_id)
)
指数:
CREATE INDEX IF NOT EXISTS ix_ed_d_date
ON public.ed USING btree
(d_date ASC NULLS LAST)
TABLESPACE pg_default;
CREATE INDEX IF NOT EXISTS ix_ed_e_id
ON public.ed USING btree
(e_id COLLATE pg_catalog."default" ASC NULLS LAST)
TABLESPACE pg_default;
查询只需min
3 分钟:
select min(d_date)
from ed
where e_id = '62e2032b029b036ba25c73cf';
解释分析查询:
Result (cost=171.70..171.71 rows=1 width=8) (actual time=186940.968..186941.463 rows=1 loops=1)
InitPlan 1 (returns $0)
-> Limit (cost=0.56..171.70 rows=1 width=8) (actual time=186940.963..186940.964 rows=1 loops=1)
-> Index Scan using ix_ed_d_date on ed (cost=0.56..2214942.25 rows=12943 width=8) (actual time=186940.961..186940.962 rows=1 loops=1)
Index Cond: (d_date IS NOT NULL)
Filter: ((e_id)::text = '62e2032b029b036ba25c73cf'::text)
Rows Removed by Filter: 30539883
Planning Time: 0.195 ms
Execution Time: 186941.491 ms
虽然使用 group by 的查询不到一秒钟:
select min(d_date)
from ed
where e_id in ('62e2032b029b036ba25c73cf')
group by e_id;
解释分析:
GroupAggregate (cost=0.56..5365.73 rows=2319 width=33) (actual time=92.093..92.095 rows=1 loops=1)
Group Key: e_id
-> Index Scan using ix_ed_e_id on ed (cost=0.56..5277.83 rows=12943 width=33) (actual time=6.753..90.622 rows=6698 loops=1)
Index Cond: ((e_id)::text = '62e2032b029b036ba25c73cf'::text)
Planning Time: 0.098 ms
Execution Time: 92.127 ms
我得到相同的结果,但为什么使用d_date
索引更简单的查询?我怎样才能使简单min(d_date)
而又不group by
具有使用的性能group by
?
'62e2032b029b036ba25c73cf'
似乎很频繁e_id
,所以 PostgreSQL 认为它可以通过按d_date
顺序查看行直到找到正确的行来获胜e_id
。不幸的是,所有带有e_id = '62e2032b029b036ba25c73cf'
high 的行d_date
,PostgreSQL 必须跳过 3000 万行,直到找到命中。如果你使用 . 你可以阻止 PostgreSQL 使用索引
min(d_date + INTERVAL '0')
。那么第一个查询应该和第二个一样快。在上创建复合索引
(e_id, d_date)
将是解决问题的完美方案,那么 PostgreSQL 不能错误地选择错误的索引。