我可以使用索引优化此查询吗?

问题描述

给定这个查询

SELECT count(u.*)
FROM res_users u
WHERE active=true AND
share=false AND
NOT exists(SELECT 1 FROM res_users_log WHERE create_uid=u.id);

目前需要 10 秒。

我尝试使用这 2 个索引命令使其更快,但没有帮助。

CREATE INDEX CONCURRENTLY id_active_share_index ON res_users (id,active,share);
CREATE INDEX CONCURRENTLY create_uid_index ON res_users_log (create_uid);

我猜是因为“不存在”这一行,但我不知道如何将它包含到索引中。

EXPLAIN (ANALYZE,BUFFERS) 给我这个输出

                                                                   QUERY PLAN                                                                   
------------------------------------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=2815437.14..2815437.15 rows=1 width=8) (actual time=39174.365..39174.367 rows=1 loops=1)
   Buffers: shared hit=124 read=112875 dirtied=70,temp read=98788 written=99211
   ->  Merge Anti Join  (cost=2678572.70..2815437.09 rows=20 width=1064) (actual time=39174.360..39174.361 rows=0 loops=1)
         Merge Cond: (u.id = res_users_log.create_uid)
         Buffers: shared hit=124 read=112875 dirtied=70,temp read=98788 written=99211
         ->  Sort  (cost=11.92..11.97 rows=20 width=1068) (actual time=5.577..5.602 rows=16 loops=1)
               Sort Key: u.id
               Sort Method: quicksort  Memory: 79kB
               Buffers: shared hit=53 read=5
               ->  Seq Scan on res_users u  (cost=0.00..11.49 rows=20 width=1068) (actual time=0.050..5.519 rows=16 loops=1)
                     Filter: (active AND (NOT share))
                     Rows Removed by Filter: 33
                     Buffers: shared hit=49 read=5
         ->  Sort  (cost=2678560.78..2716236.90 rows=15070449 width=4) (actual time=36258.796..38013.471 rows=15069209 loops=1)
               Sort Key: res_users_log.create_uid
               Sort Method: external merge  disk: 206464kB
               Buffers: shared hit=71 read=112870 dirtied=70,temp read=98788 written=99211
               ->  Seq Scan on res_users_log  (cost=0.00..263645.49 rows=15070449 width=4) (actual time=1.755..29961.086 rows=15069319 loops=1)
                     Buffers: shared hit=71 read=112870 dirtied=70
 Planning Time: 0.889 ms
 Execution Time: 39202.694 ms
(21 rows)

解决方法

对于这个查询:

SELECT count(*)
FROM res_users u
WHERE active = true AND
      share = false AND
      NOT exists (SELECT 1 FROM res_users_log rul WHERE rul.create_uid = u.id);

您想要索引:

  • res_users(active,share,id)
  • res_users_log(create_uid)

请注意,列的顺序很重要。

,

这个索引将使查询快如闪电:

CREATE INDEX ON res_users_log (create_uid);