练习“存在(从...选择1)”从哪里来?
绝大多数人支持我自己的观点,即下列陈述没有区别:
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 * FROM tableA WHERE EXISTS (SELECT NULL FROM tableB WHERE tableA.x = tableB.y)
然而,今天我来到脸对脸与对方索赔时在我们的内部开发人员会议上,有人主张select 1
是去和方式select *
选择所有的(不必要的)数据,从而损害性能。
我似乎记得有一些旧版本的Oracle或某些地方这是真的,但我找不到对此的参考。 所以,我很好奇 - 这种做法如何诞生? 这个神话起源于哪里?
补充:由于有些人坚持有证据表明这确实是一种错误的信念,在这里 - 一个谷歌查询显示很多人这样说。 如果你太懒惰,请检查这个直接链接,其中一个人甚至会比较执行计划,发现它们是相同的。
你问题的主要部分是 - “这个神话是从哪里来的?”
因此,为了回答这个问题,我想人们用sql学到的第一个性能提示就是select *
在大多数情况下都是低效的。 因此,在这种特定情况下这种做法并不没有效率,因此有些违背直觉。 所以人们对此持怀疑态度并不奇怪。 但是一些简单的研究或实验应该足以驱散大多数的神话。 虽然人类历史有点显示神话很难消除。
作为演示,请尝试这些
SELECT * FROM tableA WHERE EXISTS (SELECT 1/0 FROM tableB WHERE tableA.x = tableB.y)
SELECT * FROM tableA WHERE EXISTS (SELECT CAST('bollocks' as int) FROM tableB WHERE tableA.x = tableB.y)
现在阅读ANSI标准。 ANSI-92,第191页,案例3a
If the <select list> "*" is simply contained in a <subquery>
that is immediately contained in an <exists predicate>, then
the <select list> is equivalent to a <value expression> that
is an arbitrary <literal>.
最后,大多数RDBMS上的行为应该忽略EXISTS子句中的THE *。 根据昨天这个问题(Sql Server 2005 - 插入如果不存在)这不适用于SQL Server 2000,但我知道它在SQL Server 2005+
对于SQL Server Conor来自查询优化器团队的Cunningham解释了为什么他通常使用SELECT 1
QP将在管道初期取得并扩展所有*,并将它们绑定到对象(在本例中为列的列表)。 由于查询的性质,它将删除不需要的列。
所以对于这样一个简单的EXISTS子查询:
SELECT col1 FROM MyTable WHERE EXISTS(SELECT * FROM Table2 WHERE MyTable.col1 = Table2.col2)*将被扩展为一些潜在的大列列表,然后确定EXISTS的语义不需要任何这些列,所以基本上所有这些都可以被删除。
“SELECT 1”将避免在查询编译期间检查该表的任何不需要的元数据。
但是,在运行时,查询的两种形式将是相同的,并且具有相同的运行时。
编辑:不过,我的一些细节,因为发布这个答案,并得出这样的结论看着这个SELECT 1
并不回避此列扩展。 详细信息在这里。
上一篇: Where does the practice "exists (select 1 from ...)" come from?