MySQL查询改进(Tmp表,发送数据和排序)

时间:2014-05-20 20:56:00

标签: mysql performance

我的查询如下:

    SELECT Sender, Recipient, Sent 
FROM 
     (SELECT Sender, Recipient, Sent FROM prv_chat WHERE 100 IN (Sender, Recipient)) 
     AS chat 
GROUP BY Sender, Recipient 
ORDER BY Sent DESC LIMIT 30

它的目的是搜索发送或接收的特定用户(在这种情况下是ID为100的用户)的所有聊天消息(inner query

此查询在我的服务器上频繁运行,占用了大量时间(>0.1s
phpMyAdmin分析工具显示Copying to tmp table约占32%的时间(我猜它是由内部查询引起的),Sending data约占30%(缺少索引?),另有30%由Sorting results

DESCRIBING查询告诉我它没有使用任何索引(虽然它说有可能的索引)

以下是完整列表: Indexes

任何人都有线索?

修改

SHOW CREATE TABLE prv_chat

CREATE TABLE `prv_chat` (
 `ID` int(11) NOT NULL AUTO_INCREMENT,
 `Sender` int(9) NOT NULL,
 `Recipient` int(9) NOT NULL,
 `Chat` text NOT NULL,
 `Sent` datetime NOT NULL,
 `Read` tinyint(1) NOT NULL,
 PRIMARY KEY (`ID`),
 KEY `Sender` (`Sender`,`Recipient`),
 KEY `Sent` (`Sent`),
 KEY `Sender_3` (`Sender`,`Recipient`,`Sent`),
 KEY `Sender_2` (`Sender`,`Sent`),
 KEY `Recipient` (`Recipient`)
) ENGINE=MyISAM AUTO_INCREMENT=125082 DEFAULT CHARSET=utf8

EDIT2:我编辑了查询,现在sorting results部分已被删除。 虽然Sending resultsCopying to tmpo table进度仍然占用了大量时间

EDIT3:再次更改了查询。现在,花费很多时间的唯一部分是Sending data
DESCRIBE返回此信息: DESCRIBE

对于Xint0的查询,

编辑4: DESCRIBEDESCRINE 2

3 个答案:

答案 0 :(得分:0)

运算符OR使mysql忽略索引。请尝试改为:

SELECT * FROM(
    SELECT *  FROM prv_chat WHERE Sender=100 
    UNION ALL
    SELECT *  FROM prv_chat WHERE Recipient=100 
) AS chat
ORDER BY Sent DESC LIMIT 30; --done by hand, may not run

答案 1 :(得分:0)

编辑:查询设计中的逻辑错误。为子查询提供新建议

SELECT *
FROM prv_chat 
WHERE 100 IN (Sender, Recipient) 
ORDER BY Sent DESC;

这应该适用于您当前正在检索的内容。

100 IN (Sender, Recipient)位也会使用您的Sender_3密钥

编辑:您可能还想查看表格的InnoDB引擎

答案 2 :(得分:0)

正如您在评论中提到的,问题是使用*选择所有列。作为一般建议,如果不需要,请尽量不要选择所有列。

我建议:

select Sender, Recipient, MaxSent
from (
    select pc.Sender, pc.Recipient, max(pc.Sent) as MaxSent
    from
        prv_chat pc
        inner join (
            select ID from prv_chat where Sender = 100
            union
            select ID from prv_chat where Recipient = 100
        ) f on pc.ID = f.ID
    group by pc.Sender, pc.Recipient
) g
order by MaxSent desc limit 100;

这样,子查询f会按发件人和收件人过滤ID并使用相应的索引。

然后,发件人,收件人的子查询g组获取最大发送值,应使用索引Sender_3。

外部查询仅对已过滤和分组的结果进行排序。

修改

看到DESCRIBE输出后,似乎g子查询未使用Sender_3索引。我建议首先运行analyze table prv_chat;命令来更新索引统计信息,以便MySQL引擎可以根据当前索引覆盖率优化查询。如果这不会导致引擎使用Sender_3索引,请尝试修改它以包含ID作为第一列:(ID, Sender, Recipient, Sent)

<强> EDIT2

我认为临时表和filesort是由聚合结果排序引起的。