問題のクエリに非常に幅広い列のセットがあると仮定します。クエリは次のようになります。
set statistics io,time on;
Select a.Col1, a.Col2, b.Col3, b.Col4, c.Col5
From FirstWideTable a
Join SecondWideTable b on a.Col6=b.Col7
Join ThirdWideTable c on b.Col8=c.Col9
WHERE a.Col10=@SomeVariable;
set statistics io,time off;
上記のクエリでは、100列程度の10列を使用しています(より「選択的な」クエリ)。 SQL Serverが作成したこれらのテーブルとテーブルの統計には、述語(Col10)に対応する有効なインデックスが含まれていますが、ここには表示されていませんが、3つのテーブルにPKが作成されていると想定しています(下のデモを参照)。
CREATE NONCLUSTERED INDEX NC__a_Col1_Col2_Col6
ON FirstWideTable(Col1 ASC,Col2 ASC, Col3 ASC)
INCLUDE (Col10)
ON PRIMARY;
セカンドおよびサードワイドテーブルでは、同様のインデックスを使用できます。
クエリが必要な10列のみのサブクエリとして記述されている場合:
set statistics io,time on;
Select a.Col1, a.Col2, b.Col3, b.Col4, c.Col5
From (SELECT a.Col1, a.Col2,a.Col6,a.Col10 FROM FirstWideTable) a
Join (SELECT b.Col4,b.Col5, b.Col7 FROM SecondWideTable) b on a.Col6=b.Col7
Join (c.Col5, c.Col9 FROM ThirdWideTable) c on b.Col8=c.Col9
WHERE a.Col10=@SomeVariable;
set statistics io,time off;
結果は改善します。統計のある幅の広いテーブルの経過時間は、ひどい(30秒)経過時間を示しています。クエリ(統計に対して実行されていない統計)の実際の列がサブクエリにリストされるたびに、経過時間が大幅に減少します。
クエリ結果-ワイドテーブルには統計があります-ワイドテーブルがベースラインです。サブクエリの結果には統計がありません。タイミングは、ワイドテーブルではなく必要な列のみを調べるサブクエリを追加した後に取得されました。
CPU Time (ms) Elapsed Time (ms)
Wide table result 7265 35459
Subqueried narrow result table 1 5125 31271
Wide table result 6765 33446
Subqueried narrow result table 2 5391 27099
Wide table result 7203 34354
Subqueried narrow result table 3 5843 10321
以下の理論データからの結果:
CPU Time (ms) Elapsed Time (ms)
Wide table result 109 461
Subqueried narrow result table 1 32 441
Wide table result 78 441
Subqueried narrow result table 2 110 453
Wide table result 62 441
Subqueried narrow result table 3 63 458
これが理論的なデータがどのように生成されたかです。/*ダミーのソーステーブルを作成します* /
select * into tblSourceTable from(select top 100000 NewID()A, NewID()B from sys.columns)x
理論的なデータを生成します。
DECLARE @test2 TABLE (
[ID] [bigint] NULL,
[A] [uniqueidentifier] NULL,
[B] [uniqueidentifier] NULL,
[C] [uniqueidentifier] NULL,
[D] [uniqueidentifier] NULL,
[E] [uniqueidentifier] NULL,
[F] [uniqueidentifier] NULL,
[G] [uniqueidentifier] NULL,
[H] [uniqueidentifier] NULL,
[I] [uniqueidentifier] NULL,
[J] [uniqueidentifier] NULL,
[K] [uniqueidentifier] NULL,
[L] [uniqueidentifier] NULL,
[M] [uniqueidentifier] NULL,
[N] [uniqueidentifier] NULL,
[O] [uniqueidentifier] NULL,
[P] [uniqueidentifier] NULL,
[Q] [uniqueidentifier] NULL,
[R] [uniqueidentifier] NULL,
[S] [uniqueidentifier] NULL,
[T] [uniqueidentifier] NULL,
[U] [uniqueidentifier] NULL,
[V] [uniqueidentifier] NULL,
[W] [uniqueidentifier] NULL,
[X] [uniqueidentifier] NULL,
[Y] [uniqueidentifier] NULL,
[Z] [uniqueidentifier] NULL,
[AA] [uniqueidentifier] NULL,
[AB] [uniqueidentifier] NULL,
[AC] [uniqueidentifier] NULL,
[AD] [uniqueidentifier] NULL,
[AE] [uniqueidentifier] NULL,
[AF] [uniqueidentifier] NULL,
[AG] [uniqueidentifier] NULL,
[AH] [uniqueidentifier] NULL,
[AI] [uniqueidentifier] NULL,
[AJ] [uniqueidentifier] NULL,
[AK] [uniqueidentifier] NULL,
[AL] [uniqueidentifier] NULL,
[AM] [uniqueidentifier] NULL,
[AN] [uniqueidentifier] NULL,
[AO] [uniqueidentifier] NULL,
[AP] [uniqueidentifier] NULL,
[AQ] [uniqueidentifier] NULL,
[AR] [uniqueidentifier] NULL
)
ダミーデータセットを作成する
insert into @test2
select Top 50000 ID=ROW_NUMBER()over(order by C.A),
NewID() AS A,NewID() AS B,NewID() AS C,NewID() AS D,NewID() AS E,NewID() AS F,
NewID() AS G,NewID() AS H,NewID() AS I,NewID() AS J,NewID() AS K,NewID() AS L,
NewID() AS M,NewID() AS N,NewID() AS O,NewID() AS P,NewID() AS Q,NewID() AS R,
NewID() as S,NewID() AS T,NewID() AS U,NewID() AS V,NewID() AS W,NewID() AS X,
NewID() AS Y,NewID() AS Z,NewID() AS AA,NewID() AS AB,NewID() AS AC,NewID() AS AD,
NewID() AS AE,NewID() AS AF,NewID() AS AG,NewID() AS AH,NewID() AS AI,NewID() AS AJ,
NewID() AS AK,NewID() AS AL,NewID() AS AM,NewID() AS AN,NewID() AS AO,NewID() AS AP,
NewID() AS AQ,NewID() AS AR
FROM test C
cross apply test D
cross apply test E
cross apply test F
cross apply test G
cross apply test H
cross apply test I
cross apply test J
cross apply test K
cross apply test L
cross apply test M
cross apply test N
cross apply test O
cross apply test P
cross apply test Q
cross apply test R
cross apply test S
cross apply test T
cross apply test U
cross apply test V
cross apply test W
cross apply test X
cross apply test Y
cross apply test Z
テーブルを作成します。
Select * into [FirstWideTable] FROM @test2
Select * into [SecondWideTable] FROM @test2
Select * into [ThirdWideTable] FROM @test2
CREATE UNIQUE CLUSTERED INDEX [PK_TEST_A_ID] ON [dbo].[FirstWideTable]([ID] ASC)
CREATE UNIQUE CLUSTERED INDEX [PK_TEST_B_ID] ON [dbo].[SecondWideTable]([ID] ASC)
CREATE UNIQUE CLUSTERED INDEX [PK_TEST_C_ID] ON [dbo].[ThirdWideTable]([ID] ASC)
クエリを数回実行して、統計データを作成できるようにします
Select a.ID, a.A, a.AB, b.A, b.B, b.C, b.D, c.A, C.B, c.D, c.AA
From [FirstWideTable] a
LEFT Join [SecondWideTable] b on a.ID=b.ID
LEFT Join [ThirdWideTable] c on b.ID=c.ID
WHERE a.ID BETWEEN 1 and 50000;
Select a.ID, a.A, a.AB, b.A, b.B, b.C, b.D, c.A, C.B, c.D, c.AA
From [FirstWideTable] a
LEFT Join [SecondWideTable] b on a.ID=b.ID
LEFT Join [ThirdWideTable] c on b.ID=c.ID
WHERE a.ID BETWEEN 1 and 50000;
Select a.ID, a.A, a.AB, b.A, b.B, b.C, b.D, c.A, C.B, c.D, c.AA
From [FirstWideTable] a
LEFT Join [SecondWideTable] b on a.ID=b.ID
LEFT Join [ThirdWideTable] c on b.ID=c.ID
WHERE a.ID BETWEEN 1 and 50000;
統計を作成する
update statistics [FirstWideTable]
update statistics [SecondWideTable]
update statistics [ThirdWideTable]
結果をつかむ
set statistics io,time on
Select a.ID, a.A, a.AB, b.A, b.B, b.C, b.D, c.A, C.B, c.D, c.AA
From (Select ID, A, AB from [FirstWideTable]) a
LEFT Join(Select ID, A, B, C, D from[SecondWideTable]) b on a.ID=b.ID
LEFT Join(Select ID, A, B, D, AA from[ThirdWideTable]) c on b.ID=c.ID
WHERE a.ID BETWEEN 1 and 50000;
set statistics io,time off
set statistics io,time on
Select a.ID, a.A, a.AB, b.A, b.B, b.C, b.D, c.A, C.B, c.D, c.AA
From [FirstWideTable] a
LEFT Join [SecondWideTable] b on a.ID=b.ID
LEFT Join [ThirdWideTable] c on b.ID=c.ID
WHERE a.ID BETWEEN 1 and 50000;
set statistics time io,off
特に統計が古くなっている場合は、経過時間の改善が必ずしも見られない場合でも、CPU時間は計画間で大幅に異なる場合があります。 CPU時間と経過時間の関係を説明する短い回答 here を書きました。
UPDATE STATISTICS
影響を受けるテーブルのT-SQLコマンド。