2008-09-26 46 views
150

tôi refactored một phần chậm chạp của một ứng dụng chúng ta thừa hưởng từ một công ty khác sử dụng một bên tham gia thay vì một subquery nhưcác truy vấn con vs tham gia

where id in (select id from ...) 

Truy vấn refactored chạy khoảng 100x nhanh hơn. (~ 50 giây đến ~ 0,3) Tôi mong đợi một cải tiến, nhưng bất cứ ai có thể giải thích lý do tại sao nó quá quyết liệt? Các cột được sử dụng trong mệnh đề where đều được lập chỉ mục. Liệu SQL có thực thi truy vấn trong mệnh đề where một lần trên mỗi hàng hay một thứ gì đó không?

Cập nhật - Giải thích kết quả:

Sự khác biệt là ở phần thứ hai của "nơi id trong()" truy vấn -

2 DEPENDENT SUBQUERY submission_tags ref st_tag_id st_tag_id 4 const 2966 Using where 

vs 1 hàng được lập chỉ mục với tham gia:

SIMPLE s eq_ref PRIMARY PRIMARY 4 newsladder_production.st.submission_id 1 Using index 
+4

Bản sao có thể có của [Tham gia và truy vấn phụ] (http://stackoverflow.com/questions/2577174/join-vs-sub-query) –

+1

Không trùng lặp. Câu hỏi này đặc biệt về sự khác biệt về hiệu suất nổi bật. Các câu hỏi khác là tổng quát hơn, mở kết thúc về những ưu và khuyết điểm của mỗi phương pháp tiếp cận và tại sao một cách tiếp cận có vẻ phổ biến hơn. –

Trả lời

147

Một "truy vấn con tương quan" (tức là, một trong đó điều kiện nơi phụ thuộc vào các giá trị thu được từ các hàng của truy vấn chứa) sẽ thực hiện một lần cho mỗi hàng. Truy vấn con không tương quan (một trong đó điều kiện nơi độc lập với truy vấn chứa) sẽ thực hiện một lần ở đầu. Công cụ SQL làm cho sự khác biệt này tự động.

Nhưng, vâng, kế hoạch giải thích sẽ cung cấp cho bạn chi tiết bẩn.

+9

+1 cho việc sử dụng giải thích – susmits

+1

Xin lưu ý rằng 'PHỤ LỤC PHỤ LỤC' có nghĩa là chính xác giống như" truy vấn con tương quan ". – Timo

7

Chạy gói giải thích trên mỗi phiên bản, nó sẽ cho bạn biết lý do.

3

Xem gói truy vấn cho từng truy vấn.

đâu trongTham thể thường được thực hiện bằng cách sử dụng kế hoạch thực hiện tương tự, vì vậy thường có zero tăng tốc từ việc thay đổi giữa chúng.

+3

Haha, tôi <3 Sql tẩy tế bào chết mà bỏ phiếu vì họ không biết cách đọc kế hoạch truy vấn. –

+5

Tôi đã bỏ phiếu cho bạn để sử dụng từ "tẩy tế bào chết" –

+3

Tôi upvoted cho bạn bằng cách sử dụng từ chà –

36

Bạn đang chạy truy vấn phụ một lần cho mỗi hàng trong khi kết nối xảy ra trên các chỉ mục.

+5

Tôi không nghĩ rằng điều này là đúng sự thật. Công cụ SQL chỉ chạy truy vấn phụ một lần và sử dụng kết quả dưới dạng danh sách. – dacracot

+8

Điều đó phụ thuộc - nếu truy vấn phụ được tương quan bằng cách nào đó với truy vấn bên ngoài (sử dụng dữ liệu của nó), nó được thực hiện với mỗi hàng. – qbeuek

+4

Nó có thể đúng trong trường hợp này, nhưng nó không đúng nói chung. –

3

Trình tối ưu hóa không hoạt động tốt. Thông thường chúng có thể được chuyển đổi mà không có bất kỳ sự khác biệt nào và trình tối ưu hóa có thể làm điều này.

+1

Nhưng không phải trong MySQL – Greg

2

Với truy vấn phụ, bạn phải thực thi lại lệnh SELECT thứ 2 cho mỗi kết quả và mỗi lần thực thi thường trả về 1 hàng.

Với tham gia, lệnh SELECT thứ 2 trả về nhiều hàng hơn, nhưng bạn chỉ phải thực hiện một lần. Ưu điểm là bây giờ bạn có thể tham gia vào các kết quả, và tham gia các mối quan hệ là những gì một cơ sở dữ liệu được cho là tốt. Ví dụ: có thể trình tối ưu hóa có thể phát hiện ra cách tận dụng lợi thế của chỉ mục ngay bây giờ.

2

Nó không phải là quá nhiều truy vấn phụ như mệnh đề IN, mặc dù các kết nối là nền tảng của ít nhất là công cụ SQL của Oracle và chạy cực kỳ nhanh chóng.

+1

nơi trong thực sự isnt vốn đã xấu. – Shawn

3

Truy vấn con có thể đang thực hiện "quét toàn bộ bảng". Nói cách khác, không sử dụng chỉ mục và trả về quá nhiều hàng mà từ đó truy vấn chính cần phải lọc ra ở đâu.

Chỉ cần đoán mà không có chi tiết về khóa học nhưng đó là tình huống phổ biến.

4

Thông thường kết quả của trình tối ưu hóa không thể tìm ra truy vấn phụ có thể được thực hiện như một phép nối trong trường hợp nó thực thi truy vấn phụ cho mỗi bản ghi trong bảng thay vì tham gia bảng trong truy vấn con so với bảng bạn đang truy vấn. Một số cơ sở dữ liệu "enterprisey" hơn là tốt hơn lúc này, nhưng họ vẫn còn bỏ lỡ nó đôi khi.

4

Câu hỏi này có phần chung chung, do đó, đây là câu trả lời chung:

Về cơ bản, các truy vấn mất nhiều thời gian hơn khi MySQL có hàng để sắp xếp.

Làm điều này:

Chạy một giải thích trên mỗi truy vấn (các JOIN'ed một, thì Subqueried một), và đăng các kết quả ở đây.

Tôi nghĩ rằng việc thấy sự khác biệt trong cách giải thích của MySQL về các truy vấn đó sẽ là trải nghiệm học tập cho mọi người.

6

trước khi truy vấn chạy với tập dữ liệu được đặt thông qua trình tối ưu hóa truy vấn, trình tối ưu hóa cố gắng tổ chức truy vấn theo cách như vậy để có thể xóa nhiều hàng (hàng) khỏi tập kết quả nhanh nhất có thể . Thường thì khi bạn sử dụng các truy vấn con (đặc biệt là các truy vấn con), các bộ dữ liệu không thể được cắt tỉa ra khỏi tập kết quả cho đến khi truy vấn bên ngoài bắt đầu chạy.

Khi không nhìn thấy truy vấn, khó có thể nói điều gì là xấu về bản gốc, nhưng tôi đoán đó là thứ mà trình tối ưu hóa không thể làm tốt hơn nhiều. Chạy 'giải thích' sẽ cho bạn thấy phương pháp tối ưu hóa để truy xuất dữ liệu.

4

Truy vấn con nơi phải chạy 1 truy vấn cho mỗi hàng được trả về. Việc tham gia bên trong chỉ cần chạy 1 truy vấn.

16

Dưới đây là ví dụ về cách subqueries are evaluated in MySQL 6.0.

Trình tối ưu hóa mới sẽ chuyển đổi loại truy vấn con này thành các kết nối.

+0

Đó là một bài viết tuyệt vời về trình tối ưu hóa cải thiện MySQL 6.0, cảm ơn –

2

Taken từ Reference Manual (14.2.10.11 Rewriting Subqueries as Joins):

Một LEFT [OUTER] THAM GIA có thể nhanh hơn nhiều so với một subquery tương đương vì máy chủ có thể có thể tối ưu hóa nó tốt hơn-một thực tế là không phải là đặc trưng cho MySQL Server một mình.

Vì vậy, truy vấn phụ có thể chậm hơn LEFT [OUTER] JOINS.

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