我经常会看到正常的
JOIN
写成 CROSS JOIN
并在末尾添加 WHERE
子句,尤其是在查看 WITH RECURSIVE
文档时。例如:
a,b WHERE (a.id=b.parent_id) -- same as: a CROSS JOIN b WHERE a.id=b.parent_id
a JOIN b ON (a.id=b.parent_id)
有任何理由这样做吗?我的想法是,查询优化器可能不会将交叉联接转换为第一个版本,因此效率可能较低。
举一个实际的例子,如下:
CREATE TABLE body AS (
SELECT 1 id, 'body' AS name, NULL parent_id UNION ALL
SELECT 2, 'head', 1 UNION ALL
SELECT 3, 'eyes', 2 UNION ALL
SELECT 4, 'pupils', 3 UNION ALL
SELECT 5, 'torso', 1 UNION ALL
SELECT 6, 'arms', 5
);
-- using JOIN with condition
WITH RECURSIVE body_paths (id, part, path) AS (
SELECT id, name, name AS path FROM body WHERE parent_id IS NULL -- VALUES (1, "body", "body")
UNION ALL
SELECT body.id, body.name, CONCAT(path, '.', body.name)
FROM body JOIN body_paths ON (body.parent_id=body_paths.id)
) SELECT * FROM body_paths WHERE part in ('pupils', 'arms');
-- using CROSS JOIN + WHERE
WITH RECURSIVE body_paths (id, part, path) AS (
SELECT id, name, name AS path FROM body WHERE parent_id IS NULL -- VALUES (1, "body", "body")
UNION ALL
SELECT body.id, body.name, CONCAT(path, '.', body.name)
FROM body, body_paths WHERE (body.parent_id=body_paths.id)
) SELECT * FROM body_paths WHERE part in ('pupils', 'arms');
-- both produce
┌────┬────────┬───────────────────────┐
│ id ┆ part ┆ path │
╞════╪════════╪═══════════════════════╡
│ 6 ┆ arms ┆ body.torso.arms │
│ 4 ┆ pupils ┆ body.head.eyes.pupils │
└────┴────────┴───────────────────────┘
现在,在少于 10 行的 CTE 上,优化并不重要,但在一般情况下,应该首选非交叉连接还是为什么要以其他方式编写?
对于where子句,逗号连接相当于内连接。 (从技术上讲,带有 where 子句的交叉联接也相当于内部联接 - 只会输出每个表中匹配的记录,而不是两个表中的所有记录。)
就性能而言,应该没有区别,因为优化器会为其找出最佳查询计划。然而,在维护和可读性方面,逗号连接更难以阅读和理解,特别是当您向查询添加更多表时,并且正如您的问题所示,它们的行为也不太容易理解。关联哪些子句影响哪些连接也更困难。
逗号连接是一种更古老的语法,它在很大程度上已经失宠,这是有充分理由的。