转换为 SARGable 查询

Convert to SARGable query

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

Table:

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%'

实际执行计划:

查询 2:

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

实际执行计划:

查询 3:

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

实际执行计划:

如何强制查询处理器使用索引查找而不是table/index扫描大型数据集?

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

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

Kimberly Tripp 写了非常有趣的文章,如果您必须使用通配符执行这种查询,也许值得检查一下使用 FullTextSearch 功能的可能性。我的观点是,或者你的限制并在你的查询中做一个精确的谓词,否则你将不得不改变策略,几乎忘记了,不要试图强制使用带提示的 Seek,我看不出这种药会总比生病好

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

这样的过滤器是 sargable 如果:

  1. 您没有对筛选的列应用操作。

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

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

那么为什么 SQL 服务器不为 %ee% 查询使用索引?假装你手里拿着一本 phone 书,我要你找出所有姓氏中包含字母 %ee% 的人。您必须扫描 phone 书中的每一页,因为结果将包括以下内容:

  • 李安妮

  • 李容

  • 凯瑟琳

  • 艾琳

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

这就是 SQL 服务器全文搜索 的用武之地。