having子句中使用max/min优化查询

slwdgvem  于 2021-06-20  发布在  Mysql
关注(0)|答案(3)|浏览(430)

我有一个查询在我们的服务器上需要17-20秒,我想看看我能做些什么来优化它。MySQL5.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\u消息和pm\u索引中的中间列都是这两个表中的主键。这个表每个表有数百万条记录

select count(*) from pm_message;
3748290

select count(*) from pm_index;
6938947

对改进这个查询有什么建议吗?
我想知道把pm\u index表中的'deleted'列作为索引是否有帮助?

vwhgwdsa

vwhgwdsa1#

我将完全重写查询,因为您基本上需要一个在特定范围内删除的不同MID的列表。您不需要显示来自 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 table。

sdnqo3pr

sdnqo3pr2#

试试这个。它把事情翻了个底朝外--从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;

我怀疑这是否会有很大帮助——查询似乎需要触及两个表中的几乎所有行。
如果全部 mid pmi中的值肯定存在于 pm ,然后我的 EXISTS 子句可以删除。但是你说两张table都有 PRIMARY KEY(mid) ? 我怀疑 pmi 实际上在pk中有第二列。请提供 SHOW CREATE TABLE .

k2arahey

k2arahey3#

这就详细阐述了影子的答案。试着用两个 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) . 索引非常重要。我把它分成两个条款是因为 OR 可能会混淆查询优化器。

相关问题