Có "HOẶC" trong điều kiện INNER JOIN có phải là một ý tưởng tồi không?


94

Trong việc cố gắng cải thiện tốc độ của một truy vấn cực kỳ chậm (vài phút trên hai bảng chỉ có ~ 50.000 hàng mỗi bảng, trên SQL Server 2008 nếu điều đó quan trọng), tôi đã thu hẹp vấn đề thành một phép ORnối bên trong của tôi, như trong:

SELECT mt.ID, mt.ParentID, ot.MasterID
  FROM dbo.MainTable AS mt
  INNER JOIN dbo.OtherTable AS ot ON ot.ParentID = mt.ID
                                  OR ot.ID = mt.ParentID

Tôi đã thay đổi điều này thành (những gì tôi hy vọng là) một cặp nối trái tương đương, được hiển thị ở đây:

SELECT mt.ID, mt.ParentID,
   CASE WHEN ot1.MasterID IS NOT NULL THEN
      ot1.MasterID ELSE
      ot2.MasterID END AS MasterID
  FROM dbo.MainTable AS mt
  LEFT JOIN dbo.OtherTable AS ot1 ON ot1.ParentID = mt.ID
  LEFT JOIN dbo.OtherTable AS ot2 ON ot2.ID = mt.ParentID
  WHERE ot1.MasterID IS NOT NULL OR ot2.MasterID IS NOT NULL

.. và truy vấn hiện chạy trong khoảng một giây!

Nói chung có phải là một ý tưởng tồi khi đặt một ORđiều kiện tham gia? Hay tôi chỉ thiếu may mắn bằng cách nào đó trong cách bố trí các bảng của tôi?


6
Cho chúng tôi xem kế hoạch thực hiện thay vì truy vấn của bạn.
Blindy

có vẻ giống như một mối quan hệ kỳ lạ
nathan gonzalez

@Blindy: ý kiến ​​hay. Hóa ra các kế hoạch thực thi chỉ hiển thị những gì mà Quassnoi đề cập bên dưới: truy vấn đầu tiên dẫn đến các vòng lặp lồng nhau, trong khi truy vấn thứ hai được thực hiện với một phép nối băm.
ladenedge

Câu trả lời:


114

Loại JOINnày không thể tối ưu hóa thành a HASH JOINhoặc a MERGE JOIN.

Nó có thể được biểu thị dưới dạng kết hợp của hai tập kết quả:

SELECT  *
FROM    maintable m
JOIN    othertable o
ON      o.parentId = m.id
UNION
SELECT  *
FROM    maintable m
JOIN    othertable o
ON      o.id = m.parentId

, mỗi người trong số họ là một phần tử tương đương, tuy nhiên, trình SQL Servertối ưu hóa của không đủ thông minh để thấy nó trong truy vấn bạn đã viết (mặc dù chúng tương đương về mặt logic).


3
điều này có ý nghĩa, cảm ơn bạn. Tôi vẫn không chắc liệu có điều gì đó đặc biệt về truy vấn của mình hay tôi chỉ nên tránh ON w=x OR y=zhoàn toàn các phép nối của mẫu?
ladenedge

@ladenedge: các phép nối này sẽ được thực hiện bằng cách quét bảng trong một vòng lặp lồng nhau. Điều này là chậm nếu bảng của bạn lớn.
Quassnoi

chỉ để rõ ràng, khi bạn nói "những kết hợp này", bạn có nghĩa là tất cả các kết hợp của biểu mẫu ON w=x OR y=z? (Cảm ơn sự kiên nhẫn của bạn!)
ladenedge

3
@ladenedge: có thể có các điều kiện bổ sung có thể giúp SQL Serverhiểu rằng cần phải nối. Giả sử, truy vấn SELECT * FROM othertable WHERE parentId = 1 OR id = 2sẽ sử dụng một nối nếu cả hai trường đều được lập chỉ mục nên về mặt lý thuyết, không có gì ngăn cản việc thực hiện cùng một điều trong một vòng lặp. Cho dù SQL Serversẽ xây dựng kế hoạch này thực sự hay không, phụ thuộc vào rất nhiều yếu tố, nhưng tôi chưa bao giờ thấy nó được xây dựng trong cuộc sống thực.
Quassnoi

4

Tôi sử dụng mã sau để nhận được kết quả khác với điều kiện Điều đó đã làm việc cho tôi.


Select A.column, B.column
FROM TABLE1 A
INNER JOIN
TABLE2 B
ON A.Id = (case when (your condition) then b.Id else (something) END)

-2

Bạn có thể sử dụng UNION ALL để thay thế.

SELECT mt.ID, mt.ParentID, ot.MasterID FROM dbo.MainTable AS mt Union ALL SELECT mt.ID, mt.ParentID, ot.MasterID FROM dbo.OtherTable AS ot


UNION ALLsẽ cung cấp cho bạn các bản sao so JOINvới với một ORđiều kiện.
CodeMonkey

Đối với ĐOÀN KẾT đó sẽ đúng. Để biết thêm thông tin chi tiết đọc liên kết sau hiệp-thay-of-hay
Mitul Panchal

1
có nhưng trong ví dụ của bạn, bạn viết nó union allkhông đúng như bài báo bạn liên kết đến cũng mô tả.
CodeMonkey
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.