我有一个问题:
SELECT
someFields
FROM
someTable
WHERE
cheapLookup=1
AND (CAST(someField as FLOAT)/otherField)<0.9
那么,在CAST
是cheapLookup
的情况下,是否会执行0
和除法?如果没有,在这种情况下如何避免计算?
答案 0 :(得分:14)
这取决于查询计划,查询计划由每个考虑的替代计划的估计成本确定,以产生正确的结果。
如果谓词'cheapLookup = 1'可以使用索引,并且它具有足够的选择性,则SQL Server可能会选择在该索引上进行搜索并将第二个谓词应用为残差(即,仅在行上评估它寻求操作匹配。
另一方面,如果cheapLookup不是索引中的主键,或者它不是非常有选择性,则SQL Server可能会选择扫描,将两个谓词应用于遇到的每一行。
第二个谓词不会被选择用于搜索操作,除非在整个表达式上碰巧有一个索引计算列,并且使用该索引证明是执行整个查询的最便宜的方式。如果存在合适的索引,SQL Server将寻找'第二谓词结果&lt; 0.9',并将'cheapLookup = 1'应用为残差。索引计算列也有可能将cheapLookup作为其第二个键,这将导致纯搜索,没有残差。
关于第二个谓词的另一个问题是,如果没有计算列(无论是否为索引),SQL Server将不得不猜测表达式的选择性。使用计算列,服务器可能能够在表达式 - 结果列上创建统计信息,这将有助于优化程序。请注意,'CAST(someField as FLOAT)/ otherField'上的计算列必须在被索引或在其上创建统计信息之前保留,因为它包含不精确的数据类型。
总之,表达式的复杂性并不像使用优化程序考虑的每种可用访问方法的整个计划的估计成本那么重要。
答案 1 :(得分:6)
SQL是声明性的:你告诉数据库你想要什么,而不是你想要它做什么。数据库可以完全免费评估懒惰或急切。实际上,对于我所知道的,它可以以相反的顺序评估三次:)
在极少数情况下,您可以通过重新构建查询来提高性能,避免特定的昂贵操作。例如,将浮点数学运算移动到单独的查询将强制进行延迟评估:
declare @t table (id int, someField float, otherField float)
insert @t select id, someField, otherField from someTable
where cheaplLookup <> 1
delete @t where (CAST(someField as FLOAT)/otherField) >= 0.9
insert @t select id, someField, otherField from someTable
where cheaplLookup = 1
在您的示例中,我希望SQL Server在没有任何提示或技巧的情况下选择最佳方式。
答案 2 :(得分:2)
这取决于SQL Server如何优化查询,您可以运行查询分析器来查看您的特定情况
优化的确定方法就是说
WITH QueryResult AS (
SELECT
someFields
FROM
someTable
WHERE
cheapLookup=1
)
SELECT * FROM QueryResult WHERE (CAST(someField as FLOAT)/otherField)<0.9
答案 3 :(得分:2)
您所指的是短路,就像其他语言(例如C#)支持一样。
我相信SQL Server 可以短路,但取决于场景/优化器中发生的情况,所以肯定不能保证它会。它只是可能。
Remus Rusanu对此有很好的参考:
http://rusanu.com/2009/09/13/on-sql-server-boolean-operator-short-circuit/