Tôi có nên lồng các phép nối ngoài phụ thuộc trong SQL Server không?


9

Tôi đã nghe thông tin hỗn hợp về điều này và tôi hy vọng cho một ý kiến ​​kinh điển hoặc chuyên gia.

Nếu tôi có nhiều LEFT OUTER JOINs, mỗi cái phụ thuộc vào cái cuối cùng, có tốt hơn để lồng chúng không?

Đối với một ví dụ giả tạo, sự JOINđể MyParentphụ thuộc vào JOINđể MyChild: http://sqlfiddle.com/#!3/31022/5

SELECT
    {columns}
FROM
    MyGrandChild AS gc
LEFT OUTER JOIN
    MyChild AS c
        ON c.[Id] = gc.[ParentId]
LEFT OUTER JOIN
    MyParent AS p
        ON p.[id] = c.[ParentId]

nhập mô tả hình ảnh ở đây

So với http://sqlfiddle.com/#!3/31022/7

SELECT
    {columns}
FROM
    MyGrandChild AS gc
LEFT OUTER JOIN
    (
    MyChild AS c            
    LEFT OUTER JOIN
        MyParent AS p
            ON p.[id] = c.[ParentId]
    )
    ON c.[Id] = gc.[ParentId]

nhập mô tả hình ảnh ở đây

Như được hiển thị ở trên, chúng tạo ra các gói truy vấn khác nhau trong SS2k8


Tôi thích sử dụng các phép nối lồng nhau: michaeljswart.com/2012/09/when-i-use-nested-joins Có thể đó là vấn đề về phong cách.
Michael J Swart

@MichaelJSwart blog của bạn chỉ xuất hiện để thảo luận khi người phụ thuộc JOININNER JOIN
Matthew

1
Làm thế nào để bạn muốn xác định "tốt hơn"? Cá nhân, tôi thấy đầu tiên dễ đọc hơn nhiều - tâm trí tôi không nảy sinh xung quanh khi cố gắng đảo ngược mối quan hệ. Có ON ... ONhai lần liên tiếp (dấu ngoặc đơn hoặc không) là rất khó hiểu.
Aaron Bertrand

4
Khi tôi thấy không có sự khác biệt về hiệu suất giữa hai cách làm việc gì đó, câu hỏi tiếp theo tôi tự hỏi mình là: nếu tôi bị xe buýt đâm trúng xổ số tối nay, phiên bản nào sẽ dễ hiểu và được duy trì nhất bởi bất kỳ ai chiếm lấy mã của tôi vào ngày mai ?
Aaron Bertrand

1
Các use plangợi ý hoạt động khi cấy kế hoạch truy vấn thứ hai để là người đầu tiên nhưng không phải ngược lại.
Martin Smith

Câu trả lời:


3

Đây hoàn toàn không phải là một câu trả lời chính tắc nhưng tôi nhận thấy rằng đối với các kế hoạch truy vấn vòng lặp lồng nhau được hiển thị trong SQL Fiddle, có thể áp dụng kế hoạch từ Truy vấn 2 đến Truy vấn 1 với việc sử dụng USE PLANgợi ý nhưng việc thử thao tác ngược lại thất bại với

Bộ xử lý truy vấn không thể tạo kế hoạch truy vấn vì gợi ý USE PLAN chứa gói không thể xác minh là hợp pháp cho truy vấn. Xóa hoặc thay thế gợi ý SỬ DỤNG KẾ HOẠCH. Để có khả năng buộc kế hoạch thành công tốt nhất, hãy xác minh rằng gói được cung cấp trong gợi ý USE PLAN là một máy chủ được tạo tự động bởi SQL Server cho cùng một truy vấn.

Vô hiệu hóa quy tắc chuyển đổi tối ưu hóa cũng ReorderLOJN ngăn cản gợi ý kế hoạch thành công trước đó thành công.

Thử nghiệm với số lượng lớn hơn các chương trình dữ liệu SQL Server là chắc chắn có khả năng chuyển (A LOJ B) LOJ Cđến A LOJ (B LOJ C)một cách tự nhiên cũng nhưng tôi không thấy bất kỳ bằng chứng cho thấy điều ngược lại là đúng.

Một trường hợp rất dễ xảy ra khi truy vấn đầu tiên thực hiện tốt hơn truy vấn thứ hai là

DROP TABLE  MyGrandChild , MyChild,  MyParent

CREATE TABLE MyParent
(Id int)

CREATE TABLE MyChild
(Id int PRIMARY KEY
,ParentId int,
Filler char(8000) NULL)

CREATE TABLE MyGrandChild
(Id int
,ParentId int)

INSERT INTO MyChild
                      (Id, ParentId)
SELECT TOP (100000) ROW_NUMBER() OVER (ORDER BY @@SPID),
                     ROW_NUMBER() OVER (ORDER BY @@SPID)    
FROM master..spt_values  v1, master..spt_values                  

INSERT INTO MyGrandChild
                      (Id, ParentId)
OUTPUT INSERTED.Id INTO MyParent
SELECT TOP (3000) Id, Id AS ParentId
FROM MyChild
ORDER BY Id

SET STATISTICS IO ON;
SET STATISTICS TIME ON;

SELECT gc.Id       AS gcId,
       gc.ParentId AS gcpId,
       c.Id        AS cId,
       c.ParentId  AS cpId,
       p.Id        AS pId
FROM   MyGrandChild AS gc
       LEFT OUTER JOIN MyChild AS c
         ON c.[Id] = gc.[ParentId]
       LEFT OUTER JOIN MyParent AS p
         ON p.[Id] = c.[ParentId]

SELECT gc.Id       AS gcId,
       gc.ParentId AS gcpId,
       c.Id        AS cId,
       c.ParentId  AS cpId,
       p.Id        AS pId
FROM   MyGrandChild AS gc
       LEFT OUTER JOIN( MyChild AS c
                        LEFT OUTER JOIN MyParent AS p
                          ON p.[Id] = c.[ParentId])
         ON c.[Id] = gc.[ParentId] 

Mà đưa ra kế hoạch

nhập mô tả hình ảnh ở đây

Đối với tôi Truy vấn 1 có thời gian trôi qua là 108 ms so với 1.163 ms cho Truy vấn 2.

Truy vấn 1

Table 'Worktable'. Scan count 0, logical reads 0 
Table 'MyChild'. Scan count 0, logical reads 9196
Table 'MyGrandChild'. Scan count 1, logical reads 7
Table 'MyParent'. Scan count 1, logical reads 5

Truy vấn 2

Table 'MyParent'. Scan count 1, logical reads 15000
Table 'MyChild'. Scan count 0, logical reads 9000 
Table 'MyGrandChild'. Scan count 1, logical reads 7

Vì vậy, có thể tạm thời giả định rằng cú pháp đầu tiên ("không được kiểm tra") có khả năng có lợi vì nó cho phép các đơn đặt hàng tham gia tiềm năng hơn được xem xét nhưng tôi đã không thực hiện đủ thử nghiệm để có thể tin tưởng vào quy tắc chung này.

Hoàn toàn có thể đưa ra các ví dụ truy cập trong đó Truy vấn 2 hoạt động tốt hơn. Hãy thử cả hai và nhìn vào các kế hoạch thực hiện.


-1

không có loại THAM GIA nào được gọi là "Tham gia lồng nhau". đó là một biến thể khác của việc viết THAM GIA có thể nhằm mục đích thuận tiện dễ đọc. bạn chỉ có thể xem chúng như một "Truy vấn phụ" để hiểu mục đích.

nếu bạn quan tâm nhiều hơn về khả năng đọc mã thì tôi nghĩ, đó là lựa chọn cá nhân mà họ có thể trao đổi được.

Và nếu bạn quan tâm đến hiệu năng của truy vấn và gợi ý "Buộc THAM GIA ĐẶT HÀNG" không được sử dụng trong truy vấn, thì không vấn đề gì nếu truy vấn được viết bằng "Tham gia lồng nhau" hoặc Tất cả "Tham gia ngoài". Máy chủ SQL đưa ra thứ tự dựa trên chi phí tham gia hai bảng và / hoặc kết quả. SQL Server chỉ thực hiện THAM GIA giữa hai bộ dữ liệu.

trong thực tế, hãy tưởng tượng rằng theo cách thứ hai "lồng nhau" nếu máy chủ SQL quyết định thực hiện phần thứ hai, "MyChild AS c LEFT OUTER THAM GIA MyParent AS p ON p. [id] = c. [ParentId]" và các bảng đó xảy ra để có các hàng sẽ loại bỏ trong NEXT LEFT THAM GIA. trong trường hợp đó, máy chủ SQL đã dành các tài nguyên không cần thiết để thực hiện OUTER THAM GIA hai điều này và chuyển kết quả đó sang THAM GIA tiếp theo.

bạn cũng có thể xem câu hỏi tương tự được hỏi và trả lời thích hợp ở đây. Hiểu cú pháp 'Tham gia lồng nhau'


1
Tại sao, sau đó, họ tạo ra các kế hoạch truy vấn khác nhau mà không sử dụng FORCE JOIN ORDERgợi ý?
Matthew

Với gợi ý đó, chúng tôi không thể đảm bảo thứ tự THAM GIA và vì bạn đang thấy kế hoạch thực hiện khác nhau chứng minh điều đó. ví dụ, theo cách đầu tiên, máy chủ SQL "sử dụng tất cả Tham gia ngoài" có thể thực hiện bất kỳ thao tác nào trong Hai điều này. đầu tiên "MyChild + MyGrandChild" và sau đó THAM GIA với "MyParent". Hoặc Đầu tiên là "MyChild + MyParent" và sau đó THAM GIA vào "MyGrandChild".
Anup Shah
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.