pan*_*nts 8 sql wildcard sql-execution-plan sql-server-2012 sql-like
我希望这两个SELECT
s具有相同的执行计划和性能.由于有一个领先的通配符LIKE
,我希望进行索引扫描.当我运行它并查看计划时,第一个SELECT
按预期运行(使用扫描).但第二个SELECT
计划显示索引搜索,并且运行速度提高了20倍.
码:
-- Uses index scan, as expected:
SELECT 1
FROM AccountAction
WHERE AccountNumber LIKE '%441025586401'
-- Uses index seek somehow, and runs much faster:
declare @empty VARCHAR(30) = ''
SELECT 1
FROM AccountAction
WHERE AccountNumber LIKE '%441025586401' + @empty
Run Code Online (Sandbox Code Playgroud)
题:
当模式以通配符开头时,SQL Server如何使用索引查找?
奖金问题:
为什么连接空字符串会改变/改进执行计划?
细节:
Accounts.AccountNumber
Accounts.AccountNumber
列可以为空varchar(30)
表和索引定义:
CREATE TABLE [updatable].[AccountAction](
[ID] [int] IDENTITY(1,1) NOT NULL,
[AccountNumber] [varchar](30) NULL,
[Utility] [varchar](9) NOT NULL,
[SomeData1] [varchar](10) NOT NULL,
[SomeData2] [varchar](200) NULL,
[SomeData3] [money] NULL,
--...
[Created] [datetime] NULL,
CONSTRAINT [PK_Account] PRIMARY KEY NONCLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_updatable_AccountAction_AccountNumber_UtilityCode_ActionTypeCd] ON [updatable].[AccountAction]
(
[AccountNumber] ASC,
[Utility] ASC
)
INCLUDE ([SomeData1], [SomeData2], [SomeData3]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
CREATE CLUSTERED INDEX [CIX_Account] ON [updatable].[AccountAction]
(
[Created] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)
注意:这是两个查询的实际执行计划.对象的名称与上面的代码略有不同,因为我试图保持简单的问题.
这些测试(数据库AdventureWorks2008R2)显示了会发生什么:
SET NOCOUNT ON;
SET STATISTICS IO ON;
PRINT 'Test #1';
SELECT p.BusinessEntityID, p.LastName
FROM Person.Person p
WHERE p.LastName LIKE '%be%';
PRINT 'Test #2';
DECLARE @Pattern NVARCHAR(50);
SET @Pattern=N'%be%';
SELECT p.BusinessEntityID, p.LastName
FROM Person.Person p
WHERE p.LastName LIKE @Pattern;
SET STATISTICS IO OFF;
SET NOCOUNT OFF;
Run Code Online (Sandbox Code Playgroud)
结果:
Test #1
Table 'Person'. Scan count 1, logical reads 106
Test #2
Table 'Person'. Scan count 1, logical reads 106
Run Code Online (Sandbox Code Playgroud)
结果SET STATISTICS IO
表明LIO是相同的.但执行计划却截然不同:
在第一个测试中,SQL Server使用Index Scan
显式但在第二个测试中SQL Server使用的Index Seek
是一个Index Seek - range scan
.在最后一种情况下,SQL Server使用Compute Scalar
运算符生成这些值
[Expr1005] = Scalar Operator(LikeRangeStart([@Pattern])),
[Expr1006] = Scalar Operator(LikeRangeEnd([@Pattern])),
[Expr1007] = Scalar Operator(LikeRangeInfo([@Pattern]))
Run Code Online (Sandbox Code Playgroud)
并且,Index Seek
运算符使用Seek Predicate
(优化)a range scan
(LastName > LikeRangeStart AND LastName < LikeRangeEnd
)加上另一个unoptimized Predicate
(LastName LIKE @pattern
).
LIKE'%...'如何寻求索引?
我的回答:这不是"真实的" Index Seek
.这是一个Index Seek - range scan
,在这种情况下,有一个像相同的性能Index Scan
.
另请参阅Index Seek
和Index Scan
(类似辩论)之间的区别:
那么......它是一个寻求还是扫描?.
编辑1:执行计划OPTION(RECOMPILE)
(请参阅Aaron的建议)也显示Index Scan
(而不是Index Seek
):
归档时间: |
|
查看次数: |
3534 次 |
最近记录: |