MySQL解释:导致'使用临时;使用filesort'

时间:2011-05-02 15:28:50

标签: mysql explain filesort

我打算使用这个SQL SELECT创建一个视图,但是它的解释显示它使用临时和使用filesort。我无法弄清楚我需要什么指数才能解决这个问题。 大多数情况下,我想知道它为什么使用fileort intead使用索引进行排序。

以下是我的表格:

CREATE TABLE `learning_signatures` (
  `signature_id` int(11) NOT NULL AUTO_INCREMENT,
  `signature_file` varchar(100) NOT NULL,
  `signature_md5` varchar(32) NOT NULL,
  `image_file` varchar(100) NOT NULL,
  PRIMARY KEY (`signature_id`),
  UNIQUE KEY `unique_signature_md5` (`signature_md5`)
) ENGINE=InnoDB AUTO_INCREMENT=640 DEFAULT CHARSET=latin1

CREATE TABLE `learning_user_suggestions` (
  `user_suggestion_id` int(11) NOT NULL AUTO_INCREMENT,
  `signature_id` int(11) NOT NULL,
  `ch` char(1) NOT NULL,
  `time_suggested` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `user_id` int(11) NOT NULL,
  PRIMARY KEY (`user_suggestion_id`),
  KEY `char_index` (`ch`),
  KEY `ls_sig_id_indx` (`signature_id`),
  KEY `user_id_indx` (`user_id`),
  KEY `sig_char_indx` (`signature_id`,`ch`)
) ENGINE=InnoDB AUTO_INCREMENT=1173 DEFAULT CHARSET=latin1

这是我计划在我的视图中使用的有问题的SQL语句:

select ls.signature_id, ls.signature_file, ls.signature_md5, ls.image_file, sug.ch , count(sug.ch) AS suggestion_count
from (`learning_signatures` `ls` left join `learning_user_suggestions` `sug` on(ls.signature_id = sug.signature_id))
group by ls.signature_id, sug.ch;

解释输出:

id  select_type table   type    possible_keys                   key             key_len ref                 rows    Extra
1   SIMPLE      ls      ALL     NULL                            NULL            NULL    NULL                514     "Using temporary; Using filesort"
1   SIMPLE      sug     ref     ls_sig_id_indx,sig_char_indx    ls_sig_id_indx  4       wwf.ls.signature_id 1

另一个例子,这次使用where子句:

explain select ls.signature_id, ls.signature_file, ls.signature_md5, ls.image_file, sug.ch , count(sug.ch) AS suggestion_count
from (`learning_signatures` `ls` left join `learning_user_suggestions` `sug` on(ls.signature_id = sug.signature_id))
WHERE signature_md5 = '75f8a5b1176ecc2487b90bacad9bc4c'
group by ls.signature_id, sug.ch;

解释输出:

id  select_type table   type    possible_keys                key                    key_len ref     rows    Extra
1   SIMPLE      ls      const   unique_signature_md5         unique_signature_md5   34      const   1       "Using temporary; Using filesort"
1   SIMPLE      sug     ref     ls_sig_id_indx,sig_char_indx ls_sig_id_indx         4       const   1   

3 个答案:

答案 0 :(得分:18)

在第一个查询中,您要做的是将您的签名表与用户建议结合,获取大量行,然后使用用户建议中的某些列对结果进行分组。但是联接表没有索引来帮助分组,因为它必须在以前连接的表上定义。 你应该做的是尝试从已经由ch和signature_id分组的用户建议创建派生表,然后加入它:

SELECT ls.signature_id, ls.signature_file, ls.signature_md5, ls.image_file, 
       sug.ch, sug.suggestion_count
FROM learning_signatures ls
LEFT JOIN 
  (SELECT s.signature_id, s.ch, count(s.ch) as suggestion_count
    FROM learning_user_suggestions s 
    GROUP BY s.signature_id, s.ch ) as sug
ON ls.signature_id = sug.signature_id

优化器现在应该能够使用您的sig_char_indx索引进行灌浆,派生表将不会大于您的签名表,并且您使用唯一列加入两者。 您仍然需要对签名表进行全面扫描,但这是无法避免的,因为您无论如何都要选择所有这些。

对于第二个查询,如果要将签名限制为单个签名,只需附加

WHERE ls.signature_md5='75f8a5b1176ecc2487b90bacad9bc4c'

到上一个查询的结尾并仅按s.ch分组,因为只有一个signature_id会匹配你的md5。优化器现在应该使用md5索引where和char_index进行分组。

答案 1 :(得分:0)

如果您在learning_signatures上创建包含signature_md5和signature_id(并按此顺序)的索引,那么它可能会有所帮助

`KEY `md5_id` (`signature_md5`,`signature_id`)?

我不是MySQL专家,但我发现创建的密钥同时封装了where子句和join子句通常有助于摆脱临时和filesort

答案 2 :(得分:-1)

使用索引。在您的查询中使用EXPLAIN找到您需要的字段。

如果你有一个大多数只写DB(少量读取),你可能想避免使用索引,因为它们可能会对你的写入性能产生负面影响。