转换为 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 如果:
您没有对筛选的列应用操作。
运算符在索引中标识连续范围的合格行。那就是
带有 =、>、>=、<、<=、BETWEEN、带有已知前缀的 LIKE 等运算符的情况。
像 <> 这样的运算符不是这种情况,LIKE 带有通配符作为前缀。
在大多数情况下,当您对过滤列应用操作时,优化器不会
尝试太聪明并理解计算的含义,如果索引排序
仍然可以依靠。它只是假设结果值的排序方式可能与
源值,因此无法信任索引排序。
那么为什么 SQL 服务器不为 %ee%
查询使用索引?假装你手里拿着一本 phone 书,我要你找出所有姓氏中包含字母 %ee% 的人。您必须扫描 phone 书中的每一页,因为结果将包括以下内容:
李安妮
李容
凯瑟琳
艾琳
当我要求您提供姓名中任何位置包含 %ee%
的所有姓氏时,我的查询是不可搜索的——这意味着,您无法利用索引进行索引查找。
这就是 SQL 服务器全文搜索 的用武之地。
我想编写一个查询来搜索 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 如果:
您没有对筛选的列应用操作。
运算符在索引中标识连续范围的合格行。那就是 带有 =、>、>=、<、<=、BETWEEN、带有已知前缀的 LIKE 等运算符的情况。 像 <> 这样的运算符不是这种情况,LIKE 带有通配符作为前缀。
在大多数情况下,当您对过滤列应用操作时,优化器不会 尝试太聪明并理解计算的含义,如果索引排序 仍然可以依靠。它只是假设结果值的排序方式可能与 源值,因此无法信任索引排序。
那么为什么 SQL 服务器不为 %ee%
查询使用索引?假装你手里拿着一本 phone 书,我要你找出所有姓氏中包含字母 %ee% 的人。您必须扫描 phone 书中的每一页,因为结果将包括以下内容:
李安妮
李容
凯瑟琳
艾琳
当我要求您提供姓名中任何位置包含
%ee%
的所有姓氏时,我的查询是不可搜索的——这意味着,您无法利用索引进行索引查找。
这就是 SQL 服务器全文搜索 的用武之地。