SQL Server 2005的检查约束不使用变量

问题描述:

当执行时被应用于下面是一些SQL示例代码:SQL Server 2005的检查约束不使用变量

--Create 2 Sales tables with constraints based on the saledate 
create table Sales1(SaleDate datetime, Amount money) 
ALTER TABLE dbo.Sales1 ADD CONSTRAINT 
    CK_Sales1 CHECK (([SaleDate]>='01 May 2010')) 
GO 
create table Sales2(SaleDate datetime, Amount money) 
ALTER TABLE dbo.Sales2 ADD CONSTRAINT 
    CK_Sales2 CHECK (([SaleDate]<'01 May 2010')) 
GO 

--Insert some data into Sales1 
insert into Sales1 (SaleDate, Amount) 
values ('02 May 2010', 50) 
insert into Sales1 (SaleDate, Amount) 
values ('03 May 2010', 60) 
GO 

--Insert some data into Sales2 
insert into Sales2 (SaleDate, Amount) 
values ('30 Mar 2010', 10) 
insert into Sales2 (SaleDate, Amount) 
values ('31 Mar 2010', 20) 
GO 

--Create a view that combines these 2 tables 
create VIEW [dbo].[Sales] 
AS 
    SELECT SaleDate, Amount FROM Sales1 
    UNION ALL 
    SELECT SaleDate, Amount FROM Sales2 
GO 

--Get the results 
--Query 1 
select * from Sales where SaleDate < '31 Mar 2010' -- if you look at the execution plan this query only looks at Sales2 (Which is good) 

--Query 2 
DECLARE @SaleDate datetime 
SET @SaleDate = '31 Mar 2010' 
select * from Sales where SaleDate < @SaleDate -- if you look at the execution plan this query looks at Sales1 and Sales2 (Which is NOT good) 

望着执行计划,你会看到,这两个查询是不同的充。对于查询1,唯一被访问的表是Sales1(这很好)。对于查询2,两个表都被访问(哪个是坏的)。为什么这些执行计划有所不同,以及如何在使用变量时让Query 2仅访问相关表?

我试图为SaleDate列添加索引,这似乎没有帮助。

查询计划被缓存以供重用,因此它是为一般情况创建的。缓存的计划必须对所有可能的值@SalesDate有效。这意味着查询计划必须在两个视图中查看。

可避免通过运行动态SQL:

declare @sql varchar(max) 
set @sql = 'select * from Sales where SaleDate < ' + @SaleDate 
exec (@sql) 

有优化查询一个变量的特定值,就像一个选项:

SELECT * 
FROM Sales 
WHERE SaleDate < ' + @SaleDate 
OPTION (OPTIMIZE FOR (@SalesDate = '2010-01-01')) 

但SQL Server仍然坚持查看两个表,因为即使它试图优化2010-01-01,它也必须返回2009-01-01的正确结果。

这是预期的。该计划现在可以与变量中的任何值一起重用。

具有字面值,它不会打扰可恢复性,因为如果字面更改,计划会更改。现在

,我描述了这种行为一个很好的链接。关键词是 ...

编辑: