为什么SQL Server Optimizer不使用检查约束定义来查找包含行的表?

为什么SQL Server Optimizer不使用检查约束定义来查找包含行的表?,sql,sql-server,sql-server-2012,sql-view,Sql,Sql Server,Sql Server 2012,Sql View,我使用SQL Server 2012,我有一个很大的表,我将我的表分为以下几个表: Create Table A2013 ( Id int identity(1,1), CountA int , Name varchar(50), ADate DATETIME NULL CHECK (DATEPART(yy, ADate) = 2013) ) Create Table A2014 ( Id int identity(1,1), Cou

我使用SQL Server 2012,我有一个很大的表,我将我的表分为以下几个表:

Create Table A2013
(
    Id int identity(1,1),
    CountA int ,
    Name varchar(50),
    ADate DATETIME NULL
      CHECK (DATEPART(yy, ADate) = 2013)
)

Create Table A2014
(
    Id int identity(1,1),
    CountA int ,
    Name varchar(50),
    ADate DATETIME NULL
      CHECK (DATEPART(yy, ADate) = 2014)
)

Insert Into A2013 Values ( 102 , 'A','20131011' )
Insert Into A2013 Values (15 , 'B' ,'20130211' )
Insert Into A2013 Values ( 54, 'C' ,'20131211' )
Insert Into A2013 Values ( 54, 'D' ,'20130611' )
Insert Into A2013 Values ( 95, 'E' ,'20130711' )
Insert Into A2013 Values (8754 , 'F' ,'20130310' )

Insert Into A2014 Values ( 102 , 'A','20141011'  )
Insert Into A2014 Values (15 , 'B' ,'20140911' )
Insert Into A2014 Values ( 54, 'C' ,'20140711' )
Insert Into A2014 Values ( 54, 'D' ,'20141007' )
Insert Into A2014 Values ( 95, 'E' ,'20140411' )
Insert Into A2014 Values (8754 , 'F' ,'20140611' ) 
我创建了一个分区视图,如下所示:

Create View A 
As
    Select * From A2013
    Union 
    Select * From A2014
我希望
SQL Optimizer
使用一个好的计划,并使用我的检查约束定义来确定哪个成员表包含行,但在运行此查询时它会扫描两个表:

Select * From A Where A.ADate = '20140611'


我希望SQL Optimizer不会使用table
A2013

检查约束表达式必须正确,以便优化器消除执行计划中不需要的表。以下约束避免将函数应用于列,并且是可修改的:

CREATE TABLE dbo.A2013
    (
      Id int IDENTITY(1, 1)
    , CountA int
    , Name varchar(50)
    , ADate datetime NULL
      CONSTRAINT CK_A2013_ADate
                     CHECK ( ADate >= '20130101'
                             AND ADate < '20140101' )
    );

CREATE TABLE dbo.A2014
    (
      Id int IDENTITY(1, 1)
    , CountA int
    , Name varchar(50)
    , ADate datetime NULL
      CONSTRAINT CK_A2014_ADate
                     CHECK ( ADate >= '20140101'
                             AND ADate < '20150101' )
    );
创建表dbo.A2013
(
Id int标识(1,1)
,CountA int
,姓名varchar(50)
,ADate datetime NULL
约束CK_A2013_ADate
检查(日期>='20130101'
和ADate<'20140101')
);
创建表dbo.A2014
(
Id int标识(1,1)
,CountA int
,姓名varchar(50)
,ADate datetime NULL
约束CK_A2014_ADate
检查(日期>='20140101'
和ADate<'20150101')
);

检查约束表达式必须正确,以便优化器消除执行计划中不需要的表。以下约束避免将函数应用于列,并且是可修改的:

CREATE TABLE dbo.A2013
    (
      Id int IDENTITY(1, 1)
    , CountA int
    , Name varchar(50)
    , ADate datetime NULL
      CONSTRAINT CK_A2013_ADate
                     CHECK ( ADate >= '20130101'
                             AND ADate < '20140101' )
    );

CREATE TABLE dbo.A2014
    (
      Id int IDENTITY(1, 1)
    , CountA int
    , Name varchar(50)
    , ADate datetime NULL
      CONSTRAINT CK_A2014_ADate
                     CHECK ( ADate >= '20140101'
                             AND ADate < '20150101' )
    );
创建表dbo.A2013
(
Id int标识(1,1)
,CountA int
,姓名varchar(50)
,ADate datetime NULL
约束CK_A2013_ADate
检查(日期>='20130101'
和ADate<'20140101')
);
创建表dbo.A2014
(
Id int标识(1,1)
,CountA int
,姓名varchar(50)
,ADate datetime NULL
约束CK_A2014_ADate
检查(日期>='20140101'
和ADate<'20150101')
);
问题不在于表达式是否可搜索。据我所知,术语“sargable”适用于查询中索引的使用。问题是SQL Server是否将
where
子句识别为与
check
约束匹配

您拥有的检查约束是:

CHECK (DATEPART(yy, ADate) = 2014)
其中
子句为:

Where A.ADate = '20140611'
问题在于,第二个未被识别为第一个的子集。您可以通过添加冗余来解决此问题:

Where A.ADate = '20140611' and DATEPART(yy, A.ADate) = 2014
或者,您可以通过使用范围来解决这个问题——但是要小心数据类型,因为数据类型转换肯定会混淆优化器。我认为以下措施会奏效:

CHECK ADate BETWEEN '2014-01-01' and '2014-12-31'
WHERE A.ADate = '2014-06-11'
(连字符是可选的,可以删除。)

(据我所知)原因并不明确:

SQL Server查询优化器可识别中的搜索条件 此SELECT语句仅引用1998年5月销售和销售记录中的行 1998年6月销售表。因此,它将搜索限制在这些表上

分区视图返回时不需要检查约束 正确的结果。但是,如果尚未设置检查约束 定义后,查询优化器必须搜索所有表,而不是 仅包含分区列上的搜索条件。 在没有检查约束的情况下,视图的操作与任何其他视图一样 和所有人一起。查询优化器无法对 存储在不同表中的值,不能跳过搜索 参与视图定义的表

问题不在于表达式是否可搜索。据我所知,术语“sargable”适用于查询中索引的使用。问题是SQL Server是否将
where
子句识别为与
check
约束匹配

您拥有的检查约束是:

CHECK (DATEPART(yy, ADate) = 2014)
其中
子句为:

Where A.ADate = '20140611'
问题在于,第二个未被识别为第一个的子集。您可以通过添加冗余来解决此问题:

Where A.ADate = '20140611' and DATEPART(yy, A.ADate) = 2014
或者,您可以通过使用范围来解决这个问题——但是要小心数据类型,因为数据类型转换肯定会混淆优化器。我认为以下措施会奏效:

CHECK ADate BETWEEN '2014-01-01' and '2014-12-31'
WHERE A.ADate = '2014-06-11'
(连字符是可选的,可以删除。)

(据我所知)原因并不明确:

SQL Server查询优化器可识别中的搜索条件 此SELECT语句仅引用1998年5月销售和销售记录中的行 1998年6月销售表。因此,它将搜索限制在这些表上

分区视图返回时不需要检查约束 正确的结果。但是,如果尚未设置检查约束 定义后,查询优化器必须搜索所有表,而不是 仅包含分区列上的搜索条件。 在没有检查约束的情况下,视图的操作与任何其他视图一样 和所有人一起。查询优化器无法对 存储在不同表中的值,不能跳过搜索 参与视图定义的表


如果显式地添加
和DATEPART(yy,ADate)=2014会怎么样?为什么不使用分区,在这种情况下不需要多个表。@RADAR我最常使用分区视图的时间是哪一次?@ardalanshagholi,,实际上是将数据拆分到不同的文件中groups@RADAR谢谢你的回应,但我们最常使用分区视图的时间是什么时候?如果您显式地添加
和DATEPART(yy,ADate)=2014
?为什么不使用分区,在这种情况下不需要多个表。@RADAR我最常使用分区视图的时间是什么时候?@ardalanshagholi,,实际上是将数据拆分到不同的文件中groups@RADAR谢谢你的回应,但是,我们最常使用分区视图的时间是什么时候?如果使用
where DATEPART(yy,ADate)=2014,它不会产生更好的执行计划吗?我不认为