慢查询,state ='排序结果'mysql

时间:2013-01-04 19:34:12

标签: mysql performance indexing

我已生成查询

select 
    mailsource2_.file as col_0_0_, 
    messagedet0_.messageId as col_1_0_, 
    messageent1_.mboxOffset as col_2_0_, 
    messageent1_.mboxOffsetEnd as col_3_0_, 
    messagedet0_.id as col_4_0_ 
from MessageDetails messagedet0_, MessageEntry messageent1_, MailSourceFile mailsource2_ 
where messagedet0_.id=messageent1_.messageDetails_id 
and messageent1_.mailSourceFile_id=mailsource2_.id 
order by mailsource2_.file, messageent1_.mboxOffset;

说明没有使用完整扫描和索引:

+----+-------------+--------------+--------+------------------------------------------------------+---------+---------+--------------------------------------+------+----------------------------------------------+
| id | select_type | table        | type   | possible_keys                                        |key     | key_len | ref                                  | rows | Extra           |
+----+-------------+--------------+--------+------------------------------------------------------+---------+---------+--------------------------------------+------+----------------------------------------------+
|  1 | SIMPLE      | mailsource2_ | index  | PRIMARY                                              |file    | 384     | NULL                                 | 1445 | Using index; Using temporary; Using filesort |
|  1 | SIMPLE      | messageent1_ | ref    | msf_idx,md_idx,FKBBB258CB60B94D38,FKBBB258CBF7C835B8 |msf_idx | 9       | skryb.mailsource2_.id                | 2721 | Using where           |
|  1 | SIMPLE      | messagedet0_ | eq_ref | PRIMARY                                              |PRIMARY | 8       | skryb.messageent1_.messageDetails_id |    1 |           |
+----+-------------+--------------+--------+------------------------------------------------------+---------+---------+--------------------------------------+------+----------------------------------------------+


CREATE TABLE `mailsourcefile` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `file` varchar(127) COLLATE utf8_bin DEFAULT NULL,
  `size` bigint(20) DEFAULT NULL,
  `archive_id` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `file` (`file`),
  KEY `File_idx` (`file`),
  KEY `Archive_idx` (`archive_id`),
  KEY `FK7C3F816ECDB9F63C` (`archive_id`),
  CONSTRAINT `FK7C3F816ECDB9F63C` FOREIGN KEY (`archive_id`) REFERENCES `archive` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1370 DEFAULT CHARSET=utf8 COLLATE=utf8_bin

我还有文件和mboxOffset的索引。 SHOW FULL PROCESSLIST表示mysql正在排序结果,需要花费几分钟时间。结果集大小为5M记录。我该如何优化呢?

4 个答案:

答案 0 :(得分:3)

优化总是很棘手。为了缩短你的执行时间,我想你可能需要做一些一些的预烹饪。

如果文件名相似,(例如/ path / to / file / 1,/ path / to / file / 2),对它们进行排序将意味着很多字节比较,可能由unicode编码加以复制。我会在插入时计算文件名的哈希值(例如MD5()),然后使用它进行排序。

如果文件已经很好地分发(例如postfix spool名称),你可能需要在插入时提出一些方案:

  1. 简单地从一些连接表中读取记录将自动以正确的顺序生成它们;这可能不会节省很多时间,但它会快速为您提供一些数据,以便您可以开始处理,或
  2. 找到一种方法来提供数据的“窗口”,这样就不会立即处理所有数据。

答案 1 :(得分:3)

不要认为在查询本身中有很多优化要做。连接会使它更具可读性,但现在iirc mysql完全能够检测到这些类型的构造并计划连接本身。

有必要增加tmp_table_size和max_heap_table_size,以允许此查询的结果集保留在内存中,而不必将其写入磁盘。

  

内存临时表的最大大小是tmp_table_size和max_heap_table_size值的最小值

http://dev.mysql.com/doc/refman/5.5/en/internal-temporary-tables.html

解释中的“using temporary”表示它正在使用临时表(请参阅上面的链接) - 由于数据量很大,可能会将其写入磁盘(再次参阅上面的链接了解更多信息)在此)。 单独的文件列是1到384个字节之间的任何位置,因此我们将一半用于估算并忽略其余列,这会导致结果集中每行192个字节。

1445 * 2721  =   3,931,845 rows
     * 192   = 754,914,240 bytes
     / 1024 ~=     737,221 kb
     / 1024 ~=         710 mb

这肯定比max_heap_table_size(16,777,216字节)更多,并且最有可能超过tmp_table_size。

不必将这样的结果写入磁盘肯定会提高速度。

祝你好运!

答案 2 :(得分:1)

正如@raheel shan上面所说,你可能想尝试一些JOIN

select 
    mailsource2_.file as col_0_0_, 
    messagedet0_.messageId as col_1_0_, 
    messageent1_.mboxOffset as col_2_0_, 
    messageent1_.mboxOffsetEnd as col_3_0_, 
    messagedet0_.id as col_4_0_ 
from 
  MessageDetails messagedet0_ 
inner join 
  MessageEntry messageent1_ 
on 
  messagedet0_.id = messageent1_.messageDetails_id 
inner join 
  MailSourceFile mailsource2_ 
on 
  messageent1_.mailSourceFile_id = mailsource2_.id
order by 
  mailsource2_.file, 
  messageent1_.mboxOffset

如果钥匙关闭,我很抱歉,但我想我已经传达了这一点。

答案 3 :(得分:0)

使用类似

的连接编写查询

选择

mailsource2_.file为col_0_0_,     messagedet0_.messageId为col_1_0_,     messageent1_.mboxOffset为col_2_0_,     messageent1_.mboxOffsetEnd为col_3_0_,     messagedet0_.id为col_4_0_

<强>从   MessageDetails m0

内部联接   MessageEntry m1   m0.id = m1.messageDetails_id

内部联接   MailSourceFile m2   m1.mailSourceFile_id = m2.id

排序   m2_.file,   m1_.mboxOffset;

看到你解释我发现了3件我觉得不好的东西

额外列中的1个文件排序

类型列中的2个索引

3密钥长度为384

如果减少密钥长度,可以快速检索,考虑使用的字符集和部分索引

在这里你可以为order by做强制索引并使用index for join(创建适当的多列索引并分配它们)记住它总是很好,在同一个表中存在列的顺序

索引类型表示它正在扫描整个索引列,这是不好的