2013-08-05 6 views
8

私はこれらの2つが同じ実行計画とパフォーマンスを持つことを期待しています。 LIKEには先頭にワイルドカードがあるので、インデックススキャンが必要です。これを実行して計画を見ると、最初のSELECTは期待通りに(スキャンで)動作します。しかし、第2の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列がNULL可能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] 
    

    注: ここのため実際実行計画があります2つのクエリ。質問を簡単にするために、オブジェクトの名前は上のコードと少し異なります。

    The two execution plans.

  • +1

    は、実際の実行中にのみ推定計画に差がありますか? –

    +3

    @GordonLinoff SQL Server 2012のバージョン番号は11、2008 R2:10.5、2008:10など – swasheck

    +0

    重要なことはわかりませんが、実際に実行したクエリは「LIKE '%441025586401% 、ワイルドカードで始まり、終わりに – Lamak

    答えて

    7

    これらの試験(データベース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が同じであることを示しています。 しかし、実行計画はかなり異なっている:最初のテストで enter image description here

    、SQL Serverは、明示的なIndex Scanを使用していますが、第二のテストSQL ServerでIndex Seek - range scanあるIndex Seekを使用しています。最後のケースではSQL Serverは、これらの値

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

    と、Index Seekオペレータを生成するCompute Scalar演算子を使用range scanLastName > LikeRangeStart AND LastName < LikeRangeEnd)プラス(LastName LIKE @patternPredicate別の最適化されていないため(最適化)Seek Predicateを使用します。

    「%...」を使ってインデックスを検索する方法はありますか?

    私の答え:「実際の」Index Seekではありません。この場合、Index Scanのような同じパフォーマンスを持つIndex Seek - range scanです。

    参照してください、また、Index SeekIndex Scanの差(同様の議論): So…is it a Seek or a Scan?

    編集1:OPTION(RECOMPILE)(アーロンの勧告をしてください参照)ショーのための実行計画、(代わりにIndex Seekの)も、Index Scanenter image description here

    関連する問題