2009-06-19 40 views
131

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 điều kiện trong mệnh đề JOIN so với mệnh đề WHERE không?Điều kiện bên trong JOIN hoặc WHERE

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' 

nào làm bạn thích (và có lẽ tại sao)?

+3

Bạn có chạy hai truy vấn không? Bạn đã kiểm tra các kế hoạch thực hiện do hai truy vấn tạo ra chưa? Bạn đã quan sát điều gì? –

+8

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

+0

@Steve Dignan: Bạn nên đánh giá điều 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à - tiền thưởng - bạn sẽ có một đoạn mã mà bạn có thể sử dụng lại khi các tình huống phức tạp hơn phát sinh. –

Trả lời

108

Các đại số quan hệ cho phép thay thế lẫn nhau của các vị từ trong mệnh đề WHEREINNER JOIN, vì vậy ngay cả INNER JOIN truy vấn với WHERE khoản có thể có các vị từ rearrranged bởi tôi ưu hoa để họ có thể đã được loại trừ trong quá trình JOIN.

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 việc làm cho INNER JOIN tương đối "không đầy đủ" và đặt một số tiêu chí trong WHERE chỉ đơn giản là làm cho danh sách tiêu chí lọc dễ bảo 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.

+13

Được thêm vào để thêm vào tùy thuộc vào nó. Chuẩn bị mọi thứ. – marr75

+2

Nó không chỉ là về truy vấn sạch sẽ hoặc dễ đọc, đó là về hiệu suất.đưa điều kiện tham gia cải thiện hiệu suất cho số lượng lớn dữ liệu với các bảng được lập chỉ mục phù hợp. – Shahdat

+0

@Shahdat chưa bao giờ thấy kế hoạch thực hiện nơi nó tạo ra bất kỳ sự khác biệt nào về điều kiện tương đương ở đâu hoặc tham gia –

7

WHERE sẽ lọc sau khi JOIN diễn ra.

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

+8

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

+1

Cade Roux: Phải. Thường thì những gì bạn viết trong 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 giả sử rằng điều này sẽ đúng trong một thế giới lý thuyết, trong khi câu trả lời của bạn dĩ nhiên chính xác hơn trong thế giới của các trình tối ưu hóa truy vấn tự động :) – TheTXI

3

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

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

0

Đặt điều kiện trong tham gia có vẻ "sai ngữ nghĩa" đối với tôi, vì đó không phải là những gì JOINs là "cho". Nhưng điều đó rất định tính.

Vấn đề bổ sung: nếu bạn quyết định chuyển từ kết nối bên trong sang, hãy tham gia đúng, có điều kiện bên trong JOIN 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í "có chủ ý" (đối với 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 JOIN). – Thetam

20

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 thương hiệu của RDBMS và không tìm thấy sự khác biệt về hiệu suất.

Tôi muốn giữ điều kiện tham gia riêng biệt với đ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 trong mệnh đề nối.

+1

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

+1

Bạn đã hỏi về các phương pháp hay nhất. Ngay sau khi bạn bắt đầu thử nghiệm cách triển khai RDBMS cụ thể hoạt động, những người khác đã đưa ra lời khuyên đúng: điểm chuẩn. –

2

Tôi thường thấy hiệu suất tăng khi lọc khi tham gia. Đặc biệt 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 về đọc hợp lý với hầu hết các truy vấn làm điều này quá, đó là, trong một môi trường khối lượng cao, một chỉ số 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ích thú khi ai đó cho thấy điểm chuẩn SQL của họ và họ đã thực hiện cả hai phiên bản của một sproc 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

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

82

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

Tuy nhiên, nơi bạn đặt điều kiện tạo ra sự khác biệt lớn nếu bạn đang sử dụng các kết nối trái hoặc phải. Ví dụ: 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 bản ghi có thứ tự ngày muộn hơn ngày 15 tháng 5 năm 2009, do đó chuyển đổi tham gia trái sang tham gia bên trong. Thứ hai sẽ cung cấp cho những hồ sơ cộng với bất kỳ khách hàng không có đơn đặt hàng. Tập kết quả 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ỉ cho mục đích ví dụ, 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 chỉ muốn xem các bản ghi trong một bảng nhưng không phải là bản ghi 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 
+0

Cảm ơn bạn đã giải thích bằng các ví dụ –

+0

Câu trả lời hay - rõ ràng và phù hợp với OP – psrpsrpsr

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