优化表以避免使用临时文件并使用filesort

时间:2016-06-04 01:44:00

标签: mysql sql optimization

我有一个消息表

CREATE TABLE `messages` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `author` int(11) DEFAULT NULL,
  `time` int(10) unsigned DEFAULT NULL,
  `text` text CHARACTER SET latin1,
  `dest` int(11) unsigned DEFAULT NULL,
  `type` tinyint(4) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `author` (`author`),
  KEY `dest` (`dest`)
) ENGINE=InnoDB AUTO_INCREMENT=2758 DEFAULT CHARSET=utf8;

我需要在两个用户之间收到消息

SELECT
    ...
FROM
    `messages` m
LEFT JOIN `people` p ON m.author = p.id
WHERE
    (author = 1 AND dest = 2)
OR (author = 2 AND dest = 1)
ORDER BY
    m.id DESC
LIMIT 0, 25

当我解释此查询时,我得到了

enter image description here

请原谅任何无知,但有没有办法我可以优化这个表,以避免为此查询使用临时表和filesort,现在它不会导致问题,但我很确定将来它会麻烦吗?

2 个答案:

答案 0 :(得分:3)

首先,我猜测left join没有必要。其次,请考虑使用union all。然后一种方法是:

(SELECT ...
 FROM messages m JOIN
      people p
      ON m.author = p.id
 WHERE author = 1 AND dest = 2
 ORDER BY id DESC
 LIMIT 25
)
UNION ALL
(SELECT ...
 FROM messages m JOIN
      people p
      ON m.author = p.id
 WHERE author = 2 AND dest = 1
 ORDER BY id DESC
 LIMIT 25
)
ORDER BY m.id DESC
LIMIT 0, 25

使用此查询,messages(author, dest, id)上的索引应该使其快速。 (注意:您可能需要在m.id列表中添加SELECT。)

答案 1 :(得分:0)

以戈登的答案为基础:

SELECT  m2..., p...
    FROM
    ( 
      ( SELECT  id
            FROM  messages
            WHERE  author = 1
              AND  dest = 2
            ORDER BY  id DESC
            LIMIT  75 
      )
    UNION  ALL
      (
        SELECT  id
            FROM  messages
            WHERE  author = 2
              AND  dest = 1
            ORDER BY  id DESC
            LIMIT  75 
      )
    ) ORDER BY  id DESC
    LIMIT  50, 25 ) AS m1
    JOIN  messages AS m2  ON m2.id = m1.id
    JOIN  people p  ON p.id = m2.author
    ORDER BY  m1.id DESC

注意:

  • 戈登的索引现在正在"覆盖"。 (这增加了效率,从而掩盖了我添加的其他一些东西。)
  • 懒惰评估意味着它不需要铲除周围超过25行的所有庞大的字段。相反,只需要处理25个。此外,我避免触及people开始。
  • 代码显示"第3页"应该是这样的。请注意LIMIT 75LIMIT 50,25
  • "通过OFFSET"分页;有几个问题。见my blog
  • 这个配方仍然不会避免" filesort"和"使用temp"。但速度才是真正的目标,对吗? (" Filesort"用词不当 - 如果您不包含TEXT列,则排序将在RAM中完成。)
  • 当您添加INDEX(author, dest, id)时,INDEX(author)变得多余;放下它。
  • ALL之后的UNION不是UNION的默认值,但它避免了额外的传递(和临时表)来重复数据。
  • 仍然会涉及2或3个临时表。有关详细信息,请参阅EXPLAIN FORMAT=JSON SELECT ...