我打算使用这个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
答案 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(少量读取),你可能想避免使用索引,因为它们可能会对你的写入性能产生负面影响。