使用group by with order一起查询时间慢

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用group by with order一起查询时间慢相关的知识,希望对你有一定的参考价值。

我有一个查询,我需要按列排序结果。如果我按id订购,它的工作速度非常快(2.8毫秒)。但是,如果我尝试按任何其他列(甚至索引)进行排序,则查询执行时间会变高(800毫秒)。我可以在EXPLAIN中看到,按ID排序正在使用索引扫描,如果我通过reg_date订购它会进行Seq Scan。

这是我的索引。我还重新索引了表格。

+--------------------+------------------------------------------------------------------------+
|     indexname      |                                indexdef                                |
+--------------------+------------------------------------------------------------------------+
| pk_users           | CREATE UNIQUE INDEX pk_users ON public.users USING btree (id)          |
| idx_users_reg_date | CREATE INDEX idx_users_end_date ON public.users USING btree (reg_date) |
+--------------------+------------------------------------------------------------------------+

如果我按id排序,则执行时间为2.601 ms

select
    users.id,
    users.full_name,
    sum(user_comments.badges) as badges,
    count(user_comments) as comment_count
from
    users
left join user_comments
        on users.id = user_comments.user_id
group by users.id
order by users.id
limit 10

但是,如果我按users.reg_date列(具有索引)进行排序,则大约为818.336毫秒

select
    users.id,
    users.full_name,
    sum(user_comments.badges) as badges,
    count(user_comments) as comment_count
from
    users
left join user_comments
        on users.id = user_comments.user_id
group by users.id
order by users.reg_date
limit 10;
QUERY PLAN
Limit  (cost=73954.85..73954.88 rows=10 width=328) (actual time=614.913..614.914 rows=10 loops=1)
  Buffers: shared hit=9 read=25307, temp read=6671 written=6671
  ->  Sort  (cost=73954.85..74216.20 rows=104539 width=328) (actual time=614.912..614.912 rows=10 loops=1)
        Sort Key: users.reg_date
        Sort Method: top-N heapsort  Memory: 25kB
        Buffers: shared hit=9 read=25307, temp read=6671 written=6671
        ->  GroupAggregate  (cost=67941.35..71695.80 rows=104539 width=328) (actual time=432.031..598.345 rows=104539 loops=1)
              Buffers: shared hit=6 read=25307, temp read=6671 written=6671
              ->  Merge Left Join  (cost=67941.35..69866.37 rows=104539 width=328) (actual time=432.019..535.760 rows=161688 loops=1)
                    Merge Cond: (users.id = user_comments.user_id)
                    Buffers: shared hit=6 read=25307, temp read=6671 written=6671
                    ->  Sort  (cost=33360.14..33621.49 rows=104539 width=8) (actual time=267.480..292.054 rows=104539 loops=1)
                          Sort Key: users.id
                          Sort Method: external merge  Disk: 1408kB
                          Buffers: shared hit=4 read=22164, temp read=181 written=181
                          ->  Seq Scan on users  (cost=0.00..23213.39 rows=104539 width=8) (actual time=0.012..202.277 rows=104539 loops=1)
                                Buffers: shared hit=4 read=22164
                    ->  Materialize  (cost=34581.21..34981.87 rows=80133 width=324) (actual time=164.533..205.544 rows=80155 loops=1)
                          Buffers: shared hit=2 read=3143, temp read=6490 written=6490
                          ->  Sort  (cost=34581.21..34781.54 rows=80133 width=324) (actual time=164.525..193.679 rows=80155 loops=1)
                                Sort Key: user_comments.user_id
                                Sort Method: external merge  Disk: 24048kB
                                Buffers: shared hit=2 read=3143, temp read=6490 written=6490
                                ->  Seq Scan on user_comments  (cost=0.00..3946.33 rows=80133 width=324) (actual time=0.028..48.802 rows=80155 loops=1)
                                      Buffers: shared hit=2 read=3143
Total runtime: 619.567 ms
答案

正如其中一条评论中所提到的,磁盘上有各种类型,“排序方法:外部合并磁盘:24048kB”。

如果可能,应该避免这种情况,因此如果您有足够的内存,则可以增加work_mem。默认值“4MB”相当小。

请记住,如果您将work_mem设置为大并且有大量查询同时进行工作,则可能会耗尽系统内存。

要在日志文件中查看临时文件用法,还应设置“log_temp_files = 0”

另一答案

这是通过横向连接改进的吗?

select u.id, u.full_name,
       uc.badges, uc.comment_count
from users u left join lateral
     (select sum(uc.badges) as badges, count(*) as comment_count
      from user_comments uc
      where u.id = uc.user_id
     ) uc
order by u.reg_date
limit 10
另一答案
  • 首先。为什么表'user_itens'出现在您的EXPLAIN中?您在此查询中使用任何视图吗?
  • 当您在GROUP BY和ORDER BY上使用相同的键,并且您的键是UNIQUE时,它会使Postgres使用更好的计划。
  • 尝试在此会话中为WORK_MEM使用更高的值,然后重试(使用命令SET work_mem = 64MB或其他类似的值)。然后多次运行您的查询。

以上是关于使用group by with order一起查询时间慢的主要内容,如果未能解决你的问题,请参考以下文章

sql里 where和order by一起使用是怎样的顺序

GROUP BY 和 ORDER BY一起使用

一起使用 ORDER BY 和 GROUP BY

mysql ORDER BY,GROUP BY 和DISTINCT原理

GROUP BY 和 ORDER BY一起使用时,要注意的问题!

GROUP BY 和 ORDER BY一起使用