SQL Server查询优化器执行不必要的连接

时间:2016-08-23 02:30:11

标签: sql-server join

我想知道是否有人可以阐明为什么SQL Server(在我的情况下是2016 RTM,但我怀疑这不是版本特定的)正在执行这个看似不必要的INNER JOIN。

考虑以下两个由外键连接的表:

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,即使没有从中选择任何列,也不能从[batch_values]中删除任何记录由于外键约束而导致的连接结果。

screenshot of query and execution plan

在我看来,查询优化器应该将INNER JOIN丢弃为不必要的,只需在[batch_values]上执行主键搜索,但它不会。

这是重要的,因为如果我开发了连接多个表格的视图来呈现更大的图片&#34;对于易于使用的基础数据,在查询这些视图时,我将受到性能影响。

1 个答案:

答案 0 :(得分:0)

SQL Optimizer使用JOIN ELIMINATION有许多限制

E.g。如果您在外键中使用多个列,或者不信任约束,或者标记为&#39;不用于复制&#39;等。

如果使用外键中的列指定WHERE谓词,则SQL Server可能不会使用JOIN ELIMINATION。

删除WHERE或删除&#34; Batch_id = 100&#34;从WHERE,您应该看到优化器现在使用JOIN ELIMINATION

文档仅限于此主题,因此我无法提供证据链接,但许多人在过去的5到7年中针对不同版本报告了此问题,并同意该行为是设计的。我的建议是向MS提出一个事件,并直接向他们询问它是否对您的系统至关重要。