1

我已经生成了查询

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

4 回答 4

3

优化总是很棘手。为了减少执行时间,我认为您可能需要进行某种预煮。

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

如果文件已经很好地分布(例如后缀假脱机名称),您可能需要提出一些插入方案:

  1. 简单地从某个连接表中读取记录将自动以正确的顺序生成它们;这可能不会节省很多时间,但它会快速为您提供一些数据,以便您开始处理,或者
  2. 找到一种方法来为数据提供一个“窗口”,这样就不需要一次处理所有数据。
于 2013-01-04T23:07:43.123 回答
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

解释中的“使用临时”表示它正在使用临时表(再次参见上面的链接) - 由于大量数据,它可能会被写入磁盘(再次,请参见上面的链接以获取更多信息) . 单独的文件列在 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。

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

祝你好运!

于 2013-01-11T09:00:08.243 回答
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

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

于 2013-01-04T21:30:35.197 回答
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 on m0.id = m1.messageDetails_id

m1.mailSourceFile_id = m2.id上内部加入 MailSourceFile m2

m2_.file、m1_.mboxOffset 排序;

在看到你的解释后,我发现了 3 件我认为不好的事情

1 个文件在额外列中排序

2 类型列中的索引

3个密钥长度为384

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

在这里,您可以为 order by 执行强制索引并使用索引进行连接(创建适当的多列索引并分配它们)记住,在同一个表中存在列的情况下排序总是好的

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

于 2013-01-12T10:25:56.207 回答