如何在mysql中优化这个sql

时间:2013-07-23 08:36:36

标签: mysql

我有一个像这样的SQL:

select t1.id,t1.type from collect t1 
 where t1.type='1' and t1.status='1' 
    and t1.total>(t1.totalComplate+t1.totalIng)  
    and id not in(
             select tid from collect_log t2 
              where t2.tid=t1.id and t2.bid='1146') 
limit 1;

没关系,但是如果我使用订单命令,它的性能似乎不太好:

select t1.id,t1.type from collect t1 
 where t1.type='1' and t1.status='1' 
    and t1.total>(t1.totalComplate+t1.totalIng)  
    and id not in(
             select tid from collect_log t2 
              where t2.tid=t1.id and t2.bid='1146') 
order by t1.id asc 
limit 1;
它变得更糟。 我该如何优化呢?

这里有解释:

id | select_type        | table | type | possible_keys | key | key_len | ref             | rows | Extra                       |
+----+--------------------+-------+------+---------------+-----+---------+-----------------+------+-----------------------------+
|  1 | PRIMARY            | t1    | ref  | i2,i1,i3      | i1  | 4       | const,const     |   99 | Using where; Using filesort |
|  2 | DEPENDENT SUBQUERY | t2    | ref  | i5            | i5  | 65      | img.t1.id,const |    2 | Using where; Using index 

2 个答案:

答案 0 :(得分:1)

1)如果尚未完成,请在collect.id列上定义索引:

CREATE INDEX idx_collect_id ON collect (id);

如果可以的话,或者可能是唯一的索引(如果id对于任何两行都不相同):

CREATE UNIQUE INDEX idx_collect_id ON collect (id);

也许您需要collect_log.tidcollect_log.bid上的索引。或者甚至在两个列上,如下:

CREATE INDEX idx_collect_log_tidbid ON collect (tid, bid);

如果有意义的话,将其设为UNIQUE,也就是说,如果表中的(tid,bid)对没有两行具有相同的值。例如,如果这些查询给出相同的结果,那么可能

SELECT count(*) FROM collect_log;

SELECT count(DISTINCT tid, bid) FROM collect_log;

但如果你不确定它意味着什么,不要让它变得独一无二。

2)验证列collect.typecollect.statuscollect_log.bid的类型。在您的查询中,您将它们与字符串进行比较,但它们可能被定义为INT(或SMALLINTTINYINT ...)?在这种情况下,我建议你删除数字周围的引号,因为与整数比较相比,字符串比较非常缓慢。

select t1.id,t1.type from collect t1 
 where t1.type=1 and t1.status=1 
    and t1.total>(t1.totalComplate+t1.totalIng)  
    and id not in(
             select tid from collect_log t2 
              where t2.tid=t1.id and t2.bid=1146) 
order by t1.id asc 
limit 1;

3)如果仍然没有帮助,只需在查询前添加EXPLAIN,即可获得执行计划。将结果粘贴到此处,我们可以帮助您理解它。实际上,我建议你在创建任何新索引之前执行这一步。

答案 1 :(得分:-1)

我首先尝试使用 INNER IN删除LEFT JOIN语句。

像这样(未经测试):

select t1.id,t1.type 
from collect t1 
    LEFT JOIN collect_log t2 ON t1.id = t2.tid
where t1.type='1' 
    and t1.status='1' 
    and t1.total>(t1.totalComplate+t1.totalIng)  
    and NOT t2.bid = '1146'
order by t1.id asc 
limit 1;