转换为SARGable查询

时间:2018-12-20 11:01:05

标签: sql-server indexing sql-server-2008-r2 query-performance

我想编写查询来搜索表中包含的字符串。

表格:

Create table tbl_sarg
(
    colname varchar(100),
    coladdres varchar(500)
);

注意:我只想使用Index Seek来搜索3亿条记录。

索引:

create nonclustered index ncidx_colname on tbl_sarg(colname);

样本记录:

insert into tbl_sarg values('John A Mak','HNo 102 Street Road Uk');
insert into tbl_sarg values('Shawn A Meben','Church road USA');
insert into tbl_sarg values('Lee Decose','ShopNo 22 K Mark UK');
insert into tbl_sarg values('James Don','A Mall, 90 feet road UAE');

查询1:

select * from tbl_sarg
where colname like '%ee%'

实际执行计划:

enter image description here

查询2:

select * from tbl_sarg
where charindex('ee',colname)>0

实际执行计划:

enter image description here

查询3:

select * from tbl_sarg
where patindex('%ee%',colname)>0

实际执行计划:

enter image description here

如何强制查询处理器对大型数据集使用索引查找代替表/索引扫描?

2 个答案:

答案 0 :(得分:1)

根据定义,您发布的所有查询都不是可SARg的,例如,使用'%..%'会自动强制查询引擎执行扫描,另一种情况是使用函数(例如charindex或patindex)在谓词中的列中。

这里有一些帖子:https://bertwagner.com/2017/08/22/how-to-search-and-destroy-non-sargable-queries-on-your-server/

如果您必须使用通配符执行这种查询,金伯利·特里普(Kimberly Tripp)撰写了很多有趣的文章,也许值得检查一下使用FullTextSearch功能的可能性。我的意思是,或者您要限制并在查询中做一个精确的谓词,否则您将不得不改变策略,几乎忘记了,不要试图将Seek与HINT一起使用,我看不出这种药会比疾病好。

答案 1 :(得分:1)

搜索参数(简称SARG)是一个过滤谓词,可让优化程序依赖 索引顺序。过滤谓词使用以下形式(或带有两个定界符的变体 范围,或操作数位置翻转): <column> <operator> <expression>

如果满足以下条件,则此过滤器可设置

  1. 您不要对已过滤的列进行操作。

  2. 运算符在索引中标识连续范围的合格行。那是 运算符,例如=,>,> =,<,<=,BETWEEN,具有已知前缀的LIKE等。 像<>,以通配符作为前缀的LIKE这样的运算符不是这种情况。

在大多数情况下,将操作应用于过滤后的列时,优化器不会 尝试太聪明,理解计算的含义,以及是否对索引进行排序 仍然可以依靠。它只是假设结果值的排序方式可能与 源值,因此不能信任索引顺序。

那么SQL Server为什么不将索引用于%ee%查询?假装您手里拿着电话簿,我要求您查找姓氏包含字母%ee%的所有人。您将必须扫描电话簿中的每个页面,因为结果将包括以下内容:

  • 李安妮(Anne Lee)

  • 李容

  • 凯瑟琳

  • Alien

    当我要求您提供名称中任何位置包含%ee%的所有姓氏时,我的查询都不可靠-这意味着您无法利用索引进行索引查找。

这就是 SQL Server全文搜索的地方。