2016-08-23 59 views
1

我想知道是否有人可以闡明爲什麼SQL Server(2016 RTM在我的情況下,但我懷疑這不是版本特定的)執行這個看似不必要的INNER JOIN。SQL Server查詢優化器執行不必要的連接

考慮外鍵加入了以下兩個表:

CREATE TABLE [dbo].[batches](
[Id] [smallint] IDENTITY(1,1) PRIMARY KEY, 
[Date] [date] NOT NULL, 
[Run] [tinyint] NOT NULL, 
[Clean] [bit] NOT NULL) 

CREATE TABLE [dbo].[batch_values](
[Batch_Id] [smallint] NOT NULL, 
[Key] [int] NOT NULL, 
[Value] [int] NOT NULL, 
CONSTRAINT [PK_batch_values] PRIMARY KEY CLUSTERED 
([Batch_Id] ASC, [Key] ASC)) 
GO 

ALTER TABLE [dbo].[batch_values] WITH CHECK 
ADD CONSTRAINT [FK_batch_values_batches] FOREIGN KEY([Batch_Id]) 
REFERENCES [dbo].[batches] ([Id]) 
GO 

ALTER TABLE [dbo].[batch_values] CHECK CONSTRAINT [FK_batch_values_batches] 
GO 

填充表的一些數據:現在

SET NOCOUNT ON; 

DECLARE 
    @BatchCount int, 
    @BatchId smallint, 
    @KeyCount int; 

SET @BatchCount = 1; 

WHILE @BatchCount <= 100 
BEGIN 

    INSERT INTO dbo.[batches] 
    VALUES (DATEADD(dd, @BatchCount/10, '2016-01-01'), @BatchCount % 10, @BatchCount % 2); 

    SET @BatchId = SCOPE_IDENTITY(); 

    SET @KeyCount = 1; 

    WHILE @KeyCount <= 1000 
    BEGIN 

     INSERT INTO dbo.batch_values 
     VALUES (@BatchId, @KeyCount, RAND() * 1000000 - 500000); 

     SET @KeyCount = @KeyCount + 1; 

    END; 

    SET @BatchCount = @BatchCount + 1; 

END; 

,如果我運行下面的查詢執行計劃顯示即使沒有從中選擇列,SQL Server也正在對[批處理]表執行INNER JOIN,並且由於外鍵約束的原因,由於連接而無法從[批處理值]中刪除記錄。

screenshot of query and execution plan

這在我看來,查詢優化器應該丟棄INNER JOIN是不必要的,只是做一個主鍵徵求[batch_values],但事實並非如此。

這是很重要的,因爲如果我開發視圖連接多個表來呈現底層數據的「更大圖片」以便於使用,那麼在查詢這些視圖時,我將會獲得性能優勢。

+1

行不能丟棄,但它們可以相乘。 – Blorgbeard

+0

哦,不,他們不能,因爲你在batch_values上指定了PK。嗯。 – Blorgbeard

+0

哦,是的,他們可以這樣做,因爲FK只能用一種方式。它可能會從其他表中遺漏。這是一個奇怪的情況,因爲它是一個垂直分區表(都加入主鍵)。如果我以正確的方式讀取FK,您可以在'batch'中創建一條記錄,而不會以'batch_values'存在(但不是另一種方式) –

回答

0

使用SQL Optimizer的JOIN ELIMINATION有很多限制

E.g.如果您在外鍵中使用多列,或者約束不受信任,或者標記爲「不適用於複製」等。

如果您在外鍵列中指定WHERE謂詞,SQL Server可能不會使用JOIN ELIMINATION。

刪除WHERE或刪除「BATCH_ID = 100」從那裏,你應該看到的優化現在使用連接排除

的文檔關於這一主題的限制,所以我不能提供證明的鏈接,但許多人們在過去的5 - 7年裏針對不同的版本報道了這個問題,並且同意這種行爲是通過設計的。我的建議是向MS提出一個事件,並直接詢問它是否對您的系統至關重要。

+0

我玩了一些,還做了一些搜索JOIN ELIMINATION,看起來你對WHERE子句是正確的。 –