优化 JOIN ON OR 而无需为每个 OR 重复查询
Optimizing JOIN ON OR without repeating query for every OR
正如 this answer 所解释的那样,无法优化 JOIN ON
与 OR
的组合。我确实注意到我正在尝试编写的查询中的糟糕性能。
为了描述我的场景,应该返回一条 header 记录以及来自所有相关项目记录的数据。一个项目可以与基于三个字段之一的 header 记录相关。下面的 SQL 看起来语法合理但是非常昂贵,因为它不能优化 JOIN ON OR:
SELECT
header.a,
header.b,
item.x,
item.y,
item.z
FROM header
LEFT OUTER JOIN item ON item.x = header.a
OR item.y = header.a
OR item.z = header.b;
请注意,这是从一个复杂得多的查询中概括出来的(涉及另外 6 个联接和各种过滤器)。我预计 JOIN ON OR
实施会起作用,但我无法确认它,因为 OR
产生的完整 table 扫描可能需要几个小时才能完成。 (奖金问题:三重条件会导致单个连续 FTS 还是三个连续 FTS?)
由于周围查询的复杂性,我想避免链接答案中建议的 UNION ALL 方法。这不仅仅是因为我想避免这种程度的重复,而且查询的其余部分虽然经过优化,但其本身却非常昂贵。有没有我没有看到的替代方案?
虽然我明白你的观点是在整个查询中有很多复杂性,但我建议拆分此执行并在这种情况下实际使用 SQLScript。
由于您有效地使用三种不同的方式来关联 header 和项目,因此进行了三个查询。
使用 SQLScript,将这三个简单的连接查询分配给三个单独的 table 变量是相当简单的。
这些连接中的每一个都可以非常有效地处理,而且它们三个都可以同时执行。这不会减少整体工作,但会减少总执行时间。
此外,根据查询的性质,您可以联合三个 table 变量并将它们用作复杂剩余计算的输入。
在任何情况下:这些是您的 table 之间的三个独立链接,不试图将它们塞进一个 "mother of all SQL" 语句中似乎是最优雅和最有效的:-)
这可能看起来很丑陋,但它避免了 OR,并且有机会使用索引(如果存在):
SELECT
header.a
, header.b
, COALESCE(i1.x, i2.x, i3.x) AS itemx
, COALESCE(i1.y, i2.y, i3.y) AS itemy
, COALESCE(i1.z, i2.z, i3.z) AS itemz
FROM header h0
LEFT OUTER JOIN item i1 ON i1.x = h0.a
LEFT OUTER JOIN item i2 ON i2.y = h0.a
LEFT OUTER JOIN item i3 ON i3.z = h0.b
;
注意:它确实 假设 item.{x.y,z} 不可为空.
正如 this answer 所解释的那样,无法优化 JOIN ON
与 OR
的组合。我确实注意到我正在尝试编写的查询中的糟糕性能。
为了描述我的场景,应该返回一条 header 记录以及来自所有相关项目记录的数据。一个项目可以与基于三个字段之一的 header 记录相关。下面的 SQL 看起来语法合理但是非常昂贵,因为它不能优化 JOIN ON OR:
SELECT
header.a,
header.b,
item.x,
item.y,
item.z
FROM header
LEFT OUTER JOIN item ON item.x = header.a
OR item.y = header.a
OR item.z = header.b;
请注意,这是从一个复杂得多的查询中概括出来的(涉及另外 6 个联接和各种过滤器)。我预计 JOIN ON OR
实施会起作用,但我无法确认它,因为 OR
产生的完整 table 扫描可能需要几个小时才能完成。 (奖金问题:三重条件会导致单个连续 FTS 还是三个连续 FTS?)
由于周围查询的复杂性,我想避免链接答案中建议的 UNION ALL 方法。这不仅仅是因为我想避免这种程度的重复,而且查询的其余部分虽然经过优化,但其本身却非常昂贵。有没有我没有看到的替代方案?
虽然我明白你的观点是在整个查询中有很多复杂性,但我建议拆分此执行并在这种情况下实际使用 SQLScript。
由于您有效地使用三种不同的方式来关联 header 和项目,因此进行了三个查询。 使用 SQLScript,将这三个简单的连接查询分配给三个单独的 table 变量是相当简单的。
这些连接中的每一个都可以非常有效地处理,而且它们三个都可以同时执行。这不会减少整体工作,但会减少总执行时间。
此外,根据查询的性质,您可以联合三个 table 变量并将它们用作复杂剩余计算的输入。
在任何情况下:这些是您的 table 之间的三个独立链接,不试图将它们塞进一个 "mother of all SQL" 语句中似乎是最优雅和最有效的:-)
这可能看起来很丑陋,但它避免了 OR,并且有机会使用索引(如果存在):
SELECT
header.a
, header.b
, COALESCE(i1.x, i2.x, i3.x) AS itemx
, COALESCE(i1.y, i2.y, i3.y) AS itemy
, COALESCE(i1.z, i2.z, i3.z) AS itemz
FROM header h0
LEFT OUTER JOIN item i1 ON i1.x = h0.a
LEFT OUTER JOIN item i2 ON i2.y = h0.a
LEFT OUTER JOIN item i3 ON i3.z = h0.b
;
注意:它确实 假设 item.{x.y,z} 不可为空.