以下三个SQL语句的性能是否有任何差异?
SELECT * FROM tableA WHERE EXISTS (SELECT * FROM tableB WHERE tableA.x = tableB.y) SELECT * FROM tableA WHERE EXISTS (SELECT y FROM tableB WHERE tableA.x = tableB.y) SELECT * FROM tableA WHERE EXISTS (SELECT 1 FROM tableB WHERE tableA.x = tableB.y)
它们都应该工作并返回相同的结果集.但是如果内部SELECT选择tableB的所有字段,一个字段或只是一个常量,这是否重要?
当所有陈述行为相同时,是否有最佳做法?
关于EXISTS子句的真相是SELECT子句不在EXISTS子句中计算 - 您可以尝试:
SELECT * FROM tableA WHERE EXISTS (SELECT 1/0 FROM tableB WHERE tableA.x = tableB.y)
...并且应该期望除以零误差,但是你不会因为它没有被评估.这就是为什么我的习惯是在EXISTS中指定NULL以证明可以忽略SELECT:
SELECT * FROM tableA WHERE EXISTS (SELECT NULL FROM tableB WHERE tableA.x = tableB.y)
在EXISTS子句中重要的是FROM和beyond子句 - WHERE,GROUP BY,HAVING等.
这个问题没有考虑到数据库的标记,应该是因为供应商以不同的方式处理事情 - 所以测试,并检查解释/执行计划以确认.版本之间的行为可能会发生变化......
绝对是#1.它"看起来"可怕,但意识到优化器会做正确的事情,并表达意图.如果一个人意外地认为EXISTS但输入IN,那么这也是一个轻微的错误奖励.#2是可以接受但不具有表现力.第三个选项在我不太谦虚的意见中发臭.它太接近于说"如果'没有价值'存在"舒适.
一般而言,如果代码提供其他好处并且实际上不会影响性能,那么编写看起来效率低下的代码并不重要.
也就是说,优化器几乎总是执行复杂的连接/选择/分组向导,以同样的方式保存简单的EXISTS /子查询.
在给予自己的勇气以便巧妙地重写那个讨厌的OR之后,你最终会意识到优化器仍然使用相同的糟糕的执行计划来解决嵌入式OR更容易理解的查询.
故事的寓意是了解你的平台优化器.尝试不同的事情,看看实际上正在做什么,因为关于"装饰性"查询优化的猖獗的膝盖抽搐假设几乎总是不正确的,与我的经验无关.
我意识到这是一个老帖子,但我认为重要的是要清楚为什么人们可能会选择一种格式而不是另一种格式.
首先,正如其他人所指出的那样,数据库引擎应该忽略Select子句.每个版本的SQL Server都有/确实,Oracle有,MySQL确实等等.在很多很多数据库开发中,我只遇到过一个没有正确忽略Select子句的DBMS:Microsoft Access.具体来说,旧版本的MS Access(我不能说当前版本).
在我发现这个"功能"之前,我曾经使用过Exists( Select *...
.但是,我发现MS Access将流经子查询中的每一列,然后丢弃它们(Select 1/0
也行不通).这说服了我切换到Select 1
.如果即使一个DBMS是愚蠢的,另一个也可能存在.
写作Exists( Select 1...
在传达意图方面非常清楚(坦率地说,"如果'没有价值'存在",那就太过于接近了."并且让DBMS用Select语句做一些愚蠢的事情几乎是不可能的. .Select Null
将起到同样的作用,但只是更多的字符写.
我转而Exists( Select 1
绝对确保DBMS不会是愚蠢的.然而,那是在很多个月前,而今天我希望大多数开发人员都希望看到Exists( Select *
哪些工作完全相同.
也就是说,Exists(Select *
即使您的DBMS正确评估它,我也可以提供一个避免的理由.Select *
如果您不必在Exists子句中跳过其使用的每个实例,则更容易找到并破坏所有用途.