此SELECT查询需要180秒才能完成

时间:2010-08-05 15:02:26

标签: sql mysql select

更新:

只是在更加明显的地方提及它。当我将IN更改为=时,查询执行时间从180下降到0.00008秒。可笑的速度差异。


此SQL查询需要180秒才能完成!怎么可能?有没有办法优化它更快?

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
    )
  )

每张表中只有大约5000行,因此它不应该太慢。

3 个答案:

答案 0 :(得分:16)

(将我的评论作为答案发布,因为显然它确实有所作为!)

  

如果更改IN,则有任何区别   到=

如果有人想进一步调查,我刚刚做了一个测试,发现它很容易重现。

创建表

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

创建程序

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

填充表

  call prc_filler(5000)

查询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

查询2(同样的问题)

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

答案 1 :(得分:12)

Here is a good explanation why = is better than IN

Mysql内部查询存在问题 - 不能很好地使用索引(如果有的话)。

  1. 确保您在join / where / order等所有字段中都有索引。
  2. 在单独的查询中获取这些Max和MIN值(如果您想跳过多个请求开销,或者只是使用多个查询执行请求,请使用存储过程完成此事。
  3. 反正:

    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
    

答案 2 :(得分:4)

您可以使用EXPLAIN来了解查询如何执行得如此之慢。

MySQL并不真正喜欢嵌套的子选择,所以可能会发生的事情是它会在磁盘上进行排序以获得最小值和最大值并且无法重用结果。

重写为联接可能会有所帮助。

如果只是寻找快速解决方法,请尝试:

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