【问题标题】:mysql query performance helpmysql查询性能帮助
【发布时间】:2010-04-22 12:54:26
【问题描述】:

我有一个很大的表来存储电子邮件中包含的单词

mysql> explain t_message_words;
+----------------+---------+------+-----+---------+----------------+
| Field          | Type    | Null | Key | Default | Extra          |
+----------------+---------+------+-----+---------+----------------+
| mwr_key        | int(11) | NO   | PRI | NULL    | auto_increment |
| mwr_message_id | int(11) | NO   | MUL | NULL    |                |
| mwr_word_id    | int(11) | NO   | MUL | NULL    |                |
| mwr_count      | int(11) | NO   |     | 0       |                |
+----------------+---------+------+-----+---------+----------------+

表包含大约 100M 行
mwr_message_id 是消息表的 FK
mwr_word_id 是单词表的 FK
mwr_count 是消息 mwr_message_id 中单词 mwr_word_id 的出现次数

为了计算最常用的词,我使用以下查询

SELECT SUM(mwr_count) AS word_count, mwr_word_id
FROM t_message_words
GROUP BY mwr_word_id
ORDER BY word_count DESC
LIMIT 100;

几乎永远运行(在测试服务器上超过半小时)

mysql> show processlist;
+----+------+----------------+--------+---------+------+----------------------+-----------------------------------------------------
| Id | User | Host           | db     | Command | Time | State                | Info
+----+------+----------------+--------+---------+------+----------------------+-----------------------------------------------------
processlist
| 41 | root | localhost:3148 | tst_db | Query   | 1955 | Copying to tmp table | SELECT SUM(mwr_count) AS word_count, mwr_word_id
    FROM t_message_words
    GROUP BY mwr_word_id |
+----+------+----------------+--------+---------+------+----------------------+-----------------------------------------------------
3 rows in set (0.00 sec)

我可以做些什么来“加速”查询(除了添加更多内存、更多 CPU、更快的磁盘)?

提前谢谢你
斯特凡诺

附:解释结果:

mysql> EXPLAIN SELECT SUM(mwr_count) AS word_count, mwr_word_id
    -> FROM t_message_words
    -> GROUP BY mwr_word_id
    -> ORDER BY word_count DESC
    -> LIMIT 100;
+----+-------------+-----------------+-------+---------------+----------------------+---------+------+----------+---------------------------------+
| id | select_type | table           | type  | possible_keys | key                  | key_len | ref  | rows     | Extra                           |
+----+-------------+-----------------+-------+---------------+----------------------+---------+------+----------+---------------------------------+
|  1 | SIMPLE      | t_message_words | index | NULL          | IDX_t_message_words2 | 4       | NULL | 94823285 | Using temporary; Using filesort |
+----+-------------+-----------------+-------+---------------+----------------------+---------+------+----------+---------------------------------+
1 row in set (0.01 sec)

【问题讨论】:

  • 这与双稳态无关。

标签: mysql performance group-by bigtable


【解决方案1】:

我不明白你是否有一个 mwr_message_id 和 mwr_word_id 索引,或者只是 mwr_word_id 索引,或者除主键索引之外的任何其他索引。如果您没有 mwr_word_id 索引(或将 mwr_word_id 作为第一个字段),我建议您添加一个。

如果您已经有这样的索引,并且这对于一个非常常见的场景来说确实很痛苦,我建议您在 word 表中添加一些冗余,该表将 mwr_word_id 在所有 mwr_message_id 中的总出现次数相加。

您还可以在 t_message_words 中添加一些触发器来处理这种冗余的更新。

【讨论】:

  • 是的,我已经将两者都编入索引了。事实上,我无法通过在 words 表中添加冗余来解决这个问题,因为“真实”查询(为了简洁起见,此处未显示)也包含一个 Join on mwr_message_id 字段。
  • 好吧,那么您应该向我们展示真实的查询,以便我们提供更准确的答案:)
  • 答案似乎是我发布的查询无法加速:(我本可以发布我面临的真正查询,但很难找到答案。谢谢你的建议,我正在做一些“类似”的事情来解决这个问题。
【解决方案2】:

也许mwr_word_id 上的索引会有所帮助。它现在是密钥的一部分,但您可以纯粹为此添加密钥。

你也可以在配置文件中增加mysql的缓存。

【讨论】:

  • 很遗憾 mwr_word_id 已经被索引了:(关于缓存,你能告诉我我应该尝试更改 my.ini 中的哪个参数吗?我已经修改了 innodb_buffer_pool_size (从 77MB 到 512MB),没有任何执行时间的显着变化。
  • @Stefano:“内存中临时表的最大大小是 tmp_table_size 和 max_heap_table_size 中的最小值”,请参阅dev.mysql.com/doc/refman/5.0/en/internal-temporary-tables.html。我认为你增加了错误的设置:)
  • @Stefano 使用 EXPLAIN 查询看看它会做什么也没有什么坏处。
  • @extraneon:感谢您指出 mysql 文档中的页面。我试图同时增加 tmp_table_size 和 max_heap_table_size,但没办法:(我也用 EXPLAIN 结果更新了问题
  • @Stefano 拆分查询可以接受吗?如果没有 order_by 到内存中明确定义的临时表,而不是从该表中进行排序选择?优势?手工临时表的规则不同,可能比自动临时表大。另外,您也许可以在临时表上使用 MyISAM,这对于 group_by 来说应该更快一些。
【解决方案3】:

UPD:如果您需要运行此查询一次 - 只需等待它完成即可。如果您需要多次运行此查询 - 通过触发每个插入/更新/删除来创建具有唯一单词的表并在此表中更新计数

【讨论】:

  • 对不起,Andrii,但我看不到这样一个索引的原因。查询中未使用 mwr_message_id 且 mwr_count 不是条件。在您看来,为什么这会提高性能?
  • 哦,对不起... :-( 如果您需要运行一次此查询 - 只需等待它完成。如果您需要多次运行此查询 - 创建表通过触发器在此表中包含唯一单词和更新计数