【问题标题】:Why SQL Server Optimizer do not use CHECK constraint definitions to find which table contains the rows?为什么 SQL Server Optimizer 不使用 CHECK 约束定义来查找包含行的表?
【发布时间】:2015-01-15 02:18:36
【问题描述】:

我使用 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' ) 

我创建了一个partition view,如下所示:

Create View A 
As
    Select * From A2013
    Union 
    Select * From A2014

我希望SQL Optimizer 使用一个好的计划并使用我的 CHECK 约束定义来确定哪个成员表包含行但是在运行此查询时它会扫描两个表:

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

我预计 SQL 优化器不使用表 A2013?!?

【问题讨论】:

  • 如果显式添加AND DATEPART(yy, ADate) = 2014 会怎样?
  • 为什么不使用分区,这样就不需要多个表了。
  • @RADAR 什么时候最常使用分区视图?
  • @ArdalanShahgholi, msdn.microsoft.com/en-us/library/ms188730.aspx ,您实际上将数据拆分到不同的文件组中
  • @RADAR 坦克等待您的回复,但我们最常使用分区视图是什么时候?

标签: sql sql-server sql-server-2012 sql-view


【解决方案1】:

CHECK CONSTRAINT 表达式必须为sargable,以便优化器消除执行计划中不需要的表。下面的约束避免将函数应用于列并且是 sargable:

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' )
    );

【讨论】:

  • where DATEPART(yy, ADate) = 2014 会不会产生更好的执行计划?我不认为这个问题是可悲的。我认为问题是等效性。
  • 直到 sargable 是一个词。关于它的词源有什么想法吗?
  • @Gordon_Linoff,我认为 Ardalan 希望 SQL Server 从计划中消除不需要的表,无论是静态的还是动态的。在检查约束中使用 non-sargable 表达式,将不会发生消除。在 WHERE 子句中使用 non-sarable 表达式(如 DATEPART),视图中的所有表也将被扫描。
  • 如果在where 子句中使用相同的表达式,检查约束中的几乎所有表达式都是“sargable”。问题是 SQL Server 无法识别where 表达式和check 约束中的表达式之间的等价性
【解决方案2】:

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

你的检查约束是:

CHECK (DATEPART(yy, ADate) = 2014)

where 子句是:

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'

(连字符是可选的,可以去掉。)

documentation(据我所知)并没有明确说明原因:

SQL Server 查询优化器识别出搜索条件 此 SELECT 语句仅引用 May1998Sales 和 Jun1998 销售表。因此,它将搜索限制在这些表中。

。 . .

分区视图返回不需要检查约束 正确的结果。但是,如果 CHECK 约束尚未 定义,查询优化器必须搜索所有表而不是 只有那些覆盖分区列上的搜索条件的。 如果没有 CHECK 约束,视图的运行方式与任何其他视图一样 与联合所有。查询优化器不能对 存储在不同表中的值,它不能跳过搜索 参与视图定义的表。

【讨论】:

  • 确实,术语 sargable 最常用于指代有效使用索引。但是,同样的概念更普遍地适用于查询中的表和分区的消除。如果您使用冗余的 DATEPART 谓词检查执行计划,我想您会发现所有表都被触及,即使优化器可能足够聪明,只包含与约束匹配的表。
猜你喜欢
  • 1970-01-01
  • 2011-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-31
  • 2022-01-11
相关资源
最近更新 更多