使用带有IN子句的嵌套子查询提高MySQL查询的性能

时间:2014-07-15 19:17:18

标签: mysql sql performance

我想提高以下查询的效果。

SELECT  DISTINCT StringId 
FROM    translations 
WHERE   status = 1  
AND     TranslationId IN 
( 
    SELECT  Max(TranslationId) 
    FROM    translations  
    WHERE   languageId = 2 
    AND     TranslationId > 0  
    GROUP BY StringId;

此查询目前需要永远,因为In子句。

以下子查询

SELECT  Max(TranslationId) 
FROM    translations  
WHERE   languageId = 2 
AND     TranslationId > 0  
GROUP BY StringId;

返回16,000行,带有16,000行的IN子句需要这么长时间。

我提出的改进查询是

SELECT  DISTINCT t1.StringId 
FROM    translations t1 
INNER JOIN 
(   
    SELECT  Max(TranslationId) MaxTranslationId, 
            StringId 
    FROM    translations  
    WHERE   languageId = 2 
    AND     TranslationId > 0  
    GROUP BY StringId
) t2    ON  t1.StringId = t2.StringId 
        AND t1.TranslationId = t2.MaxTranslationId 
WHERE   status = 1;

我希望内连接只返回与StringId和Max(TranslationId)匹配的行,就像使用In子句一样。

如果这是一种正确的方法,有人可以给我一个答案吗?

1 个答案:

答案 0 :(得分:2)

以下是使用NOT EXISTS的替代方法:

SELECT DISTINCT t.StringId 
FROM translations t
WHERE status = 1 AND
      NOT EXISTS (select 1
                  from translations t2
                  where t2.languageId = 2 and
                        t2.StringId = t.StringId and
                        t2.translationId > t.translationId
                 ) AND
      EXISTS (select 1
              from translations t2
              where t2.languageId = 2 and
                    t2.StringId = t.StringId and
                    t2.translationId > 0
                 )

对于性能,您需要translations(StringId, languageId, translationId)上的索引。这消除了其中一个聚合,用索引查找替换它,这可能会更快。

编辑:以上应该有效。但是,这也可能相对有效:

SELECT  DISTINCT StringId 
FROM    translations t
WHERE   status = 1 AND
        t.TranslationId = (SELECT  Max(t2.TranslationId) 
                           FROM    translations t2
                           WHERE   t2.languageId = 2 AND t2.TranslationId > 0 AND
                                   t2.StringId = t.StringId
                          );