正如其他人指出的那样,这个相关的子查询可以重写为一个连接,但这并不完全是完整的故事,因为未转换的 EXISTS 的执行计划无论如何都会看起来很像一个连接。所以这不是一个真正的语法问题,而是一个查询优化问题。
EXISTS 实际上只是“加入此数据集但仅加入其中的单行,即使有 1,000,000 个匹配项”的语法简写,或者也称为semijoin。
因此,EXISTS 谓词针对相关或不相关子查询所需的半连接可以通过多种方式实现,这在很大程度上取决于两个表中的数字或记录。
如果您想象 CUSTOMER 估计只有一行,并且优化器估计 RENTALS 中有数千行 PICKUP = 'CARY',那么优化器很可能会从 CUSTOMER TABLE 中读取该行并执行对 RENTALS 表进行一次查找。
如果估计有 100 万个 CUSTOMERS 并且 RENTALS 表中只有一行,那么该执行计划将是疯狂的——优化器可以通过以 RENTALS 表开头并查找 CUSTOMER 表中的单行来反转连接回来。在这种情况下,可以说根本没有执行子查询。
在这些极端之间,还有其他各种优化。例如,将 RENTAL.CID 列的唯一值构建到 PICKUP='CARY' 行的内存哈希表中,并全面扫描 CUSTOMER TABLE 以探测每一行的哈希表,这将是一个 HASH SEMIJOIN . 同样,没有执行可识别的子查询。(Barmer 建议的查询重写可能会导致这种计划,但也可能会限制优化器查看适用于其他数据分布和基数的其他计划)。
所以,正如其他答案所说,这个问题真的没有实际意义,因为我认为这里有两个重要的教训:
- 许多不同的 SQL 语句可以导致相同的执行计划,单个 SQL 语句也可以导致多个执行计划。
- 您应该编写在语法上表达您想要的结果的查询,而不是一般地抢占和约束查询优化器的选择。
第二点很重要,因为它反对某些开发人员避免编写相关子查询(尤其是 EXISTS 或 NOT EXISTS)以提供他们自己的优化的本能。特别是,考虑到正确/错误的数据分布,用外部连接替换 EXISTS 可能不是最理想的。
为了直接回答这个问题,我会说:
- 0
- 1
- 但是很多行在 CUSTOMERS
- 可能是别的东西。