sql – LIKE’%…’如何在索引上寻找?

我希望这两个SELECT具有相同的执行计划和性能.由于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

题:

当模式以通配符开头时,sql Server如何使用索引查找?

奖金问题:

为什么连接空字符串会改变/改进执行计划?

细节:

> Accounts.AccountNumber上有一个非聚集索引
>还有其他索引,但搜索和扫描都在此索引上.
> Accounts.AccountNumber列是可以为空的varchar(30)
>服务器是sql Server 2012

表和索引定义:

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,SORT_IN_TEMPDB = OFF,DROP_EXISTING = OFF,ONLINE = OFF,ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]


CREATE CLUSTERED INDEX [CIX_Account] ON [updatable].[AccountAction]
(
    [Created] ASC
)WITH (PAD_INDEX = OFF,ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

注意:
以下是两个查询的实际执行计划.对象的名称与上面的代码略有不同,因为我试图保持简单的问题.

解决方法

这些测试(数据库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;

结果:

Test #1
Table 'Person'. Scan count 1,logical reads 106
Test #2
Table 'Person'. Scan count 1,logical reads 106

SET STATISTICS IO的结果显示LIO是相同的.
但执行计划完全不同:

在第一个测试中,sql Server使用显式索引扫描,但在第二个测试中,sql Server使用Index Seek,它是一个Index Seek – 范围扫描.在最后一种情况下,sql Server使用Compute Scalar运算符来生成这些值

[Expr1005] = Scalar Operator(LikeRangeStart([@Pattern])),[Expr1006] = Scalar Operator(LikeRangeEnd([@Pattern])),[Expr1007] = Scalar Operator(LikeRangeInfo([@Pattern]))

并且,Index Seek运算符使用Seek Predicate(优化)进行范围扫描(LastName> LikeRangeStart AND LastName< LikeRangeEnd)加上一个未优化的Predicate(LastName LIKE @pattern).

How can LIKE ‘%…’ seek on an index?

我的回答:这不是一个“真正的”索引搜索.这是一个索引搜索范围扫描,在这种情况下,它具有与索引扫描相同的性能.

请参阅Index Seek和Index Scan之间的区别(类似的争论):
So…is it a Seek or a Scan?.

编辑1:OPTION(RECOMPILE)的执行计划(请参阅Aaron的推荐)还显示了索引扫描(而不是索引搜索):

相关文章

SELECT a.*,b.dp_name,c.pa_name,fm_name=(CASE WHEN a.fm_n...
if not exists(select name from syscolumns where name=&am...
select a.*,pano=a.pa_no,b.pa_name,f.dp_name,e.fw_state_n...
要在 SQL Server 2019 中设置定时自动重启,可以使用 Window...
您收到的错误消息表明数据库 &#39;EastRiver&#39; 的...
首先我需要查询出需要使用SQL Server Profiler跟踪的数据库标...