任务:从号码表中找到每个员工的电话号码。但仅当每个员工只有一个数字时才输出,否则null而不是数字。
解决方案CROSS APPLY:
SELECT n.name, t.phone_num
FROM emp_names n
CROSS APPLY (SELECT phone_num
FROM phones p
WHERE p.name = n.name
GROUP BY phone_num
HAVING count(*)=1) t
但是这个方法在 11g 中不适用,因为。还没有CROSS APPLY。我正在尝试使用子查询的解决方案:
SELECT n.name,
(SELECT phone_num
FROM phones p
WHERE p.name = n.name
GROUP BY phone_num
HAVING count(*)=1) phone_num
FROM emp_names n
是否相当于请求的成本?毕竟,如果在表中emp_names我们有一个名称 1000 次,那么将有 1000 个相同的子查询具有相同的答案。同时,phones从表中拉出所有相同号码的人并加入也不是一种选择,因为 这张桌子很大。
有没有类似CROSS APPLYOracle 11g 更经济的方式?
尝试与此查询进行比较:
您可以在真实数据或尽可能接近真实的数据示例上比较执行计划。因此,我将避免将上述要求评估为最“经济”的要求。
对比一下
CROSS APPLY(问题最有可能是关于OUTER APPLY),你可以用11g中的等价物LATERAL(因为没有官方支持,只针对测试环境):对db<>fiddle的请求。
子句中的相关子查询
SELECT(问题中的第二个)通常比其等效子查询更有效OUTER JOIN(但并非总是如此,具体取决于数据)。问题中假设对于外部表中的 1000 个相同的值,子查询将执行 1000 次并返回相同的答案是false。在这种情况下,数据库将缓存子查询的结果(标量子查询缓存)将是一个优势。即对于来自外部表的每一组值,子查询只会执行一次,其结果会被写入内存中的临时哈希表。对于所有后续相同的值,将从该哈希表中获取结果。
一个支持上述内容的小例子。架构准备:
以下查询将返回三条记录,但子查询只会执行一次:
你可以这样尝试