sql - Postgres 中的慢速查询优化

标签 sql postgresql query-optimization sql-optimization

我们有一个特定 SQL 查询的性能问题,我们正在尝试弄清楚我们如何改进这里。它的执行时间约为 20 - 100 秒!

这是查询及其解释:

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。

在一个表中,我们有大约 50 万行。与查询相关的字段是:

  • due_date(不带时区的时间戳,可以为空)
  • 状态(整数,不为空)

我们有以下索引:

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)

先谢谢你, - jack

最佳答案

对于这个查询:

SELECT  j.*
FROM "jobs" j
WHERE j."status" IN (1, 2, 3, 4)
ORDER BY "jobs"."due_date" ASC
LIMIT 5;

“明显”索引在(status) 上。但这可能无济于事。目标是摆脱排序。因此,您可以重写查询并使用索引 jobs(status, due_date):

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 行上进行,这应该很快。

编辑:

这是一个相关的想法,具有相同的索引:

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;

这可以使用索引进行 ROW_NUMBER() 计算。这可能需要对表进行全表扫描。但是,最终排序将被限制为 20 行,因此最终排序被淘汰。

关于sql - Postgres 中的慢速查询优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56441909/

相关文章:

java - 使用列表参数将 HQL 查询转换为可执行的 SQL 查询

mysql - 解释一下MySQL中这个表中的key_len

mysql - 无法返回符合条件的记录

c# - 用随机数字更新多行

sql - Tsql - 使用 max 和 group by 获取整行信息

postgresql - double 的 Sqlalchemy CAST 等效项

sql - Spark如何比较boolean和string类型的数据

json - 如何在 Postgres 中使用条件 WHERE json 层次结构列?

ruby-on-rails - Rails 急切加载似乎查询错误

sql - 如何优化 Oracle SQL 中列名作为函数参数出现的查询?