2010-08-05 25 views
12

CẬP NHẬT:Truy vấn SELECT này mất 180 giây để hoàn thành

Chỉ cần đề cập đến nó ở một nơi dễ thấy hơn. Khi tôi thay đổi IN cho =, thời gian thực hiện truy vấn đã giảm từ 180 xuống còn 0,00008 giây. Khác biệt tốc độ vô lý.


Truy vấn SQL này mất 180 giây để hoàn tất! Làm thế nào là có thể? có cách nào để tối ưu hóa nó nhanh hơn không?

SELECT IdLawVersionValidFrom 
FROM question_law_version 
WHERE IdQuestionLawVersion IN 
    (
    SELECT MAX(IdQuestionLawVersion) 
    FROM question_law_version 
    WHERE IdQuestionLaw IN 
    (
    SELECT MIN(IdQuestionLaw) 
    FROM question_law 
    WHERE IdQuestion=236 AND IdQuestionLaw>63 
    ) 
) 

Chỉ có khoảng 5000 hàng trong mỗi bảng nên không quá chậm.

+5

Bất kỳ sự khác biệt nếu bạn thay đổi 'IN' cho '='? –

+7

Những tên cột đó làm tổn thương não tôi. Bạn có thể giải thích những gì các truy vấn được cho là phải làm gì? – RedFilter

+0

@ Martin Smith nó sẽ là đáng ngạc nhiên (và giáo dục cho tôi) nếu nó làm cho bất kỳ sự khác biệt. –

Trả lời

16

Bất kỳ sự khác biệt nếu bạn thay đổi IN đến =?

Nếu có ai muốn điều tra thêm về điều này, tôi vừa mới thực hiện kiểm tra và thấy rất dễ tái sản xuất.

Tạo Bảng

CREATE TABLE `filler` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY (`id`) 
) 

Tạo Thủ tục

CREATE PROCEDURE `prc_filler`(cnt INT) 
BEGIN 
     DECLARE _cnt INT; 
     SET _cnt = 1; 
     WHILE _cnt <= cnt DO 
       INSERT 
       INTO filler 
       SELECT _cnt; 
       SET _cnt = _cnt + 1; 
     END WHILE; 
END 

cư Bảng

call prc_filler(5000) 

Query 1

SELECT id 
FROM filler 
WHERE id = (SELECT MAX(id) FROM filler WHERE id = 
(SELECT MIN(id) 
    FROM filler 
    WHERE id between 2000 and 3000 
    ) 
) 

Equals Explain Output http://img689.imageshack.us/img689/5592/equals.png

Query 2 (cùng một vấn đề)

SELECT id 
FROM filler 
WHERE id in (SELECT MAX(id) FROM filler WHERE id in 
(SELECT MIN(id) 
    FROM filler 
    WHERE id between 2000 and 3000 
    ) 
) 

In Explain Output http://img291.imageshack.us/img291/8129/52037513.png

+0

Tôi tò mò muốn một số chuyên gia MySQL bình luận về sự khác biệt về hiệu năng. Rõ ràng các truy vấn con sẽ trả về 1 hàng để chỉ bằng với toán tử đúng, nhưng tại sao sử dụng IN tạo ra sự khác biệt lớn về hiệu suất khi nó chỉ kiểm tra nếu giá trị được tìm thấy trong kết quả 1 hàng? – wadesworld

+3

@Wade - Câu trả lời của Mark ở đây đã bao hàm tôi nghĩ rằng http://stackoverflow.com/questions/3417074/why-would-an-in-condition-be-slower-than-in-sql/3417190#3417190 –

12

Here is a good explanation why = is better than IN

Mysql có vấn đề với các truy vấn bên trong - không được sử dụng chỉ số (nếu có).

  1. Hãy chắc chắn rằng bạn có chỉ số trên tất cả các lĩnh vực trong tham gia/nơi/trật tự, vv
  2. có được những giá trị Max và MIN trong một truy vấn riêng biệt (sử dụng thủ tục lưu trữ cho toàn bộ điều này nếu bạn muốn bỏ qua các yêu cầu nhiều overhead Hoặc chỉ cần làm một yêu cầu với nhiều truy vấn

Dù sao:.

SELECT 
     IdLawVersionValidFrom 
FROM 
     question_law_version 
    JOIN 
     question_law 
     ON 
     question_law_version.IdQuestionLaw = question_law.IdQuestionLaw 
WHERE 
     question_law.IdQuestion=236 
    AND 
     question_law.IdQuestionLaw>63 

ORDER BY 
     IdQuestionLawVersion DESC, 
     question_law.IdQuestionLaw ASC 
LIMIT 1 
+0

+1 Tôi có nghĩa là để đề cập đến chỉ số, nhưng ... bằng cách nào đó ... không :) – Unreason

+0

Thật ra, nhận xét của Martin Smith là câu trả lời đúng. –

+0

@Richard Knop - Truy vấn của tôi có làm việc cho bạn hay không? –

4

Bạn có thể sử dụng EXPLAIN để tìm hiểu thế nào là nó có thể cho một truy vấn để thực thi quá chậm.

MySQL không thực sự thích lựa chọn lồng nhau vì vậy có lẽ điều xảy ra là nó đi và không sắp xếp trên đĩa để lấy min và max và không sử dụng lại kết quả.

Viết lại như tham gia có thể sẽ giúp ích.

Nếu chỉ tìm kiếm một giải pháp thử nhanh: (! Gửi bài bình luận của tôi như là một câu trả lời như dường như nó đã tạo sự khác biệt)

SET @temp1 =  
    (
    SELECT MIN(IdQuestionLaw) 
    FROM question_law 
    WHERE IdQuestion = 236 AND IdQuestionLaw > 63 
) 

SET @temp2 = 
    (
    SELECT MAX(IdQuestionLawVersion) 
    FROM question_law_version 
    WHERE IdQuestionLaw = @temp1 
) 

SELECT IdLawVersionValidFrom 
FROM question_law_version 
WHERE IdQuestionLawVersion = @temp2 
+0

Thật ra, nhận xét của Martin Smith là câu trả lời đúng. –

+0

Hoàn toàn đồng ý và đã +1 cho điều đó. Đừng chú ý đến việc anh ta sử dụng 'EXPLAIN' :) – Unreason

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