1

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

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、更快的磁盘)?

提前谢谢

PS解释结果:

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)
4

3 回答 3

1

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

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

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

于 2010-04-22T13:16:20.613 回答
0

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

您还可以在配置文件中增加 mysql 的缓存。

于 2010-04-22T12:59:51.857 回答
0

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

于 2010-04-22T13:19:06.237 回答