2009-11-19 33 views
6

Tôi có câu hỏi như thế này:Tôi có thể buộc mysql thực hiện truy vấn con đầu tiên không?

SELECT `table_1`.* from `table_1` 
    INNER JOIN `table_2` [...] 
    INNER JOIN `table_3` [...] 
WHERE `table_1`.`id` IN(
    SELECT `id` FROM [...] 
) 
AND [more conditions] 

Khi tôi sử dụng giải thích, đó là 'subquery THUỘC' ở cuối, nhưng tôi muốn subquery này được thực hiện đầu tiên, trước khi các điều kiện khác.

Có thể không?

Trả lời

2

Bạn có thể chọn kết quả truy vấn phụ vào bảng tạm thời trước rồi sau đó tham gia vào truy vấn chính trong truy vấn chính.

2

Cách tốt nhất là đặt điều kiện WHERE cho bảng1 vào truy vấn phụ trong mệnh đề FROM. EG:

SELECT `table_1`.* 
FROM (
     SELECT * FROM `table_1` WHERE `table_1`.`id` IN (...) 
    ) 
    INNER JOIN `table_2` [...] 
    INNER JOIN `table_3` [...] 
WHERE [more conditions] 
-1

Thật không may, không, bạn không thể. Các truy vấn phụ thực sự chạy một lần cho mỗi hàng trong truy vấn bên ngoài.

Tôi thực sự khuyên bạn nên chuyển đổi điều này thành một lần gia nhập khác, sử dụng table_1.id làm chìa khóa của bạn cho bảng khác.

13
SELECT `table_1`.* 
FROM `table_1` 
INNER JOIN 
     `table_2` [...] 
INNER JOIN 
     `table_3` [...] 
WHERE `table_1`.`id` IN 
     (
     SELECT `id` 
     FROM [...] 
     ) 
     AND [more conditions] 

Nếu bảng bên trong được lập chỉ mục đúng, truy vấn phụ ở đây không được "thực hiện" một cách nghiêm ngặt.

Do truy vấn phụ là một phần của biểu thức IN, điều kiện được đẩy vào truy vấn con và nó được chuyển thành một EXISTS.

Trong thực tế, subquery này được đánh giá trên mỗi bước:

EXISTS 
(
SELECT NULL 
FROM [...] 
WHERE id = table1.id 
) 

Bạn thực sự có thể nhìn thấy nó trong mô tả chi tiết được cung cấp bởi EXPLAIN EXTENDED.

Đó là lý do tại sao nó được gọi là DEPENDENT SUBQUERY: kết quả của mỗi đánh giá tùy thuộc vào giá trị của table1.id. Truy vấn phụ như vậy không tương quan, đó là phiên bản được tối ưu hóa tương quan.

MySQL luôn đánh giá mệnh đề EXISTS sau các bộ lọc đơn giản hơn (vì chúng dễ đánh giá hơn nhiều và có khả năng truy vấn phụ sẽ không được đánh giá).

Nếu bạn muốn subquery được đánh giá tất cả cùng một lúc, viết lại các truy vấn như thế này:

SELECT table_1.* 
FROM (
     SELECT DISTINCT id 
     FROM [...] 
     ) q 
JOIN table_1 
ON  table_1.id = q.id 
JOIN table_2 
ON  [...] 
JOIN table_3 
ON  [...] 
WHERE [more conditions] 

Điều này buộc các subquery được hàng đầu trong tham gia, đó là hiệu quả hơn nếu subquery là nhỏ so đến table_1 và kém hiệu quả hơn nếu truy vấn con lớn hơn so với table_1.

Nếu có chỉ mục trên [...].id được sử dụng trong truy vấn phụ, truy vấn phụ sẽ được thực hiện bằng cách sử dụng INDEX FOR GROUP-BY.

+0

Vấn đề với việc đẩy truy vấn con xuống là điều này là không thể nếu truy vấn con phụ thuộc vào một phần không đổi của truy vấn bên ngoài (xem https://stackoverflow.com/questions/44859809/how-to-optimize-dependent-subquery -with-constant-expression) – andig

3

đây là một lỗi được biết đến trong mysql: http://bugs.mysql.com/bug.php?id=25926

một workaround hữu ích là để đẩy xuống subquery vào một select * from (subquery) as dt loại subquery.

+0

Lỗi bạn đề cập chỉ ảnh hưởng đến các truy vấn con 'GROUP BY/DISTINCT'. Một vị từ 'IN' trên truy vấn con với mệnh đề' DISTINCT' trong nó tương đương với 'JOIN'. – Quassnoi

+1

không, sự cố cũng xảy ra trong các truy vấn không liên quan đến 'GROUP BY' hoặc' DISTINCT'. disproving điều này rất đơn giản: đẩy truy vấn con xuống một cấp độ khác như tôi đề xuất và xem liệu SUBENDERY DEPENDENT có thay đổi thành bảng DERIVED hay không. (và làm thế nào để bạn biết truy vấn này không có GROUP BY? áp phích ban đầu không cung cấp truy vấn thực tế.) – longneck

+0

Cách giải quyết đó có hiệu quả đối với tôi: truy vấn mất 32 phút xuống còn 0,452 giây. Cảm ơn! – Deebster

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