gpt4 book ai didi

sql - LIKE '%...'如何寻找索引?

转载 作者:行者123 更新时间:2023-12-04 04:05:46 25 4
gpt4 key购买 nike

我希望这两个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, 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
    SET STATISTICS IO的结果表明LIO与相同。
    但是执行计划却大不相同:

    在第一个测试中,SQL Server使用显式的 Index Scan,但是在第二个测试中,SQL Server使用一个 Index SeekIndex Seek - range scan。在最后一种情况下,SQL Server使用 Compute Scalar运算符生成这些值
    [Expr1005] = Scalar Operator(LikeRangeStart([@Pattern])), 
    [Expr1006] = Scalar Operator(LikeRangeEnd([@Pattern])),
    [Expr1007] = Scalar Operator(LikeRangeInfo([@Pattern]))

    并且, Index Seek运算符对 Seek Predicate( range scan)加上另一个未优化的 LastName > LikeRangeStart AND LastName < LikeRangeEnd( Predicate)使用 LastName LIKE @pattern(已优化)。

    How can LIKE '%...' seek on an index?



    我的回答:这不是“真实的” Index Seek。这是一个Index Seek - range scan,在这种情况下,其性能与Index Scan相同。

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

    编辑1: OPTION(RECOMPILE)的执行计划(请参见Aaron的建议)还显示了 Index Scan(而不是 Index Seek):

    关于sql - LIKE '%...'如何寻找索引?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18065994/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com