存在/不存在:“选择 1”与“选择字段”
Posted
技术标签:
【中文标题】存在/不存在:“选择 1”与“选择字段”【英文标题】:Exists / not exists: 'select 1' vs 'select field' 【发布时间】:2014-12-15 05:05:35 【问题描述】:两者中哪一个会更好(我最近被指责不小心我的代码,因为我在 Oracle 中使用了后者):
Select *
from Tab1
Where (not) exists(Select 1 From Tab2 Where Tab1.id = Tab2.id)
Select *
from Tab1
Where (not) exists(Select Field1 From Tab2 Where Tab1.id = Tab2.id)
还是两者都一样?
请从 SQL Server 和 Oracle 的角度回答。
我已经用谷歌搜索(主要来自 sql-server 端)并发现对此仍有很多争论,尽管我目前的观点/假设是 RDMBS 中的优化器已经足够成熟,可以理解所有需要子查询是一个布尔值。
【问题讨论】:
没有区别,都是一样的。检查两个查询的执行计划以进行验证。 看看这个答案..***.com/a/6140367/2975396 【参考方案1】:是的,它们是一样的。 exists
检查子查询中是否至少有一行。如果是,则计算结果为true
。子查询中的列无论如何都无关紧要。
根据MSDN,exists
:
指定一个子查询来测试行是否存在。
还有Oracle:
EXISTS 条件测试子查询中是否存在行。
也许mysql documentation 更能说明问题:
传统上,EXISTS 子查询以 SELECT * 开头,但它可以以 SELECT 5 或 SELECT column1 或任何其他开头。 MySQL 会忽略此类子查询中的 SELECT 列表,因此没有区别。
【讨论】:
Postgres 有什么不同吗? 我不知道。我没有使用 Postegres 的经验。 PostgreSQL 也是一样的。你也可以选择 null 作为其他任何东西。【参考方案2】:我知道这是旧的,但想补充我最近观察到的几点..
即使exists只检查存在,当我们写“select *”时,列会被扩展,除了这个轻微的开销,没有区别。
来源:http://www.sqlskills.com/blogs/conor/exists-subqueries-select-1-vs-select/
更新:
我提到的文章似乎无效。即使我们写select 1
,SQLServer 也会扩展所有列..
在使用各种方法时,请参考下面的链接进行深入分析和性能统计..
Subquery using Exists 1 or Exists *
【讨论】:
Conor 的文章确实有错误。他建议SELECT *
将扩展所有列元数据,而SELECT 1
不会。然而,他们俩实际上都是这样做的。您可以通过拒绝对列的权限并运行SELECT 1 WHERE EXISTS (SELECT 1 FROM T);
来查看这一点,这可能会因The SELECT permission was denied on the column 'Foo'
而意外失败,或者通过简单地计时添加更多列的效果或查看调试器***.com/a/6140367/73226
@MartinSmith:非常感谢,我很久以前就读过你的回答,但有些东西错过了一些东西。再次感谢您揭穿这个神话【参考方案3】:
子查询的列列表中的表达式完全无关紧要,它甚至不会被执行:
select * from dual t1
where exists (
select 1/0 from dual t2
--^^^ division by 0
where t2.dummy = t2.dummy)
/
DUMMY
--------
X
【讨论】:
【参考方案4】:根据我的使用经验,唯一需要注意的是 "EXISTS(SELECT * ..." 和 "EXISTS(SELECT 1 ..." 是模式绑定对象中不允许使用 "*" —— 它会抛出:
模式绑定对象中不允许使用语法“*”。
【讨论】:
以上是关于存在/不存在:“选择 1”与“选择字段”的主要内容,如果未能解决你的问题,请参考以下文章
问题存在与认知---问题产生的原因是对存在的不完全或错误认知