使用 UNION 或 OR 查询?

Query with UNION or OR?

我有一个table 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。对吗?

它们在技术上并不相同,联合运算符会删除重复项,而第二个示例则不会。

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) 上的索引。您的第二个版本可能正在进行全面 table 扫描。

I have a table friend used to store the relationship between two user.

For example: (1,2) means user1 and user2 are friends. (2,1) means the same, but there we won't store that, making uid1 < uid2 manually:

通常,您可以通过 PRIMARY KEY on (udi1, uid2) and a 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的索引覆盖了;

<strike>CREATE INDEX index_uid1 ON friend USING BTREE (uid1);</strike>

则不能有重复项(包括切换的重复项),也没有人可以与 him/her self 成为朋友,您的查询可以简单地是:

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. 基础table中的重复行(由PK排除)。
  2. 多个 SELECT 分支多次提取行
  3. 在您的特定情况下:合乎逻辑 具有切换 ID 的重复项(由 CHECK 约束排除)。

一旦理解了这一点,您也就理解了不同查询技术的含义。使用建议的设置,只有 2. 仍然是可能的问题。