如何解决慢连接取决于在它之外使用的条件
我有两个表:users
和 notifications
。两者都有大约 500 000 行。
用户可能收到通知。
我创建了一个视图 user_notifications
,它按 user_id
对通知进行分组:
SELECT
user_id,count(*) as notification_count,...
FROM notifications
GROUP BY user_id
这是我用来查找用户以及用户收到多少通知的查询:
SELECT
user_id
name,user_notifications.notification_count,...
FROM users
LEFT JOIN LATERAL (
SELECT
notification_count,...
FROM user_notifications
WHERE user_id = users.user_id
) user_notifications ON TRUE
WHERE name ILIKE '%John Doe%'
列 user_id
在两个表中都有索引,users.name
(GIN gin_trgm_ops) 也是如此。
此查询产生一个结果并且速度很慢(800 毫秒)。根据 EXPLAIN ANALYZE
,加入时不使用 notifications.user_id
上的索引。
但是,如果我不使用视图,而是直接加入和分组notifications
,则使用索引并且查询速度很快(10ms)。
此外,如果我使用 user_id
而不是 name
的视图和查询,即 WHERE user_id = '1'
,使用索引并且查询很快。
当我查询 notifications.user_id
而不是 user_id
时,为什么 postgres 使用 name
上的索引?为什么在我不查询视图时使用索引?
(使用 PostgreSQL 12.5)
附注。查询和数据被简化,但这些是有趣的部分。我知道我不必使用视图,但它会简化并使其他查询更清晰。
更新:
EXPLAIN ANALYZE
输出:
Merge Left Join (cost=66189.69..79940.44 rows=50 width=275) (actual time=21124.540..21124.636 rows=1 loops=1)
Merge Cond: ((users.user_id)::text = (notifications.user_id)::text)
-> Sort (cost=354.77..354.89 rows=50 width=269) (actual time=2.379..2.416 rows=1 loops=1)
Sort Key: users.user_id
Sort Method: quicksort Memory: 25kB
-> Bitmap Heap Scan on users (cost=160.39..353.36 rows=50 width=269) (actual time=2.338..2.365 rows=1 loops=1)
Recheck Cond: ((name)::text ~~* '%John Doe%'::text)
Heap Blocks: exact=1
-> Bitmap Index Scan on name_index (cost=0.00..160.38 rows=50 width=0) (actual time=2.309..2.315 rows=1 loops=1)
Index Cond: ((name)::text ~~* '%John Doe%'::text)
-> GroupAggregate (cost=65834.92..73334.92 rows=500000 width=39) (actual time=7305.864..17762.391 rows=477778 loops=1)
Group Key: notifications.user_id
-> Sort (cost=65834.92..67084.92 rows=500000 width=6) (actual time=7305.828..10839.863 rows=477779 loops=1)
Sort Key: notifications.user_id
Sort Method: external merge Disk: 8248kB
-> Seq Scan on notifications (cost=0.00..11667.00 rows=500000 width=6) (actual time=0.016..3485.382 rows=499998 loops=1)
Planning Time: 0.472 ms
Execution Time: 21126.607 ms
出于某种原因,EXPLAIN ANALYZE
需要大约 20 秒,而没有它的查询需要 800 毫秒。
我使用 LATERAL
的原因是,当我直接加入 notifications
表(即完全跳过视图)时,常规联接导致索引未被使用。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。