2

我有 3 个大表(10k、10k 和 100M 行),并试图对它们的连接进行简单计数,其中所有连接的列都被索引。为什么 COUNT(*) 需要这么长时间,我怎样才能加快速度(没有触发器和运行摘要)?

mysql> describe SELECT COUNT(*) FROM `metaward_alias` INNER JOIN `metaward_achiever` ON (`metaward_alias`.`id` = `metaward_achiever`.`alias_id`) INNER JOIN `metaward_award` ON (`metaward_achiever`.`award_id` = `metaward_award`.`id`) WHERE `metaward_award`.`owner_id` = 8;
+----+-------------+-------------------+--------+-------------------------------------------------------+----------------------------+---------+---------------------------------+------+-------------+
| id | select_type | table             | type   | possible_keys                                         | key                        | key_len | ref                             | rows | Extra       |
+----+-------------+-------------------+--------+-------------------------------------------------------+----------------------------+---------+---------------------------------+------+-------------+
|  1 | SIMPLE      | metaward_award    | ref    | PRIMARY,metaward_award_owner_id                       | metaward_award_owner_id    | 4       | const                           | 1552 |             | 
|  1 | SIMPLE      | metaward_achiever | ref    | metaward_achiever_award_id,metaward_achiever_alias_id | metaward_achiever_award_id | 4       | paul.metaward_award.id          | 2498 |             | 
|  1 | SIMPLE      | metaward_alias    | eq_ref | PRIMARY                                               | PRIMARY                    | 4       | paul.metaward_achiever.alias_id |    1 | Using index | 
+----+-------------+-------------------+--------+-------------------------------------------------------+----------------------------+---------+---------------------------------+------+-------------+
3 rows in set (0.00 sec)

但实际上运行查询大约需要 10 分钟,而且我在 MyISAM 上,所以表在这段时间内完全锁定

4

3 回答 3

3

我猜原因是您对三个表进行了巨大的连接(如果不先应用 where 子句,结果将是 10k * 10k * 100M = 10 16行)。尝试重新排序连接(例如以 开头metaward_award,然后 join 只看metaward_achiever需要多长时间,然后尝试 plug metaward_alias,可能使用子查询来强制您首选的评估顺序)。

如果这没有帮助,您可能必须对数据进行非规范化,例如通过存储特定的别名数量metaward_achiever。然后你会完全摆脱一个加入。也许您甚至可以缓存 的总和metaward_award,具体取决于您的数据更新的频率和频率。

其他可能有帮助的事情是将所有数据库内容放入 RAM :-)

于 2009-09-17T07:01:36.767 回答
1

10 分钟对于该查询来说太长了。我认为您必须有一个非常小的密钥缓存。您可以通过以下方式获取其大小(以字节为单位):

SELECT @@key_buffer_size

首先,您应该运行ANALYZE TABLEOPTIMIZE TABLE。他们会对您的索引进行排序,并可以稍微提高性能。

您还应该查看是否可以为列使用更紧凑的类型。例如,如果您的所有者或奖励或别名不超过 1600 万,您可以将 INT 列更改为 MEDIUMINT(当然是 UNSIGNED)。在某些情况下甚至可能是 SMALLINT?这将减少您的索引占用空间,并且您将在缓存中放置更多的索引。

于 2009-09-17T13:11:34.403 回答
1

确保您有以下索引:

metaward_alias      id
metaward_achiever   alias_id
metaward_achiever   award_id
metaward_award      id
metaward_award      owner_id

我相信很多人也会建议依靠特定的列,但在 MySql 中,这对您的查询没有任何影响。

更新

您还可以尝试在主表而不是连接表之一上设置条件。这会给你同样的结果,但它可能会更快(我不知道 MySql 有多聪明):

SELECT COUNT(*) FROM `metaward_award` 
   INNER JOIN `metaward_achiever` 
      ON (`metaward_achiever`.`award_id` = `metaward_award`.`id`) 
   INNER JOIN `metaward_alias` 
      ON (`metaward_alias`.`id` = `metaward_achiever`.`alias_id`) 
WHERE `metaward_award`.`owner_id` = 8
于 2009-09-17T06:50:48.730 回答