我想知道是否有人可以阐明为什么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正在对[batches]表执行INNER JOIN,即使未从中选择任何列,因此也无法从[batch_values]中删除任何记录由于外键约束的联接数。
在我看来,Query Optimizer应该将INNER JOIN丢弃为不必要的,而只是对[batch_values]进行主键查找,但事实并非如此。
这很重要,因为如果我开发连接多个表的视图以呈现基础数据的“大图”以便于使用,那么在查询这些视图时,我会受到性能的影响。
通过SQL Optimizer使用JOIN ELIMINATION有很多限制
例如,如果您在外键中使用多个列,或者约束不受信任,或者标记为“非用于复制”等。
如果您用外键中的列指定WHERE谓词,则SQL Server可能不使用JOIN ELIMINATION。
从WHERE中删除WHERE或删除“ Batch_id = 100”,您应该看到优化器现在使用JOIN ELIMINATION
文档仅限于此主题,因此我无法提供证明链接,但是许多人在过去5-7年中针对不同版本报告了此问题,并同意行为是设计使然。我的建议是引发MS事件,并直接询问他们是否对您的系统至关重要。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句