2

以下是设置和测试脚本。测试脚本假设只扫描表 T4。但是,当 T1 和 T4 的行数超过 10000 时,它会开始扫描这两个表。

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中的良好执行计划:

https://docs.google.com/file/d/0B6OXmuJYfpRcTE9Pd0xpSEhEQy04eWZqa2lKejM5YkdPRHFr/edit?usp=docslist_api

xml 中的错误执行计划: https ://docs.google.com/file/d/0B6OXmuJYfpRcU2ZUVFdtLUcxQk83TVFSNUFoZEYtbVdaWU4w/edit?usp=docslist_api

4

1 回答 1

0

您预计不会扫描 T1,因为视图已分区。但是,表变量导致扫描。从表变量中选择的语句与创建表变量并将值插入表变量的语句分开解析——因此优化器不知道这些值。

如果您使用文字值而不是 (SELECT * FROM @a),它将不会引用 T1,而只会扫描 T4。不过,奇怪的是,这样做的成本更高,性能更差。

探索使用包含列在 DateY 上创建索引以优化性能。

于 2014-09-09T01:09:40.010 回答