用UNION或OR查询?

时间:2018-05-17 12:47:41

标签: sql postgresql postgresql-performance

我有一个用于存储两个用户之间关系的表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 。这是对的吗?

3 个答案:

答案 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 KEYCHECK 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查询中有三个 可能的重复来源:

    基础表格中的
  1. 重复行(由PK排除)。
  2. 由多个SELECT分支多次获取行。
  3. 在您的特定情况下: 逻辑 带有切换ID的重复项(由CHECK约束排除。)
  4. 了解了这一点后,您还了解了不同查询技术的含义。使用建议设置时,只有2.仍然存在问题。