SQL Server 用户使用术语“sargable”。我想知道“sargable”是否有一个客观的、与实现无关的永恒定义。
例如,WHERE foo LIKE '%bar%'很多人说它是不可 sargable 的,但一些 RDBMS能够在此类查询上使用索引。那么“不可以”是什么意思呢?
其他参考
mus*_*cio 47
“sargable”一词最早由 P. Griffiths Selinger 等人提出。在他们 1979 年由 ACM 发表的论文“关系数据库管理系统中的访问路径选择”中。对于非 ACM 成员,该论文的副本位于http://cs.stanford.edu/people/chrismre/cs345/rl/selinger.pdf
该术语在本段中定义:
索引和段1扫描都可以选择采用一组谓词,称为搜索参数(或 SARGS),在元组返回到 RSI 2调用方之前将其应用于元组。如果元组满足谓词,则返回;否则,扫描将继续,直到找到满足 SARGS 的元组或用尽该段或指定的索引值范围。这通过消除对可以在 RSS 中被有效拒绝的元组进行 RSI 调用的开销来降低成本。并非所有谓词都具有可以成为 SARGS 的形式。阿可优化搜索谓词是形式中的一个(或它可以被放入表格)“列比较运算符值”。SARGS 以析取范式表示为此类谓词的布尔表达式。
换句话说,sargable 谓词可以由存储引擎(访问方法)通过直接观察表或索引记录来解析。相反,不可 sargable 谓词需要更高级别的 DBMS 才能采取行动。例如,WHERE lastname = 'Doe'存储引擎可以通过简单地查看lastname每条记录的字段内容来决定结果。另一方面,WHERE UPPER(lastname) = 'DOE'需要 SQL 引擎执行一个函数,这意味着存储引擎必须将它读取的所有行(前提是它们与可能的其他可判断谓词匹配)返回给 SQL 引擎进行评估,从而产生额外的 CPU 成本.
从最初的定义可以看出,sargable predicates 不仅可以应用于索引扫描,还可以应用于表(System R 术语中的段)扫描,只要满足“列比较-运算符值”条件,因此它们可以由存储引擎评估。Db2 确实是这种情况,它是系统 R在许多方面的后代:
索引 sargable 谓词不用于括起搜索,但如果选择了索引,则从索引评估,因为谓词中涉及的列是索引键的一部分。这些谓词也由索引管理器评估。
数据 sargable 谓词是不能由索引管理器评估但可以由数据管理服务 (DMS) 评估的谓词。通常,这些谓词需要访问基表中的各个行。如有必要,DMS 将检索评估谓词所需的列,
事实上,在 SQL Server 中,sargable 谓词只是那些可以使用索引查找解析的谓词,这可能是由其存储引擎无法在表扫描期间应用此类谓词决定的。
Sargable 和非 sargable 谓词有时分别被描述为“阶段 1”和“阶段 2”谓词(这也来自Db2 术语)。在读取表或索引记录时,可以在查询处理的最低级别评估阶段 1 谓词。与第 1 阶段条件匹配的行(如果有)被发送到评估的下一个级别,即第 2 阶段。
1 -- System R 中的 Segment 是表元组的物理存储;段扫描在某种程度上相当于其他 DBMS 中的表扫描。
2 -- RSI -- RSS 3 Interface,一个面向元组的查询接口。与本次讨论相关的接口函数是 NEXT,它返回匹配查询谓词的下一行。
3 -- RSS,或研究存储系统,系统 R 的存储子系统。
Bre*_*zar 22
对我来说,SARGable 意味着 SQL Server 可以使用您的搜索谓词执行索引查找。
您不能只说 DBMS 可以“利用”索引,因为对于不可 sargable 谓词,SQL Server 最终可能会扫描非聚集索引。
Vic*_*ork 12
根据Dmitri Korotkevitch 的Pro SQL Server Internals的说法:
如果存在索引,则搜索参数 ABLE 谓词是 SQL SERVER 可以利用索引查找操作的谓词。
SARGable 谓词是 SQL Server 可以隔离要处理的单个值或索引键值范围的谓词
SARGable 谓词包括以下运算符:
=,>,>=,<,<=,IN,BETWEEN, andLIKE(在前缀匹配的情况下)非可优化搜索操作符包括:
NOT,NOT IN,<>,和LIKE(不前缀匹配),以及使用功能或计算对表,和类型转换,其中的数据类型不符合所创建的索引。
示例:
WHERE name like 'SARGable%'
WHERE name like '%non-SARGable%'
Run Code Online (Sandbox Code Playgroud)
演示:
DROP TABLE dbo.Testing;
GO
CREATE TABLE Testing (
WeirdDatatype int NOT NULL,
SomethingElse char(200)
);
CREATE NONCLUSTERED INDEX IDX_ALWAYS_SARGable
ON dbo.Testing( SomethingElse);
CREATE NONCLUSTERED INDEX IDX_NOT_ALWAYS_SARGable
ON dbo.Testing(SomethingElse);
INSERT INTO dbo.Testing
( WeirdDatatype, SomethingElse )
SELECT TOP 1000 m.message_id, CONVERT(char(200), m.text)
FROM sys.messages AS m;
Run Code Online (Sandbox Code Playgroud)
现在我们运行:
SELECT *
FROM dbo.Testing AS t
WHERE t.WeirdDatatype = 1001;
SELECT *
FROM dbo.Testing AS t
WHERE t.SomethingElse LIKE 'Line%'
SELECT *
FROM dbo.Testing AS t
WHERE t.SomethingElse LIKE '%Line%'
AND t.WeirdDatatype = 1001;
Run Code Online (Sandbox Code Playgroud)
结果是:
我们来看看SARGable查询的属性(Index Seek)
查询优化器能够在开始和结束的索引中定义限制。它有一个用于查询的搜索参数。
现在是非 SARGable 查询:
您可以看到谓词 '%non..%' 的开头不允许查询优化器在索引中定义开始和结束或范围。它现在必须搜索整个表(扫描)。