我想知道是否有人可以阐明为什么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;对于易于使用的基础数据,在查询这些视图时,我将受到性能影响。
答案 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提出一个事件,并直接向他们询问它是否对您的系统至关重要。