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>;

我鼓励您使用 INEXISTS:

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>);