我想知道是否有人可以阐明为什么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],但事实并非如此。
这是很重要的,因为如果我开发视图连接多个表来呈现底层数据的“更大图片”以便于使用,那么在查询这些视图时,我将会获得性能优势。
行不能丢弃,但它们可以相乘。 – Blorgbeard
哦,不,他们不能,因为你在batch_values上指定了PK。嗯。 – Blorgbeard
哦,是的,他们可以这样做,因为FK只能用一种方式。它可能会从其他表中遗漏。这是一个奇怪的情况,因为它是一个垂直分区表(都加入主键)。如果我以正确的方式读取FK,您可以在'batch'中创建一条记录,而不会以'batch_values'存在(但不是另一种方式) –