SQL中where子句的顺序重要吗?


121

假设我有一个名为PEOPLE3列的表ID, LastName, FirstName,这些列都没有索引。
LastName比较独特,FirstName却不那么独特。

如果我进行2次搜索:

select * from PEOPLE where FirstName="F" and LastName="L" 
select * from PEOPLE where LastName="L" and FirstName="F"

我相信第二个更快,因为LastNamewhere子句中,更独特的标准()排在第一位,并且记录将被更有效地消除。我认为优化器不够聪明,无法优化第一个sql。

我的理解正确吗?


8
不,顺序无关紧要-任何体面的查询优化器都会查看所有 WHERE子句,并找出满足该查询的最有效方法
marc_s 2012年

3
当您运行这两个语句时,您的观察结果是什么?执行计划是什么样的?
康拉德·弗里克斯

3
您是指特定的RDBMS吗?确实存在差异。
约恩


Answers:


101

不,该顺序无关紧要(至少:无关紧要)。

任何体面的查询优化器都会查看该子句的所有部分,WHERE并找出满足该查询的最有效方法。

我知道SQL Server查询优化器将选择合适的索引-不管您有两个条件都处于哪个顺序。我假设其他RDBMS也会有类似的策略。

重要的是您是否有合适的索引!

对于SQL Server,如果满足以下条件,它将可能使用索引:

  • 索引 (LastName, FirstName)
  • 索引 (FirstName, LastName)
  • (LastName)或或(FirstName)(或两者)上的索引

另一方面-对于SQL Server来说-如果您习惯于从表中SELECT *获取所有列,并且表很小,则查询优化器很有可能只会执行表(或聚集索引)扫描而不是使用一个索引(因为查找整个数据页以获取所有其他列的速度非常快)。


如果没有索引,则op可能是正确的,具体取决于数据。当然在没有索引的情况下进行这样的Somnething,将是一个奇怪的决定……
Tony Hopkinson

@TonyHopkinson:我不这么认为-即使没有索引,我也怀疑是否有任何区别。毕竟:没有索引,RDBMS除了可以进行全表扫描外,还能做什么?
marc_s 2012年

2
使用SQL Server有趣的旁注,显然谓词中NOT EXISTS的顺序实际上会影响计划的创建:bradsruminations.blogspot.com/2010/04/looking-under-hood.html
Justin Swartsel,2012年

3
奇怪的是,对于第一次执行查询,WHERE子句中条件的顺序确实很重要!我有两个条件,例如:WHERE T1.col_1/T2.col_2 > 10 AND T2.col_2 <> 0并出现DIVIDE BY 0错误。在切换顺序条件之后,查询成功执行。然后我转回了订单,所以我希望再次出现错误,但这一次还是可以的!最后我的结论是,对于第一次运行而言,订单确实很重要,直到建立执行计划为止。 “无关紧要”是因为优化程序/执行计划将解决该问题
Radu Gheorghiu 2014年

1
我喜欢你说的:“ ...至少:不要紧”-我完全同意。不幸的是,有时候这确实很重要。我已经看到了SQL对于优化器来说太复杂而无法处理的情况,而列顺序和表连接顺序之类的事情确实有所作为。它取决于RDBMS,SQL语句的复杂性,甚至取决于发行版。非常复杂的SQL可能导致错误的优化器决策或在优化器代码中使用硬编码的默认值。
维克多·迪里奥

19

WHERE子句的顺序不应在符合SQL标准的数据库中有所作为。在大多数数据库中,不能保证评估顺序。

不要以为SQL关心顺序。以下在SQL Server中生成错误:

select *
from INFORMATION_SCHEMA.TABLES
where ISNUMERIC(table_name) = 1 and CAST(table_name as int) <> 0

如果首先执行此子句的第一部分,则仅将数字表名强制转换为整数。但是,它失败了,提供了一个清楚的例子,即SQL Server(与其他数据库一样)不关心WHERE语句中子句的顺序。


导致错误的查询与WHERE谓词评估的顺序有什么关系?
吉姆(Jim)

7
@Jim如果ISNUMERIC(table_name) = 1首先被求值,则CAST只会调用数字表名。但是,由于未首先CAST对其进行评估,因此也会对非数字表名称进行评估,从而导致错误消息。
hibbelig

2
出色的澄清
neeohw

只是为了确保我检查了条件的交换是否会使SQL Server以相反的方式处理它们,但是这两种方法都失败了。我认为这可能意味着两件事:(1)不能尽其所能进行优化,或者(2)这是一个编译时错误,SQL甚至没有开始尝试比较任何东西,只是进行了初步的努力。我的猜测是它是nr。2.
Louis Somers

9

ANSI SQL草稿2003 5WD-01-Framework-2003-09.pdf

6.3.3.3规则评估顺序

...

如果优先级不是由格式或括号确定的,则通常从左到右执行表达式的有效评估。但是,取决于表达式是否实际上是从左到右求值,这取决于实现,特别是在操作数或运算符可能导致条件升高或是否可以在不完全评估表达式所有部分的情况下确定表达式的结果时。

这里复制


2

不,所有RDBM都首先要分析查询并通过对where子句重新排序来对其进行优化。

根据您使用的RDBM,可以显示分析的结果(例如在oracle中搜索解释计划)

M.


它基于索引来执行。因此,它在内容方面是间接的。
托尼·霍普金森

1

原始OP声明

我相信第二个更快,因为在where子句中,更独特的标准(LastName)首先出现,并且记录将更有效地消除。我认为优化器没有足够的智能来优化第一个sql。

我猜您在创建索引时选择列的顺序会混淆这一点,在索引中您必须将选择性最高的列放在第一位而不是第二高选择性的列上,依此类推。

顺便说一句,对于上述两个查询,SQL Server优化器将不执行任何优化,但将使用Trivila计划,只要该计划的总成本小于并行度阈值成本即可。


0

假设名称未编入索引,这是事实。但是,不同的数据会使它出错。为了找出执行此方法的方式,每次可能有所不同,DBMS必须为每个列运行一个不同的计数查询并比较数字,这比耸耸肩继续下去要花费更多。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.