Điều kiện trong THAM GIA hoặc Ở ĐÂU


192

Có sự khác biệt nào (hiệu suất, thực hành tốt nhất, v.v ...) giữa việc đặt một điều kiện trong mệnh đề THAM GIA so với mệnh đề WHERE không?

Ví dụ...

-- Condition in JOIN
SELECT *
FROM dbo.Customers AS CUS
INNER JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
AND CUS.FirstName = 'John'

-- Condition in WHERE
SELECT *
FROM dbo.Customers AS CUS
INNER JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
WHERE CUS.FirstName = 'John'

Bạn thích cái nào hơn (và có lẽ tại sao)?


4
Bạn đã chạy hai truy vấn? Bạn đã kiểm tra các kế hoạch thực hiện được tạo bởi hai truy vấn? Bạn đã quan sát cái gì?
S.Lott

21
@ S.Lott, truy vấn này chỉ dành cho mục đích. Tôi chỉ tự hỏi "nói chung" đó là phương pháp ưa thích - nếu có.
Steve Dignan

1
@Steve Dignan: Bạn nên điểm chuẩn này với dữ liệu mẫu và xem xét các kế hoạch truy vấn. Câu trả lời sẽ rất, rất rõ ràng. Và - phần thưởng - bạn sẽ có một đoạn mã bạn có thể sử dụng lại khi có tình huống phức tạp hơn phát sinh.
S.Lott

1
Cá nhân tôi sẽ đặt điều kiện trong mệnh đề THAM GIA nếu điều kiện mô tả mối quan hệ. Các điều kiện chung chỉ lọc bộ kết quả sẽ chuyển đến phần WHERE sau đó. Ví dụ:FROM Orders JOIN OrderParties ON Orders.Id = OrderParties.Order AND OrderParties.Type = 'Recipient' WHERE Orders.Status = 'Canceled'
Glutexo

Câu trả lời:


153

Đại số quan hệ cho phép khả năng thay thế lẫn nhau của các vị từ trong WHEREmệnh đề và INNER JOIN, do đó, ngay cả INNER JOINcác truy vấn với WHEREmệnh đề cũng có thể có các vị từ được sắp xếp lại bởi trình tối ưu hóa để chúng có thể bị loại trừ trong JOINquá trình.

Tôi khuyên bạn nên viết các truy vấn theo cách dễ đọc nhất có thể.

Đôi khi điều này bao gồm làm cho INNER JOINtương đối "không đầy đủ" và đưa một số tiêu chí vào một WHEREcách đơn giản để làm cho danh sách các tiêu chí lọc dễ dàng duy trì hơn.

Ví dụ: thay vì:

SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
    ON ca.CustomerID = c.CustomerID
    AND c.State = 'NY'
INNER JOIN Accounts a
    ON ca.AccountID = a.AccountID
    AND a.Status = 1

Viết:

SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
    ON ca.CustomerID = c.CustomerID
INNER JOIN Accounts a
    ON ca.AccountID = a.AccountID
WHERE c.State = 'NY'
    AND a.Status = 1

Nhưng nó phụ thuộc, tất nhiên.


7
Đó không chỉ là về truy vấn sạch hoặc khả năng đọc, mà còn về hiệu suất. đưa các điều kiện tham gia cải thiện hiệu suất cho lượng dữ liệu lớn với các bảng được lập chỉ mục đúng.
Shahdat

1
Tôi chỉ chạy báo cáo doanh số hàng tháng tham gia 5-6 bảng trên vài triệu hồ sơ. Perf cải thiện 30% - máy chủ sql 2012
Shahdat

2
@Shahdat nếu bạn nhận được sự khác biệt đáng kể về hiệu suất di chuyển các điều kiện bộ lọc của bạn từ mệnh đề where sang tham gia bên trong, bạn cần đăng các kế hoạch thực hiện đó.
Cade Roux

4
@Cade Tôi đã điều tra các kế hoạch thực hiện - cả hai kịch bản hiển thị cùng một chi phí. Tôi chạy các truy vấn nhiều lần dường như cả hai đều giống nhau về thời gian. Trước đây, tôi đã chạy các truy vấn trong sản xuất và có sự khác biệt đáng kể về hiệu suất vì cơ sở dữ liệu đang được sử dụng bởi người dùng trực tiếp. Xin lỗi vì sự nhầm lẫn đó.
Shahdat

4
Câu trả lời này phù hợp với INNER THAM GIA nhưng không dành cho tham gia trái / phải.
sotn

121

Đối với các kết nối bên trong tôi không thực sự nhận thấy sự khác biệt (nhưng như với tất cả các điều chỉnh hiệu suất, bạn cần kiểm tra đối với cơ sở dữ liệu của bạn trong các điều kiện của bạn).

Tuy nhiên, nơi bạn đặt điều kiện sẽ tạo ra một sự khác biệt rất lớn nếu bạn đang sử dụng các phép nối trái hoặc phải. Ví dụ, hãy xem xét hai truy vấn sau:

SELECT *
FROM dbo.Customers AS CUS 
LEFT JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
WHERE ORD.OrderDate >'20090515'

SELECT *
FROM dbo.Customers AS CUS 
LEFT JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
AND ORD.OrderDate >'20090515'

Đầu tiên sẽ chỉ cung cấp cho bạn những hồ sơ có đơn đặt hàng muộn hơn ngày 15 tháng 5 năm 2009, do đó chuyển đổi tham gia bên trái thành tham gia bên trong. Thứ hai sẽ cung cấp cho các hồ sơ cộng với bất kỳ khách hàng không có đơn đặt hàng. Các kết quả được đặt rất khác nhau tùy thuộc vào nơi bạn đặt điều kiện. (Chọn * nếu chỉ nhằm mục đích, bạn không nên sử dụng khóa học trong mã sản xuất.) Ngoại lệ cho điều này là khi bạn muốn chỉ xem các bản ghi trong một bảng chứ không phải bảng khác. Sau đó, bạn sử dụng mệnh đề where cho điều kiện không tham gia.

SELECT *
FROM dbo.Customers AS CUS 
LEFT JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
WHERE ORD.OrderID is null

Cảm ơn đã giải thích với các ví dụ
Rennish Joseph

1
"do đó chuyển đổi tham gia bên trái thành tham gia bên trong". Làm sao? Bạn có thể xây dựng một chút?
user1451111

@ user1451111 Tìm hiểu những gì LEFT / RIGHT THAM GIA trả về: hàng INNER THAM GIA cộng với các hàng bảng trái / phải chưa từng có được mở rộng bởi NULL. ĐẦY ĐỦ trả về hàng tham gia INNER THAM GIA TẤT CẢ các hàng bảng trái & phải chưa từng có được mở rộng bởi NULL. Luôn biết INNER THAM GIA bạn muốn là một phần của THAM GIA NGOÀI. Một WHERE hoặc ON yêu cầu một cột có thể mở rộng NULL không phải là NULL sau khi OUTER THAM GIA BẬT xóa bất kỳ hàng nào được mở rộng bởi NULL, tức là chỉ để lại các hàng INNER THAM GIA, tức là "biến OUTER THAM GIA thành INNER THAM GIA".
philipxy

1
@ user1451111 hoặc, theo cách hiểu đơn giản hơn: A left join Blà mọi hàng từ A được nối với mọi hàng khớp từ B. Nếu B không có hàng nào khớp, thì các cột A có giá trị nhưng mỗi cột từ B trên hàng đó hiển thị dưới dạng giá trị NULL. Nếu bạn đã viết where B.somecolumn = ‘somevalue’thì bạn có một NULL (B.somecolumn) được so sánh với 'somevalue'. Bất cứ điều gì được so sánh với NULL đều sai, vì vậy tất cả các hàng của bạn không có hàng B phù hợp cho hàng A sẽ bị loại bỏ và kết quả bạn nhận được giống như INNER THAM GIA sẽ đưa ra, do đó, kết nối bên ngoài đã trở thành một bên trong
Caius Jard

có Tôi đã kiểm tra các kết quả giống nhau đối với: CHỌN fund.id, perspectiveects. TỪ triển vọng fundstham gia bên trong trên (perspectiveects.id = fund.lead_id và perspectiveects.is_manual = 'no') và SELECT fund.id, perspectiveects.id TỪ fundstrái tham gia triển vọng trên (perspectiveects.id = fund.lead_id) trong đó có triển vọng.is_manual = 'không'
Rohit Dhiman

25

Hầu hết các sản phẩm RDBMS sẽ tối ưu hóa cả hai truy vấn giống hệt nhau. Trong "Điều chỉnh hiệu suất SQL" của Peter Gulutzan và Trudy Pelzer, họ đã thử nghiệm nhiều nhãn hiệu RDBMS và không tìm thấy sự khác biệt về hiệu suất.

Tôi thích giữ các điều kiện tham gia tách biệt với các điều kiện hạn chế truy vấn.

Nếu bạn đang sử dụng OUTER JOIN đôi khi , cần đặt điều kiện vào mệnh đề nối.


1
Tôi đồng ý với bạn rằng về mặt cú pháp thì nó sạch hơn và tôi phải bảo vệ kiến ​​thức của bạn về cuốn sách đó và uy tín rất cao của bạn, nhưng tôi có thể nghĩ ra 4 truy vấn trong tuần trước với các kế hoạch thực hiện, thời gian CPU và đọc logic rất khác nhau khi Tôi di chuyển nơi vị ngữ để tham gia.
marr75

2
Bạn đã hỏi về thực hành tốt nhất. Ngay khi bạn bắt đầu thử nghiệm cách triển khai RDBMS cụ thể, những người khác đã đưa ra lời khuyên chính xác: điểm chuẩn.
Bill Karwin

12

WHERE sẽ lọc sau khi THAM GIA xảy ra.

Lọc trên THAM GIA để ngăn hàng được thêm vào trong quá trình THAM GIA.


10
Về mặt ngữ nghĩa, chúng bị ngăn chặn trong quá trình INNER THAM GIA, nhưng trình tối ưu hóa có thể sắp xếp lại các dự đoán INNER và WHERE theo ý muốn, vì vậy trình tối ưu hóa có thể loại trừ chúng sau này nếu muốn.
Cade Roux

1
Cade Roux: Phải. Thông thường, những gì bạn viết bằng SQL không phải là những gì trình tối ưu hóa sẽ cung cấp cho bạn khi tất cả được nói và thực hiện. Tôi cho rằng điều này sẽ đúng trong một thế giới toàn lý thuyết, trong khi câu trả lời của bạn dĩ nhiên đúng hơn trong thế giới tối ưu hóa truy vấn tự động :)
TheTXI

Tôi thích cách giải thích về tình trạng này trongON
Robert Rocha

3

Tôi thích THAM GIA để tham gia đầy đủ các bảng / Lượt xem và sau đó sử dụng WHERE Để giới thiệu vị từ của tập kết quả.

Nó cảm thấy cú pháp sạch hơn.


2

Tôi thường thấy hiệu suất tăng khi lọc trên tham gia. Đặc biệt là nếu bạn có thể tham gia vào các cột được lập chỉ mục cho cả hai bảng. Bạn sẽ có thể cắt giảm các lần đọc logic với hầu hết các truy vấn thực hiện điều này, trong môi trường âm lượng lớn, chỉ báo hiệu suất tốt hơn nhiều so với thời gian thực hiện.

Tôi luôn thấy buồn cười khi ai đó hiển thị điểm chuẩn SQL của họ và họ đã thực hiện cả hai phiên bản của một lần quay 50.000 lần vào nửa đêm trên máy chủ dev và so sánh thời gian trung bình.


0

Đặt điều kiện tham gia dường như là "sai về mặt ngữ nghĩa" đối với tôi, vì đó không phải là những gì THAM GIA là "cho". Nhưng đó là rất chất lượng.

Vấn đề khác: nếu bạn quyết định chuyển từ tham gia bên trong sang, giả sử, tham gia đúng, có điều kiện ở bên trong THAM GIA có thể dẫn đến kết quả không mong muốn.


3
Đôi khi những kết quả này là "mong đợi" và đôi khi thậm chí là "có chủ ý" (ví dụ với các phép nối ngoài, trong đó điều kiện WHERE có ngữ nghĩa khác với điều kiện THAM GIA).
Marcel Toth

0

Tham gia nhanh hơn theo ý kiến ​​của tôi khi bạn có một bảng lớn hơn. Nó thực sự không có nhiều sự khác biệt mặc dù đặc biệt là nếu bạn đang làm việc với một bảng khá nhỏ. Khi tôi lần đầu tiên biết về các phép nối, tôi đã nói rằng các điều kiện trong các phép nối giống như các điều kiện mệnh đề và tôi có thể sử dụng chúng thay thế cho nhau nếu mệnh đề where là cụ thể về bảng nào để thực hiện điều kiện trên.


-4

Tốt hơn là thêm điều kiện trong Tham gia. Hiệu suất là quan trọng hơn khả năng đọc. Đối với các tập dữ liệu lớn, nó quan trọng.


1
Bạn có một số loại bằng chứng, nghiên cứu làm thế nào vị trí của các vị từ được đề cập ảnh hưởng đến hiệu suất?
Zso
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.