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

bra*_*ido 14 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
Run Code Online (Sandbox Code Playgroud)

这是我计划在我的视图中使用的有问题的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;
Run Code Online (Sandbox Code Playgroud)

解释输出:

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
Run Code Online (Sandbox Code Playgroud)

另一个例子,这次使用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;
Run Code Online (Sandbox Code Playgroud)

解释输出:

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   
Run Code Online (Sandbox Code Playgroud)

pio*_*trm 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
Run Code Online (Sandbox Code Playgroud)

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

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

WHERE ls.signature_md5='75f8a5b1176ecc2487b90bacad9bc4c'
Run Code Online (Sandbox Code Playgroud)

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