在HAVING子句中使用MAX / MIN优化查询

时间:2018-09-02 21:32:49

标签: mysql sql query-optimization

我的查询在我们的服务器上耗时17-20秒,我想看看我能做些什么来对其进行优化。 MySQL 5.6,将在接下来的几个月中升级到5.7。

查询:

SELECT pm.mid AS mid
FROM 
pm_message pm
INNER JOIN pm_index pmi ON pmi.mid = pm.mid
GROUP BY pm.mid
HAVING  (MIN(pmi.deleted) > 0 AND MAX(pmi.deleted) < '1535490002') 
LIMIT 1000 OFFSET 0;

pm_message和pm_index中的中间列都是两个表中的主键。 该表每个都有数百万条记录

select count(*) from pm_message;
3748290

select count(*) from pm_index;
6938947

对改进此查询有何建议?

我想知道是否将pm_index表中的'deleted'列用作索引会有所帮助?

3 个答案:

答案 0 :(得分:1)

我将完全重写查询,因为您基本上想要一个列表,这些列表中删除的范围在一定范围内。您不需要显示pm_index表中的任何数据,因此我将使用关联的子查询与not exists运算符。这样,mysql不必对整个pm_index表进行分组和排序即可获得最小值和最大值。

SELECT pm.mid AS mid
FROM 
pm_message pm
WHERE NOT EXISTS (SELECT 1 FROM pm_index WHERE pm_index.mid=pm.mid and (pm_index.deleted<0 OR pm_index.deleted>1535490002))

该查询将受益于pm_index表的中间和已删除字段上的多列索引。

答案 1 :(得分:1)

这详细说明了Shadows的答案。尝试使用两个$scope.retrieveSelectedClass = function(newValue, oldValue, event) { }子句:

not exists

并确保您在SELECT pm.mid FROM pm_message pm WHERE NOT EXISTS (SELECT 1 FROM pm_index pmi WHERE pmi.mid = pm.mid AND pmi.deleted < 0 ) AND NOT EXISTS (SELECT 1 FROM pm_index pmi WHERE pmi.mid = pm.mid AND pmi.deleted > 1535490002 ) ; 上有一个索引。该索引非常重要。我将其分为两个子句,因为pm_index(mid, deleted)会混淆查询优化器。

答案 2 :(得分:0)

尝试一下。它可以将事情彻底解决-从pmi开始,然后最大程度地减少对pm的接触。

SELECT  mid, MIN(deleted) AS mind, MAX(deleted) AS maxd
    FROM  pm_index AS pmi
    GROUP BY  mid
    HAVING  mind > 0
      AND  maxd < '1535490002'
      AND  EXISTS (
            SELECT  1
                FROM  pm
                WHERE  mid = pmi.mid 
                  )
    LIMIT  1000 OFFSET 0;

我怀疑这是否会有帮助-查询似乎需要触摸两个表中的几乎所有行。

如果pmi中的 all 所有mid值确实存在于pm中,则可以删除我的EXISTS子句。但是,您说两个表都有PRIMARY KEY(mid)吗?我怀疑pmi的PK中实际上还有第二列。 请提供SHOW CREATE TABLE