Sql 像“%”这样的函数如何在索引上查找?

Sql 像“%”这样的函数如何在索引上查找?,sql,sql-server-2012,wildcard,sql-execution-plan,sql-like,Sql,Sql Server 2012,Wildcard,Sql Execution Plan,Sql Like,我希望这两个选择具有相同的执行计划和性能。因为有一个前导通配符,所以我希望进行索引扫描。当我运行此程序并查看计划时,第一次选择的行为与预期的扫描一样。但是第二个SELECT计划显示一个索引搜索,运行速度快20倍 代码: 问题: 当模式以通配符开头时,SQL Server如何使用索引查找 奖金问题: 为什么连接空字符串会改变/改进执行计划 详情: Accounts.AccountNumber上存在非聚集索引 还有其他索引,但搜索和扫描都在此索引上。 Accounts.AccountNumber列是

我希望这两个选择具有相同的执行计划和性能。因为有一个前导通配符,所以我希望进行索引扫描。当我运行此程序并查看计划时,第一次选择的行为与预期的扫描一样。但是第二个SELECT计划显示一个索引搜索,运行速度快20倍

代码:

问题:

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

奖金问题:

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

详情:

Accounts.AccountNumber上存在非聚集索引 还有其他索引,但搜索和扫描都在此索引上。 Accounts.AccountNumber列是可为空的varchar30 服务器是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, 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]
注: 下面是这两个查询的实际执行计划。对象的名称与上面的代码略有不同,因为我试图使问题保持简单


这些测试数据库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
集合统计IO的结果表明LIO是相同的。 但执行计划却大不相同:

在第一个测试中,SQL Server使用显式索引扫描,但在第二个测试中,SQL Server使用索引查找,这是索引查找范围扫描。在最后一种情况下,SQL Server使用计算标量运算符生成这些值

[Expr1005] = Scalar Operator(LikeRangeStart([@Pattern])), 
[Expr1006] = Scalar Operator(LikeRangeEnd([@Pattern])), 
[Expr1007] = Scalar Operator(LikeRangeInfo([@Pattern]))
并且,Index Seek操作符使用一个为范围扫描LastName>LikeRangeStart和LastName 像“%”这样的函数如何在索引上查找

我的回答是:这不是一个真正的索引搜索。这是一个索引搜索范围扫描,在本例中,它具有与索引扫描相同的性能

另请参见索引搜索和索引扫描之间的区别类似的争论:

编辑1:OPTIONRECOMPILE的执行计划请参见Aaron的建议,同时显示索引扫描,而不是索引搜索:

实际执行情况是否存在差异,还是仅在估算计划中存在差异?@GordonLinoff SQL Server 2012的版本号为11,2008 R2:10.5,2008:10,等等。可能是参数嗅探,估算计划可能没有意识到该搜索实际上有多糟糕。如果在查询中使用“重新编译”选项或清除计划缓存,会发生什么情况?另外,请确保测量设置统计时间;并设置统计IO;这样您就可以看到搜索或扫描实际上是否更好。不要仅仅依靠96%和4%的数字来显示实际表现——这些数字本身基本上毫无意义。我的直觉是,在你试图混淆的过程中,你遗漏了一些重要的细节,这些细节将说明你为什么会被搜索。
[Expr1005] = Scalar Operator(LikeRangeStart([@Pattern])), 
[Expr1006] = Scalar Operator(LikeRangeEnd([@Pattern])), 
[Expr1007] = Scalar Operator(LikeRangeInfo([@Pattern]))