我有一个用于存储两个用户之间关系的表friend
。
例如:(1,2)
表示user1和user2是朋友。 (2,1)
表示相同,但我们不会将其存储起来,手动制作uid1 < uid2
:
CREATE TABLE public.friend (
uid1 INTEGER,
uid2 INTEGER
);
CREATE INDEX index_uid1 ON friend USING BTREE (uid1);
CREATE INDEX index_uid2 ON friend USING BTREE (uid2);
要找到uid=2
的朋友,我可以使用:
SQL1:
select * from friend where uid1=2
union
select * from friend where uid2=2;
SQL2:
select * from friend uid1=2 or uid2=2
我得到的是 sql2 在性能方面优于 sql1 。
但建议使用 sql1 。这是对的吗?
答案 0 :(得分:2)
它们在技术上不相同,union运算符将删除重复项,而第二个示例则不会。
答案 1 :(得分:1)
union
会导致删除重复项的开销。也许最有效的查询方法是:
select f.* from friend f where uid1 = 2
union all
select f.* from friend f where uid2 = 2 and uid1 <> 2;
特别是,这可以利用f(uid1)
和f(uid2)
上的索引。你的第二个版本可能正在进行全表扫描。
答案 2 :(得分:1)
我有一个用于存储两者之间关系的表
friend
用户。例如:
(1,2)
表示user1和user2是朋友。(2,1)
表示 相同,但我们不会存储,uid1 < uid2
手动:
通常情况下,您可以通过(udi1, uid2)
PRIMARY KEY
和CHECK
constraint强制执行uid1 < uid2
来实现此目标。
CREATE TABLE public.friend (
uid1 integer
, uid2 integer
, PRIMARY KEY (uid1, uid2)
, CONSTRAINT uid2_gt_uid1 CHECK (uid1 < uid2)
);
CREATE INDEX index_uid2 ON friend USING BTREE (uid2);
你不需要另一个索引,它被PK的索引覆盖;
CREATE INDEX index_uid1 ON friend USING BTREE (uid1);
然后就不会有重复(包括切换重复),也没有人可以与他/她自己成为朋友,你的查询可以简单地是:
SELECT * FROM friend WHERE 2 IN (uid1, uid2);
......这是简称:
SELECT * FROM friend WHERE uid1 = 2 OR uid2 = 2;
UNION
变体现在在逻辑上相同:
SELECT * FROM friend WHERE uid1=2
UNION
SELECT * FROM friend WHERE uid2=2;
但是你会UNION ALL
而不仅仅是UNION
因为没有重复项而且UNION ALL
更便宜。但仍然比上面的单SELECT
贵一点。
UNION ALL
查询中有三个 可能的重复来源:
SELECT
分支多次获取行。CHECK
约束排除。)了解了这一点后,您还了解了不同查询技术的含义。使用建议设置时,只有2.
仍然存在问题。