我有一个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上,因此表格在此期间完全锁定
答案 0 :(得分:3)
我想原因是你在三个表上做了很大的连接(没有先应用where子句,结果是10k * 10k * 100M = 10 16 行)。尝试重新排序联接(例如,从metaward_award
开始,然后仅加入metaward_achiever
查看需要多长时间,然后尝试插入metaward_alias
,可能使用子查询来强制您首选的评估顺序)。
如果这没有帮助,您可能必须对数据进行非规范化,例如存储特定metaward_achiever
的别名数。然后你就完全摆脱了一个联接。也许您甚至可以缓存metaward_award
的总和,具体取决于您的数据更新的频率和频率。
其他可能有帮助的是将所有数据库内容放入RAM: - )
答案 1 :(得分: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
答案 2 :(得分:1)
SELECT @@key_buffer_size
首先,您应该运行ANALYZE TABLE或OPTIMIZE TABLE。他们会对您的索引进行排序,并可以略微提高性能。
您还应该看看是否可以为列使用更紧凑的类型。例如,如果您不会拥有超过1600万的所有者或奖励或别名,您可以将INT列更改为MEDIUMINT(当然,UNSIGNED)。在某些情况下甚至可能是SMALLINT?这将减少您的索引占用空间,并且您将更多地放入缓存中。