SELECT ... WHERE IN 与 JOIN
SELECT ... WHERE IN vs JOIN
假设我们在一些未指定的关系SQL数据库中有4 tables A、B、C、D。 A 引用 B,也引用 C 和 D。 References 表示 A 有列 A.refX_id = X.id,X 是 A、B 和 C(公共外键 1:N)。
我想要的是根据所有子 tables B、C 和 D 的列查询 table A。我的问题是:What of the以下变体通常更好?(在可用性、效率、速度方面。)
变体 1:
SELECT DISTINCT A.* FROM A
JOIN B ON A.refB_id = B.id
JOIN C ON A.refC_id = C.id
JOIN D ON A.refD_id = D.id
WHERE <condition on B> AND <condition on C> AND <condition on D>;
从数据库的角度我更喜欢它,但看起来有点难编程。
变体 2:
SELECT id FROM B WHERE <condition on B>; # result store to array "BIds" on program side
SELECT id FROM C WHERE <condition on C>; # result store to array "CIds" on program side
SELECT id FROM D WHERE <condition on D>; # result store to array "DIds" on program side
SELECT A.* FROM A
WHERE refB_id IN (<B_ids>) AND refC_id IN (<C_ids>) AND refD_id IN (<D_ids>);
# <B_ids> menas expand whole array of ids, which can result in a very long query string
我认为 变体 2 完全是黑穗病并且无法用于潜在的大数据。但我听说,很多框架通常都使用它,因为它相对简单。如果我知道 "IN" 子句的内容是从另一个查询的结果中获取的,那么在一般情况下查询这样的数据是否合法?
不确定哪个框架使用第二种方法,但第一种方法是我将采用的方法,而且其他人也会采用。如果您在所有表的连接列上创建了适当的索引,那么第一种方法将产生比第二种方法更好的计划,因为您有多个 IN
子句,如果每个 IN
都必须处理数百万元素数???.
此外,假设并非所有 ID 都匹配,我会将 INNER JOIN
更改为 LEFT JOIN
,并将 WHERE
条件移动到 JOIN ON
条件,例如
SELECT DISTINCT A.* FROM A
LEFT JOIN B ON A.refB_id = B.id AND <condition on B>
LEFT JOIN C ON A.refC_id = C.id AND <condition on C>
LEFT JOIN D ON A.refD_id = D.id AND <condition on D>;
我鼓励您使用 IN
或 EXISTS
:
SELECT A.*
FROM A
WHERE EXISTS (SELECT 1 FROM B WHERE A.refB_id = B.id AND <condition on B>) AND
EXISTS (SELECT 1 FROM C WHERE A.refC_id = C.id AND <condition on C>) AND
EXISTS (SELECT 1 FROM D WHERE A.refD_id = D.id AND <condition on D>);
这种方法的优点:
- 没有获得大的中间笛卡尔积的危险。
- 无需为
SELECT DISTINCT
删除重复项。
- 大多数数据库处理
EXISTS
相当好。
- 您可以使用索引优化每个子查询。
编辑:
你可以用 IN
和子查询来写这个:
SELECT A.*
FROM A
WHERE A.refB_id IN (SELECT B.id FROM B WHERE <condition on B>) AND
A.refC_id IN (SELECT C.id FROM C WHERE <condition on C>) AND
A.refD_id IN (SELECT D.id FROM D WHERE <condition on D>);
假设我们在一些未指定的关系SQL数据库中有4 tables A、B、C、D。 A 引用 B,也引用 C 和 D。 References 表示 A 有列 A.refX_id = X.id,X 是 A、B 和 C(公共外键 1:N)。
我想要的是根据所有子 tables B、C 和 D 的列查询 table A。我的问题是:What of the以下变体通常更好?(在可用性、效率、速度方面。)
变体 1:
SELECT DISTINCT A.* FROM A
JOIN B ON A.refB_id = B.id
JOIN C ON A.refC_id = C.id
JOIN D ON A.refD_id = D.id
WHERE <condition on B> AND <condition on C> AND <condition on D>;
从数据库的角度我更喜欢它,但看起来有点难编程。
变体 2:
SELECT id FROM B WHERE <condition on B>; # result store to array "BIds" on program side
SELECT id FROM C WHERE <condition on C>; # result store to array "CIds" on program side
SELECT id FROM D WHERE <condition on D>; # result store to array "DIds" on program side
SELECT A.* FROM A
WHERE refB_id IN (<B_ids>) AND refC_id IN (<C_ids>) AND refD_id IN (<D_ids>);
# <B_ids> menas expand whole array of ids, which can result in a very long query string
我认为 变体 2 完全是黑穗病并且无法用于潜在的大数据。但我听说,很多框架通常都使用它,因为它相对简单。如果我知道 "IN" 子句的内容是从另一个查询的结果中获取的,那么在一般情况下查询这样的数据是否合法?
不确定哪个框架使用第二种方法,但第一种方法是我将采用的方法,而且其他人也会采用。如果您在所有表的连接列上创建了适当的索引,那么第一种方法将产生比第二种方法更好的计划,因为您有多个 IN
子句,如果每个 IN
都必须处理数百万元素数???.
此外,假设并非所有 ID 都匹配,我会将 INNER JOIN
更改为 LEFT JOIN
,并将 WHERE
条件移动到 JOIN ON
条件,例如
SELECT DISTINCT A.* FROM A
LEFT JOIN B ON A.refB_id = B.id AND <condition on B>
LEFT JOIN C ON A.refC_id = C.id AND <condition on C>
LEFT JOIN D ON A.refD_id = D.id AND <condition on D>;
我鼓励您使用 IN
或 EXISTS
:
SELECT A.*
FROM A
WHERE EXISTS (SELECT 1 FROM B WHERE A.refB_id = B.id AND <condition on B>) AND
EXISTS (SELECT 1 FROM C WHERE A.refC_id = C.id AND <condition on C>) AND
EXISTS (SELECT 1 FROM D WHERE A.refD_id = D.id AND <condition on D>);
这种方法的优点:
- 没有获得大的中间笛卡尔积的危险。
- 无需为
SELECT DISTINCT
删除重复项。 - 大多数数据库处理
EXISTS
相当好。 - 您可以使用索引优化每个子查询。
编辑:
你可以用 IN
和子查询来写这个:
SELECT A.*
FROM A
WHERE A.refB_id IN (SELECT B.id FROM B WHERE <condition on B>) AND
A.refC_id IN (SELECT C.id FROM C WHERE <condition on C>) AND
A.refD_id IN (SELECT D.id FROM D WHERE <condition on D>);