什么使SQL语句sargable?

根据定义(至少从我所看到的来看)sargable意味着查询能够让查询引擎优化查询使用的执行计划。我试着查了一下答案,但似乎没有太多关于这个主题的内容。问题是,什么能或不能使SQL查询sargable?任何文件都将非常感谢。

供参考:Sargable

89879 次浏览

不要这样做:

WHERE Field LIKE '%blah%'

这将导致表/索引扫描,因为LIKE值以通配符开始。

不要这样做:

WHERE FUNCTION(Field) = 'BLAH'

这会导致表/索引扫描。

数据库服务器必须对表中的每一行计算FUNCTION(),然后将其与'BLAH'进行比较。

如果可能的话,倒着做:

WHERE Field = INVERSE_FUNCTION('BLAH')

这将对参数运行一次INVERSE_FUNCTION(),并且仍然允许使用索引。

使查询non-sargable最常见的方法是在where子句的函数中包含一个字段:

SELECT ... FROM ...
WHERE Year(myDate) = 2008

SQL优化器不能在myDate上使用索引,即使存在索引。它需要对表中的每一行求值。更好的用法是:

WHERE myDate >= '01-01-2008' AND myDate < '01-01-2009'

其他一些例子:

Bad: Select ... WHERE isNull(FullName,'Ed Jones') = 'Ed Jones'
Fixed: Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))


Bad: Select ... WHERE SUBSTRING(DealerName,4) = 'Ford'
Fixed: Select ... WHERE DealerName Like 'Ford%'


Bad: Select ... WHERE DateDiff(mm,OrderDate,GetDate()) >= 30
Fixed: Select ... WHERE OrderDate < DateAdd(mm,-30,GetDate())

在这个回答中,我假设数据库有足够的覆盖索引。关于这个话题有足够多的问题。

很多时候,查询的sargability是由相关索引的临界点决定的。临界点定义了将一个表或结果集连接到另一个表或结果集时搜索和扫描索引之间的区别。一次查找当然比扫描整个表快得多,但是当必须查找很多行时,扫描可能更有意义。

因此,当优化器期望一个表的结果行数小于下一个表上可能索引的临界点时,SQL语句更sargable。

你可以找到一个详细的帖子和例子在这里

对于一个被认为是sargable的操作,仅仅能够使用现有索引是不够的。在上面的例子中,对where子句中的索引列添加函数调用,仍然很可能会利用已定义的索引。它将“扫描”也就是从该列(索引)中检索所有值,然后消除与提供的过滤器值不匹配的值。对于具有大量行数的表,它仍然不够高效。 真正定义sargability的是使用二叉搜索方法遍历b树索引的查询能力,这种方法依赖于对排序项数组的半集消除。在SQL中,它将在执行计划中显示为“index seek”