Slow query optimisation in Postgres
我们遇到了特定 SQL 查询的性能问题,我们正在尝试找出如何改进这里。它的执行时间约为 20 - 100 秒!
这是查询和解释:
1 2 3 4 5 6 7 8 9 10 11 12 | SELECT "jobs".* FROM"jobs" WHERE"jobs"."status" IN (1, 2, 3, 4) ORDER BY"jobs"."due_date" ASC LIMIT 5; LIMIT (cost=0.42..1844.98 ROWS=5 width=2642) (actual TIME=16927.150..18151.643 ROWS=1 loops=1) -> INDEX Scan USING index_jobs_on_due_date ON jobs (cost=0.42..1278647.41 ROWS=3466 width=2642) (actual TIME=16927.148..18151.641 ROWS=1 loops=1) FILTER: (STATUS = ANY ('{1,2,3,4}'::INTEGER[])) ROWS Removed BY FILTER: 595627 Planning TIME: 0.205 ms Execution TIME: 18151.684 ms |
我们在 AWS RDS 上使用 PostgreSQL 9.6.11。
在一个表中,我们有大约 500K 行。与查询相关的字段是:
- due_date(没有时区的时间戳,可以为空)
- 状态(整数,非空)
我们有以下索引:
1 2 3 4 | CREATE INDEX index_jobs_on_due_date ON public.jobs USING btree (due_date) CREATE INDEX index_jobs_on_due_date_and_status ON public.jobs USING btree (due_date, STATUS) CREATE INDEX index_jobs_on_status ON public.jobs USING btree (STATUS) CREATE UNIQUE INDEX jobs_pkey ON public.jobs USING btree (id) |
提前谢谢你,
- 杰克
对于这个查询:
1 2 3 4 5 | SELECT j.* FROM"jobs" j WHERE j."status" IN (1, 2, 3, 4) ORDER BY"jobs"."due_date" ASC LIMIT 5; |
"明显"索引位于
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | SELECT j.* FROM ((SELECT j.* FROM jobs j WHERE j.status = 1 ORDER BY j.due_date ASC LIMIT 5 ) UNION ALL (SELECT j.* FROM jobs j WHERE j.status = 2 ORDER BY j.due_date ASC LIMIT 5 ) UNION ALL (SELECT j.* FROM jobs j WHERE j.status = 3 ORDER BY j.due_date ASC LIMIT 5 ) UNION ALL (SELECT j.* FROM jobs j WHERE j.status = 4 ORDER BY j.due_date ASC LIMIT 5 ) ) j ORDER BY due_date LIMIT 5; |
每个子查询都应该使用复合索引。然后,最终排序将在(最多)20 行上进行,这应该很快)。
编辑:
这是一个相关的想法,索引相同:
1 2 3 4 5 6 7 8 | SELECT j.* FROM (SELECT j.*, ROW_NUMBER() OVER (PARTITION BY j.status ORDER BY j.due_date ASC) AS seqnum FROM"jobs" j ) j WHERE j.status IN (1, 2, 3, 4) AND seqnum <= 5 ORDER BY j.due_date ASC LIMIT 5; |
这可以使用索引进行