2010-05-18 31 views
0

當執行時被應用於下面是一些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列添加索引,這似乎沒有幫助。

回答

0

查詢計劃被緩存以供重用,因此它是爲一般情況創建的。緩存的計劃必須對所有可能的值@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的正確結果。

0

這是預期的。該計劃現在可以與變量中的任何值一起重用。

具有字面值,它不會打擾可恢復性,因爲如果字面更改,計劃會更改。現在

,我描述了這種行爲一個很好的鏈接。關鍵詞是 ...

編輯: