使用WHERE IN进行查询优化

时间:2010-06-04 15:37:56

标签: mysql query-optimization where-in

我想知道是否有人可以解释IN如何计算?好吧,最终我试图找出为什么这个查询很慢以及如何优化它。我等了3分多钟,当我取消查询时,它只返回了1000行,看起来好像不应该花那么长时间。

SELECT t2.* 
FROM report_tables.roc_test_results as t2 
WHERE t2.job IN (SELECT DISTINCT(t1.job) 
                   FROM report_tables.roc_test_results as t1 
                  WHERE t1.operation = 'TEST' 
                    AND result = 'Passed' 
                    AND STR_TO_DATE(t1.date_created,'%d-%M-%Y') BETWEEN '2009-10-01' 
                                                                    AND '2009-10-31')

我不确定总查询应该返回什么,如果我不得不猜测我会说大约2000条记录,则子查询返回332(当不是Distinct时为336)。

有人能给我一些关于如何优化此查询的指示吗?另外,我想知道,子查询是每次计算还是只计算一次并存储它?

根据要求,DESC的结果......(顺便说一句,请不要笑,我自学,所以我确信这张桌子的设计很有可能。)

Field                     Type               Null     Key    Default    Extra
------                      -----              -----     ---    -------    -----
operation                 varchar(10)         NO   
tester                 varchar(25)            NO   
result                 varchar(45)            NO   
fail_mode              varchar(45)         NO   
primary_failure        varchar(25)           NO   
ref_des                varchar(45)           NO   
rf_hours               varchar(15)          NO   
ac_hours               varchar(15)          NO   
comments               text              NO   
job                    varchar(15)           NO   
rma                    bigint(20) unsigned    NO   
item                   varchar(45)          NO   
item_description       text                  NO   
serial                 varchar(25)            NO   
created_by             varchar(25)            NO   
collection             bigint(20) unsigned    NO    PRI  
date_created           varchar(15)          NO   

3 个答案:

答案 0 :(得分:1)

date_created数据类型需要更改为DATETIME才值得在列上定义索引。原因是,如果您正在将数据类型从字符串更改为DATETIME,那么索引将毫无价值。

您已经提到过您正在使用LOAD DATA INFILE,并且源文件包含DD-MON-YY格式的日期。 MySQL will implicitly convert strings into DATETIME if the YY-MM-DD format is used,因此如果您在使用LOAD DATA INFILE之前可以在源文件中更正此内容,则其他内容应该放在原位。

之后,covering index使用:

  • 工作
  • 操作
  • 结果
  • DATE_CREATED

......会是一个好主意。

答案 1 :(得分:0)

首先,您不需要子查询中的distinct,因为IN无论如何都会消除重复 您是否需要WHERE子句中的函数调用,并且您是否拥有date_created列的索引?

更改时会发生什么

WHERE STR_TO_DATE(t1.date_created,'%d-%M-%Y') 
BETWEEN '2009-10-01' AND '2009-10-31')

WHERE 1.date_created >= '2009-10-01' 
AND 1.date_created < '2010-01-01'

如果使用列

上的函数,有时不会使用索引

答案 2 :(得分:0)

我的建议是用JOIN替换IN,然后考虑在某些列上添加索引,例如作业,可能还有操作和/或结果。您应该阅读MySQL手册中的索引,以及使用EXPLAIN来优化查询:

http://dev.mysql.com/doc/refman/5.1/en/indexes.html

http://dev.mysql.com/doc/refman/5.1/en/using-explain.html

以下是将IN转换为JOIN的示例:

SELECT distinct t2.* 
FROM roc_test_results as t2
inner join roc_test_results as t1 on t1.job = t2.job
WHERE t1.operation = 'TEST' 
AND t1.result = 'Passed' 
AND STR_TO_DATE(t1.date_created,'%d-%M-%Y') BETWEEN '2009-10-01' AND '2009-10-31';