2015-01-19 18 views
5

Có ai biết tại sao máy chủ sql chọn để truy vấn bảng 'Tòa nhà' hai lần? Có lời giải thích nào không? Nó có thể được thực hiện chỉ với một bàn tìm kiếm?SQL Server - tại sao quét được thực hiện hai lần cho cùng một bảng?

Đây là mẫu mã:

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 

Các kế hoạch thực hiện cho điều này luôn luôn là như nhau: Hai Clustered Index tìm kiếm thống nhất thông qua Merge Join (Concatenation). Phần còn lại ít quan trọng hơn. Dưới đây là kế hoạch thực hiện:

enter image description here

+2

Điều khoản where của bạn bị thiếu khung. Tôi nghĩ rằng có thể là nguyên nhân của việc này ... '([email protected] VÀ [email protected]) OR ([email protected] VÀ [email protected])' vì của 'OR' –

+0

Cảm ơn bạn đã trả lời nhanh. Tôi đã thử nó và nó vẫn là kế hoạch thực hiện tương tự. – Emarian

Trả lời

2

Bạn có thể thử những điều sau đây, chỉ cung cấp một tìm kiếm và cải thiện hiệu suất nhỏ. Vì @Martin_Smith cho biết những gì bạn đã mã hóa tương đương với một số 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) 
     ) 
+1

Nó cung cấp một trình tìm kiếm đơn lẻ nhưng vẫn thực hiện hai tìm kiếm. [Khi nào Tìm kiếm không phải là Tìm kiếm?] (Http://sqlblog.com/blogs/paul_white/archive/2011/02/16/when-is-a-seek-not-a-seek.aspx) –

+0

@MartinSmith trong trường hợp này, kế hoạch truy vấn gợi ý rằng các tham số trong mệnh đề IN được sắp xếp, sau đó biến vị ngữ SEEK sử dụng quét phạm vi nơi id> start và id

+0

Nó sử dụng khoảng thời gian hợp nhất để loại bỏ trùng lặp. Việc tìm kiếm được thực hiện hai lần. Xem "số lần thực hiện" trong kế hoạch thực hiện thực tế. –

5

Nó không quét hai lần. Nó đang tìm kiếm hai lần.

truy vấn của bạn là ngữ nghĩa tương tự như dưới đây.

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 

Và kế hoạch thực hiện thực hiện hai tìm kiếm và kết hợp kết quả.

+0

Tôi chưa bao giờ nghĩ đến việc nhìn vào toán tử 'OR' như một' UNION', nhưng nó thực sự có ý nghĩa rất nhiều. +1 –

+1

Có phải 'UNION' không phải là' UNION ALL' và đó là * rất * quan trọng. Hãy nghĩ kết quả là gì nếu '@ id1stBuild' bằng' @ idLastBuild' và '@ number1stBuild' bằng' @ numberLastBuild'. OR truy vấn trả về một hàng, trong khi UNION ALL trả về hai hàng. –

+0

@RemusRusanu - Điều chỉnh tốt. –

3

tại sao quét được thực hiện hai lần cho cùng một bảng?

Không phải là bản quét, là tìm kiếm và điều đó tạo nên sự khác biệt.

Thực hiện OR như một UNION, và sau đó thực hiện UNION qua một MERGE JOIN. Được gọi là một 'merge union': nối

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) 

Thay vì nối và sắp xếp các nhà khai thác khác nhau, chúng tôi bây giờ có một kết hợp tham gia (:

Merge đoàn

Bây giờ chúng ta hãy thay đổi các truy vấn một chút) và một luồng tổng hợp. Chuyện gì đã xảy ra? Việc hợp nhất tham gia (nối) hoặc "hợp nhất" không thực sự là một tham gia cả. Nó được thực hiện bởi cùng một trình lặp như là phép nối hợp nhất, nhưng nó thực sự thực hiện một liên minh trong khi vẫn giữ thứ tự của các hàng đầu vào. Cuối cùng, chúng tôi sử dụng tổng hợp luồng để loại bỏ các bản sao. (Xem bài này để biết thêm về việc sử dụng dòng tổng hợp để loại bỏ các bản sao.) Kế hoạch này nói chung là một lựa chọn tốt hơn kể từ khi loại riêng biệt bộ nhớ sử dụng và có thể đổ dữ liệu vào đĩa nếu nó chạy ra khỏi bộ nhớ trong khi tổng hợp dòng không sử dụng bộ nhớ .

Các vấn đề liên quan