以下は、セットアップとテストのスクリプトです。テスト スクリプトは、テーブル T4 のみをスキャンすることを想定しています。ただし、10000 行を超えると、テーブル T1 と T4 の両方のスキャンが開始されます。
create table T1 (A varchar(5) check ((A='S4' or A='S3' or A='S2' or A='S1' or A='FS' or A='FM' or A='FBL' or A='ES' or A='EBL' or A='BL'))
,DateX date
,id char(6)
,DateY date
,primary key clustered (A, DateX, id))
create table T4 (A varchar(5) check ((A='S1780' OR A='C1780' OR A='B1780'))
,DateX date
,id char(6)
,DateY date
,primary key clustered (A, DateX, id));
-- Insert some values
go
create view dbo.tall
as
select * from dbo.T1
union all
select * from dbo.T4
テストコード:
declare @A table (A varchar(5) primary key (A));
insert @A
values ('S1780'), ('C1780'), ('B1780');
with a as (select *
from tall
where A in (select *
from @A)
),
sd
as (select A, max(DateY) DateY
from a
group by A
),
filter24m
-- Un-comment the lines in this CTE will make the scanning T1 occur with even less row count
as (select id, a.A --, sd.DateY
from a
join sd on a.A = sd.A
--where DateX between dateadd(mm, 1, sd.DateY) and dateadd(mm, 24 + 1, sd.DateY) --
--group by id, a.A, sd.DateY
--having count(*) = 24
)
--
select *
from filter24m
不適切な実行 (T1 に 100 行、T4 に 10000 行がある場合のテスト):
テーブル「T4」。スキャン カウント 2、論理読み取り 80、物理読み取り 0、先読み読み取り 0、LOB 論理読み取り 0、LOB 物理読み取り 0、LOB 先読み読み取り 0。 テーブル「#1B3A42B1」。スキャン カウント 1、論理読み取り 6、物理読み取り 0、先読み読み取り 0、LOB 論理読み取り 0、LOB 物理読み取り 0、LOB 先読み読み取り 0。 テーブル「ワークテーブル」。スキャン カウント 0、論理読み取り 0、物理読み取り 0、先読み読み取り 0、LOB 論理読み取り 0、LOB 物理読み取り 0、LOB 先読み読み取り 0。 テーブル「ワークテーブル」。スキャン カウント 0、論理読み取り 0、物理読み取り 0、先読み読み取り 0、LOB 論理読み取り 0、LOB 物理読み取り 0、LOB 先読み読み取り 0。 テーブル「T1」。スキャン カウント 3、論理読み取り 6、物理読み取り 0、先読み読み取り 0、LOB 論理読み取り 0、LOB 物理読み取り 0、LOB 先読み読み取り 0。
|--Concatenation
|--Nested Loops(Inner Join, OUTER REFERENCES:([workdb].[dbo].[T1].[A]))
| |--Nested Loops(Inner Join, OUTER REFERENCES:([A]))
| | |--Clustered Index Seek(OBJECT:(@A), SEEK:([A] >= 'B1780' AND [A] <= 'S4') ORDERED FORWARD)
| | |--Stream Aggregate(DEFINE:([workdb].[dbo].[T1].[A]=ANY([workdb].[dbo].[T1].[A])))
| | |--Nested Loops(Inner Join, OUTER REFERENCES:([workdb].[dbo].[T1].[A]))
| | |--Stream Aggregate(DEFINE:([workdb].[dbo].[T1].[A]=ANY([workdb].[dbo].[T1].[A])))
| | | |--Clustered Index Seek(OBJECT:([workdb].[dbo].[T1].[PK__T1__EE1DD21123AC6823]), SEEK:([workdb].[dbo].[T1].[A]=[A]) ORDERED FORWARD)
| | |--Clustered Index Seek(OBJECT:(@A), SEEK:([A]=[workdb].[dbo].[T1].[A]), WHERE:([A]>='B1780' AND [A]<='S4') ORDERED FORWARD)
| |--Clustered Index Seek(OBJECT:([workdb].[dbo].[T1].[PK__T1__EE1DD21123AC6823]), SEEK:([workdb].[dbo].[T1].[A]=[workdb].[dbo].[T1].[A]) ORDERED FORWARD)
|--Merge Join(Inner Join, MERGE:([workdb].[dbo].[T4].[A])=([workdb].[dbo].[T4].[A]), RESIDUAL:([workdb].[dbo].[T4].[A]=[workdb].[dbo].[T4].[A]))
|--Nested Loops(Inner Join, OUTER REFERENCES:([workdb].[dbo].[T4].[A]))
| |--Nested Loops(Inner Join, OUTER REFERENCES:([workdb].[dbo].[T4].[A]))
| | |--Stream Aggregate(GROUP BY:([workdb].[dbo].[T4].[A]))
| | | |--Clustered Index Scan(OBJECT:([workdb].[dbo].[T4].[PK__T4__EE1DD21128711D40]), ORDERED FORWARD)
| | |--Clustered Index Seek(OBJECT:(@A), SEEK:([A]=[workdb].[dbo].[T4].[A]), WHERE:([A]>='B1780' AND [A]<='S4') ORDERED FORWARD)
| |--Clustered Index Seek(OBJECT:(@A), SEEK:([A]=[workdb].[dbo].[T4].[A]), WHERE:([A]>='B1780' AND [A]<='S4') ORDERED FORWARD)
|--Clustered Index Scan(OBJECT:([workdb].[dbo].[T4].[PK__T4__EE1DD21128711D40]), ORDERED FORWARD)
良い (両方のテーブルに 100 行しかない場合のテスト):
テーブル「#1DE1A532」。スキャン カウント 101、論理読み取り 202、物理読み取り 0、先読み読み取り 0、LOB 論理読み取り 0、LOB 物理読み取り 0、LOB 先読み読み取り 0。 テーブル「ワークテーブル」。スキャン カウント 0、論理読み取り 0、物理読み取り 0、先読み読み取り 0、LOB 論理読み取り 0、LOB 物理読み取り 0、LOB 先読み読み取り 0。 テーブル「T4」。スキャン カウント 103、論理読み取り 206、物理読み取り 0、先読み読み取り 0、LOB 論理読み取り 0、LOB 物理読み取り 0、LOB 先読み読み取り 0。
|--Nested Loops(Inner Join, OUTER REFERENCES:([Union1006]))
|--Nested Loops(Inner Join, OUTER REFERENCES:([A]))
| |--Clustered Index Seek(OBJECT:(@A), SEEK:([A] >= 'B1780' AND [A] <= 'S4') ORDERED FORWARD)
| |--Concatenation
| |--Filter(WHERE:(STARTUP EXPR([A]='BL' OR [A]='EBL' OR [A]='ES' OR [A]='FBL' OR [A]='FM' OR [A]='FS' OR [A]='S1' OR [A]='S2' OR [A]='S3' OR [A]='S4')))
| | |--Clustered Index Seek(OBJECT:([workdb].[dbo].[T1].[PK__T1__EE1DD21123AC6823]), SEEK:([workdb].[dbo].[T1].[A]=[A]) ORDERED FORWARD)
| |--Filter(WHERE:(STARTUP EXPR([A]='B1780' OR [A]='C1780' OR [A]='S1780')))
| |--Clustered Index Seek(OBJECT:([workdb].[dbo].[T4].[PK__T4__EE1DD21128711D40]), SEEK:([workdb].[dbo].[T4].[A]=[A]) ORDERED FORWARD)
|--Top(TOP EXPRESSION:((1)))
|--Nested Loops(Inner Join, WHERE:([Union1019]=[A]))
|--Concatenation
| |--Filter(WHERE:(STARTUP EXPR([Union1006]='B1780' OR [Union1006]='C1780' OR [Union1006]='S1780')))
| | |--Clustered Index Seek(OBJECT:([workdb].[dbo].[T4].[PK__T4__EE1DD21128711D40]), SEEK:([workdb].[dbo].[T4].[A]=[Union1006]) ORDERED FORWARD)
| |--Filter(WHERE:(STARTUP EXPR([Union1006]='BL' OR [Union1006]='EBL' OR [Union1006]='ES' OR [Union1006]='FBL' OR [Union1006]='FM' OR [Union1006]='FS' OR [Union1006]='S1' OR [Union1006]='S2' OR [Union1006]='S3' OR [Union1006]='S4')))
| |--Clustered Index Seek(OBJECT:([workdb].[dbo].[T1].[PK__T1__EE1DD21123AC6823]), SEEK:([workdb].[dbo].[T1].[A]=[Union1006]) ORDERED FORWARD)
|--Clustered Index Seek(OBJECT:(@A), SEEK:([A] >= 'B1780' AND [A] <= 'S4') ORDERED FORWARD)
xml での適切な実行計画:
xml の不適切な実行計画: https://docs.google.com/file/d/0B6OXmuJYfpRcU2ZUVFdtLUcxQk83TVFSNUFoZEYtbVdaWU4w/edit?usp=docslist_api