我有一个用户表
/ id_user / username / ..
朋友表(AB 和 BA 对):
/ friend_of / friend_to
和一个 friend_request 表(用于待处理的好友请求)
/ id_req/ sent_from / sent_to
我想稍微搜索一下新朋友功能(自动建议样式),并且我不想在列表中显示已经在我的朋友列表中或处于待处理的朋友请求中的朋友。
查询背后的想法是显示用户的用户名不在 friend_to 列中,也不在 sent_to 列中。
我想出了这两种口味:
select id_user,username
from public.user u
where
username like '%tom%'
and
u.id_user NOT IN (SELECT sent_to FROM friend_request where sent_from = 288)
AND
u.id_user NOT IN (SELECT friend_to FROM friends where friend_of=288);
或者
select id_user,username
from public.user u
left join friend_request fr
on
u.id_user=sent_to AND fr.sent_from=288
left join friends f
on
u.id_user = f.friend_to AND f.friend_of=288
where username like '%tom%' AND sent_to IS NULL and friend_to IS NULL;
这两个产生相同的结果。但我想要一些建议,哪一个是更好的选择性能和明智的投注实践?
NOT IN
通常是最慢的选项。LEFT JOIN
/IS NULL
更有前途。或者NOT EXISTS
:询问
只是您的查询,格式为:
或者,具有
NOT EXISTS
反半连接的变体:索引
性能的最重要因素。一个理想的设置应该有:
上的trigram GIN 或 GiST 索引。
"user".username
您需要附加模块pg_trgm。说明 - 以及 Gin 或 GiST?如果可以进行仅索引扫描,请附加其他无用的
id_user
. 您需要附加模块btree_gin
(或btree_gist
分别):然后:
多列索引(或 UNIQUE/PK 约束)
(sent_from, sent_to)
和(friend_of, friend_to)
- 列按该顺序排列。相反的顺序也可以,但效果不佳。每个查询检查单个friend_of
与许多不同friend_to
的组合,这使用建议的列顺序会更快,因为这样元组更容易定位在相同或几个索引页上。也就是说,布丁的证明仍在吃中。
EXPLAIN (BUFFERS, ANALYZE)
从您的生产数据库中获取最终结论。在旁边
不要调用你的表,
user
那是一个保留字。