Cú pháp của INNER THAM GIA được lồng bên trong OUTER THAM GIA so với kết quả truy vấn


10

TLDR; Nếu bạn nhìn vào 2 kế hoạch thực hiện, có câu trả lời dễ dàng nào tốt hơn không? Tôi cố tình KHÔNG tạo chỉ mục để dễ nhìn thấy những gì đang xảy ra.

Theo dõi câu hỏi trước đây của chúng tôi, nơi chúng tôi tìm thấy sự khác biệt về hiệu năng truy vấn giữa các kiểu nối khác nhau (nghĩa là lồng nhau so với truyền thống), tôi đã nhận ra rằng cú pháp lồng nhau cũng sửa đổi hành vi của truy vấn. Hãy xem xét 2 truy vấn sau đây.

SELECT  a.*, m.*, n.*
FROM    dbo.Autos a
LEFT JOIN dbo.Models m
  JOIN dbo.Manufacturers n  -- <-- Nested INNER JOIN
  ON n.ManufacturerID = m.ManufacturerID
ON m.ModelID = a.ModelID

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

Điều này không phải làm cho các nhà sản xuất tham gia để bao gồm một hàng tự động với ModelID KHÔNG có trong bảng Mô hình.

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

Sử dụng cú pháp truyền thống, chúng ta phải thay đổi phép nối thành Nhà sản xuất thành một phép nối ngoài, như vậy ... nhưng điều này thay đổi kế hoạch truy vấn.

SELECT a.*, m.*, n.*
FROM dbo.Autos a
LEFT JOIN dbo.Models m
ON m.ModelID = a.ModelID
LEFT JOIN dbo.Manufacturers n -- <-- Now LEFT OUTER JOIN
ON n.ManufacturerID = m.ManufacturerID

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

Câu trả lời:


12

Nếu bạn nhìn vào 2 kế hoạch thực hiện, có câu trả lời dễ dàng nào tốt hơn không? Tôi cố tình KHÔNG tạo chỉ mục để dễ nhìn thấy những gì đang xảy ra.

Kế hoạch thứ hai có chi phí ước tính thấp hơn, vì vậy theo nghĩa hạn chế đó là 'tốt hơn'.

Các tập dữ liệu nhỏ đến mức trình tối ưu hóa không mất nhiều thời gian để xem xét các lựa chọn thay thế. Hình thức đầu tiên của truy vấn xảy ra để tìm một kế hoạch sử dụng hàm băm và một bộ đệm bảng từ sớm. Chi phí ước tính của kế hoạch đó thấp đến mức trình tối ưu hóa không bận tâm tìm kiếm bất cứ điều gì tốt hơn.

Dạng truy vấn thứ hai xảy ra để tìm một kế hoạch chỉ sử dụng các vòng lặp lồng nhau tham gia sớm trong quá trình tìm kiếm và một lần nữa trình tối ưu hóa quyết định rằng kế hoạch đó là đủ tốt. Nó xảy ra rằng kế hoạch này được ước tính là rẻ hơn.

Điều đó nói rằng (như đã đề cập trong các bình luận câu hỏi) hai truy vấn không giống nhau về mặt ngữ nghĩa. Điều này có thể không quan trọng đối với bạn nếu bạn có thể đảm bảo rằng kết quả sẽ luôn giống nhau cho tất cả các trạng thái có thể có trong cơ sở dữ liệu của bạn, nhưng trình tối ưu hóa không thể đưa ra giả định đó. Nó chỉ tạo ra các kế hoạch được đảm bảo để tạo ra các kết quả tương tự được chỉ định bởi SQL, trong mọi trường hợp.

Tôi đã nhận ra rằng cú pháp lồng nhau cũng sửa đổi hành vi của truy vấn.

'Cú pháp lồng nhau' chỉ là một khía cạnh của toàn bộ đặc tả cú pháp nối ANSI. Để kích hoạt một đặc tả logic đầy đủ cho các mẫu tham gia phức tạp hơn, đặc tả cho phép các dấu ngoặc đơn (tùy chọn) và FROMcác truy vấn con mệnh đề.

Truy vấn có thể được viết bằng cú pháp ANSI tương tự bằng dấu ngoặc đơn:

SELECT
    A.*,
    M.*,
    N.* 
FROM dbo.Autos AS A
LEFT JOIN
(
    dbo.Manufacturers AS N
    JOIN dbo.Models AS M
        ON M.ManufacturerID = N.ManufacturerID
) ON M.ModelID = A.ModelID;

Hình thức này rõ ràng cho thấy rằng các yêu cầu hợp lý là để trái tham gia từ Autosđến kết quả của bên tham gia Manufacturersđể Models. Việc bỏ dấu ngoặc đơn tùy chọn sẽ cho biểu mẫu bạn gọi là 'lồng nhau':

SELECT
    A.*,
    M.*,
    N.* 
FROM dbo.Autos AS A
LEFT JOIN dbo.Manufacturers AS N
JOIN dbo.Models AS M
    ON M.ManufacturerID = N.ManufacturerID
    ON M.ModelID = A.ModelID;

Đây không phải là một cú pháp khác nhau - nó chỉ bỏ qua các dấu ngoặc đơn tùy chọn và định dạng lại một chút.

Như Martin đã đề cập, trong trường hợp này cũng có thể thể hiện yêu cầu logic bằng cách sử dụng các phép nối bên trong theo sau là một phép nối ngoài bên phải:

SELECT
    A.*,
    M.*,
    N.* 
FROM dbo.Manufacturers AS N
JOIN dbo.Models AS M
    ON M.ManufacturerID = N.ManufacturerID
RIGHT JOIN dbo.Autos AS A
    ON A.ModelID = M.ModelID;

Tất cả ba biểu mẫu truy vấn ở trên đều sử dụng cùng một cú pháp nối ANSI. Cả ba cũng xảy ra để tạo ra cùng một kế hoạch thực hiện vật lý với bộ dữ liệu được cung cấp:

Kế hoạch thực hiện chung

Như tôi đã đề cập trong câu trả lời của mình cho câu hỏi trước đó của bạn, các truy vấn thể hiện chính xác cùng một yêu cầu logic sẽ không luôn tạo ra cùng một kế hoạch thực hiện. Hình thức truy vấn logic nào bạn muốn sử dụng phần lớn là một câu hỏi về phong cách. Nói chung, không có mối tương quan giữa một phong cách cụ thể và kế hoạch truy vấn 'tốt hơn'. Tôi thường khuyên bạn không nên viết lại một truy vấn để có được một kế hoạch cụ thể nếu truy vấn mới không thực sự giống hệt với bản gốc.

Tiêu chuẩn SQL cũng cho phép FROMtruy vấn mệnh đề, do đó, một cách khác để viết cùng một đặc tả truy vấn là:

SELECT * 
FROM dbo.Autos AS A
LEFT JOIN
(
    SELECT
        N.ManufacturerID,
        ManufacturerName = N.Name,
        M.ModelID,
        ModelName = M.Name
    FROM dbo.Manufacturers AS N
    JOIN dbo.Models AS M
        ON M.ManufacturerID = N.ManufacturerID
) AS R1
    ON R1.ModelID = A.ModelID;

Sử dụng cú pháp truyền thống, chúng ta phải thay đổi phép nối thành `Các nhà sản xuất thành một phép nối ngoài, như vậy ... nhưng điều này thay đổi kế hoạch truy vấn.

Điều này có thể thay đổi ý nghĩa của truy vấn, trong trường hợp đó về mặt kỹ thuật không phải là một thay thế hợp lệ (nhưng hãy xem nhận xét của ypercube về câu hỏi của bạn).

Các dấu ngoặc đơn (tùy chọn) trong cú pháp nối ANSI có chính xác cho các yêu cầu nối phức tạp hơn như thế này, vì vậy bạn không nên ngại sử dụng chúng khi cần thiết.

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.