使用 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>
- Is a composite index also good for queries on the first field?
- PostgreSQL composite primary key
则不能有重复项(包括切换的重复项),也没有人可以与 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
查询中的重复来源:
- 基础table中的重复行(由PK排除)。
- 多个
SELECT
分支多次提取行。
- 在您的特定情况下:合乎逻辑 具有切换 ID 的重复项(由
CHECK
约束排除)。
一旦理解了这一点,您也就理解了不同查询技术的含义。使用建议的设置,只有 2.
仍然是可能的问题。
我有一个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, makinguid1 < 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>
- Is a composite index also good for queries on the first field?
- PostgreSQL composite primary key
则不能有重复项(包括切换的重复项),也没有人可以与 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
查询中的重复来源:
- 基础table中的重复行(由PK排除)。
- 多个
SELECT
分支多次提取行。 - 在您的特定情况下:合乎逻辑 具有切换 ID 的重复项(由
CHECK
约束排除)。
一旦理解了这一点,您也就理解了不同查询技术的含义。使用建议的设置,只有 2.
仍然是可能的问题。