Truy vấn con tham gia


158

Tôi đã cấu trúc lại một phần chậm của một ứng dụng mà chúng tôi được thừa hưởng từ một công ty khác để sử dụng một phép nối bên trong thay vì truy vấn con như:

WHERE id IN (SELECT id FROM ...)

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

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

Sự khác biệt nằm ở phần thứ hai của truy vấn "where id in ()" -

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


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

@simhumileco Đó không phải là sự cải thiện, nó không có gì khác biệt, nó trái ngược với những gì tác giả đã viết & loại chỉnh sửa cho kiểu mã là không phù hợp. Khi nào tôi nên chỉnh sửa mã?
philipxy

Xin chào @philipxy, tôi không có ý định can thiệp vào suy nghĩ của tác giả, mà chỉ để làm cho đoạn mã dễ đọc hơn và được viết cẩn thận hơn.
simhumileco

Câu trả lời:


160

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

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


3
Xin lưu ý rằng điều đó DEPENDENT SUBQUERYcó nghĩa chính xác giống như "truy vấn con tương quan".
Timo

38

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


5
Tôi không nghĩ điều này là đúng. Công cụ SQL chỉ nên chạy truy vấn con một lần và sử dụng kết quả làm danh sách.
dacracot

8
Điều đó phụ thuộc - nếu truy vấn con 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ó), thì nó được thực hiện với mỗi hàng.
qbeuek

4
Điều này có thể đúng trong trường hợp này, nhưng nói chung nó không đúng.
Amy B

1
OP EXPLAINnói DEPENDENT SUBQUERY, đó là chỉ số rõ ràng nhất về hành vi này.
Timo


7

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


6

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

Không thể nhìn thấy truy vấn, thật khó để nói điều gì là tồi tệ về bản gốc, nhưng tôi đoán nó sẽ 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

Nhìn vào kế hoạch truy vấn cho mỗi truy vấn.

Thông thường , trongTham gia có thể được thực hiện bằng cách sử dụng cùng một kế hoạch thực hiện, do đó, thông thường không có sự tăng tốc nào khi thay đổi giữa chúng.


3
Haha, tôi <3 Sql sẽ bỏ phiếu vì họ không biết cách đọc các kế hoạch truy vấn.
Amy B

4

Trình tối ưu hóa đã không làm một công việc rất tốt. Thông thường chúng có thể được biến đổi mà không có sự khác biệt và trình tối ưu hóa có thể làm điều này.


4

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


4

Câu hỏi này hơi chung chung, vì vậy đây là một 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 tấn hàng để sắp xếp.

Làm cái này:

Chạy GIẢI THÍCH trên mỗi truy vấn (một truy vấn THAM GIA, sau đó truy vấn) và đăng kết quả tại đâ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 đối với các truy vấn đó sẽ là kinh nghiệm học tập cho mọi người.


4

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


3

Truy vấn con có thể đã 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à vị trí từ truy vấn chính cần lọc ra.

Tất nhiên chỉ là phỏng đoán mà không có chi tiết nhưng đó là tình huống phổ biến.


2

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

Với một phép nối, CHỌN 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 kết quả và tham gia các mối quan hệ là điều mà 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ế tốt hơn của một chỉ mục ngay bây giờ.


2

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


1
nơi thực sự không phải là xấu.
Shawn

2

Lấy từ Tài liệu tham khảo ( 14.2.10.11 Viết lại các truy vấn con khi tham gia ):

MỘT TRÁI PHIẾU [NGOÀI] THAM GIA có thể nhanh hơn một truy vấn con tương đương vì máy chủ có thể tối ưu hóa nó tốt hơn một thực tế không chỉ dành riêng cho Máy chủ MySQL.

Vì vậy, các truy vấn con có thể chậm hơn TRÁI [NGOÀI] THAM GIA.

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.