有谁知道为什么sql server选择查询表'building'两次?有什么解释吗?可以只用一个表搜索吗?
这是代码示例:
DECLARE @id1stBuild INT = 1
,@number1stBuild INT = 2
,@idLastBuild INT = 5
,@numberLastBuild INT = 1;
DECLARE @nr TABLE (nr INT);
INSERT @nr
VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
CREATE TABLE building (
id INT PRIMARY KEY identity(1, 1)
,number INT NOT NULL
,idStreet INT NOT NULL
,surface INT NOT NULL
)
INSERT INTO building (number,idStreet,surface)
SELECT bl.b
,n.nr
,abs(convert(BIGINT, convert(VARBINARY, NEWID()))) % 500
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY n1.nr) b
FROM @nr n1
CROSS JOIN @nr n2
CROSS JOIN @nr n3
) bl
CROSS JOIN @nr n
--***** execution plan for the select below
SELECT *
FROM building b
WHERE b.id = @id1stBuild
AND b.number = @number1stBuild
OR b.id = @idLastBuild
AND b.number = @numberLastBuild
DROP TABLE building
此操作的执行计划始终相同:通过Merge Join(Concatenation)统一两个Clustered Index Seek。其余的不太重要。 这是执行计划:
答案 0 :(得分:5)
它没有扫描两次。它正在寻求两次。
您的查询在语义上与以下内容相同。
SELECT *
FROM building b
WHERE b.id = @id1stBuild
AND b.number = @number1stBuild
UNION
SELECT *
FROM building b
WHERE b.id = @idLastBuild
AND b.number = @numberLastBuild
执行计划执行两次搜查和结合。
答案 1 :(得分:3)
为什么在同一张桌子上扫描两次?
不是扫描,是寻求,而这一切都有所不同。
将OR实现为UNION,然后通过MERGE JOIN实现UNION。被称为'merge union':
合并联盟
现在让我们稍微改变一下查询:
select a from T where b = 1 or c = 3 |--Stream Aggregate(GROUP BY:([T].[a])) |--Merge Join(Concatenation) |--Index Seek(OBJECT:([T].[Tb]), SEEK:([T].[b]=(1)) ORDERED FORWARD) |--Index Seek(OBJECT:([T].[Tc]), SEEK:([T].[c]=(3)) ORDERED FORWARD)
我们现在有一个合并连接(连接)和一个流聚合,而不是连接和排序不同的运算符。发生了什么?合并连接(concatenation)或“merge union”实际上并不是一个连接。它由与合并连接相同的迭代器实现,但它实际上执行了一个联合,同时保留了输入行的顺序。最后,我们使用流聚合来消除重复。 (有关使用流聚合来消除重复项的更多信息,请参阅此文章。)此计划通常是更好的选择,因为sort distinct使用内存,如果流中的内存不足,可能会将数据溢出到磁盘聚合不使用内存。
答案 2 :(得分:2)
您可以尝试以下操作,它只提供一次搜索并略微提升性能。正如@Martin_Smith所说,您编码的内容相当于Union
SELECT *
FROM building b
WHERE b.id IN (@id1stBuild , @idLastBuild)
AND
(
(b.id = @id1stBuild AND b.number = @number1stBuild) OR
(b.id = @idLastBuild AND b.number = @numberLastBuild)
)