2011-05-02 32 views
13

我打算使用此SQL SELECT创建视图,但解释为它显示它正在使用临时文件和使用filesort。我无法弄清楚我需要什么指数来解决这个问题。大多数情况下,我想知道为什么它使用filesort intead来使用索引进行排序。MySQL解释:什么导致'使用临时;使用filesort'

这里是我的表:

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; 

Explain输出:

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 
+1

发布EXPLAIN输出,发布您的CREATE VIEW语句。 – 2011-05-02 15:30:30

+0

好点,我只是添加了解释输出。我还没有创建视图,我想优化SELECT首先 – bradvido 2011-05-02 15:39:13

+2

那么这里究竟有什么错误?您没有限制数据集的因素,整个learning_signatures表将被拉下。使用临时可能是因为你的innodb_buffer_pool大小。 – 2011-05-02 15:49:27

回答

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指数groupping中,派生表将不会大于您的签名表,并且您使用唯一列来加入这两个表。 您仍然需要对签名表进行全面扫描,但无法避免,因为无论如何您都要选择它。

至于第二个查询,如果你想限制签名单一个只是追加

WHERE ls.signature_md5='75f8a5b1176ecc2487b90bacad9bc4c' 

仅通过s.ch先前的查询和组的结束,因为只有一个signature_id将匹配您的无论如何,MD5。优化器现在应该使用md5索引来为where和char_index进行分组。

+0

非常好。这很有效,优化器按照您的查询描述的方式工作。感谢您的详细解释,我现在看到了不同之处。 – bradvido 2011-05-03 13:55:52

0

也许如果你创建一个包含两个signature_md5和signature_id learning_signatures的索引,它会帮助(和顺序)

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

我不是MySQL的专家,但我发现,封装where子句和连接子句的创建密钥通常有助于摆脱临时和文件夹

+0

感谢您的提示,但我只是试过了,它并没有摆脱临时文件或文件夹。 – bradvido 2011-05-02 16:23:03

-1

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

如果您拥有大部分只写数据库(读取次数很少),则可能需要避免使用索引,因为它们可能会对写入性能产生负面影响。

相关问题