我将所有表都存储在myISAM中,但是当我长时间运行更新作业时,表级锁定开始使我丧命。我将主表转换为InnoDB,现在我的许多查询都花了1分钟以上的时间来完成,它们几乎是在myISAM上即时完成的。它们通常卡在Sorting result台阶中。我做错什么了吗?
Sorting result
例如 :
SELECT * FROM `metaward_achiever` INNER JOIN `metaward_alias` ON (`metaward_achiever`.`alias_id` = `metaward_alias`.`id`) WHERE `metaward_achiever`.`award_id` = 1507 ORDER BY `metaward_achiever`.`modified` DESC LIMIT 100
现在大约需要90秒。这是描述:
+----+-------------+-------------------+--------+-------------------------------------------------------+----------------------------+---------+---------------------------------+-------+-----------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------------+--------+-------------------------------------------------------+----------------------------+---------+---------------------------------+-------+-----------------------------+ | 1 | SIMPLE | metaward_achiever | ref | metaward_achiever_award_id,metaward_achiever_alias_id | metaward_achiever_award_id | 4 | const | 66424 | Using where; Using filesort | | 1 | SIMPLE | metaward_alias | eq_ref | PRIMARY | PRIMARY | 4 | paul.metaward_achiever.alias_id | 1 | | +----+-------------+-------------------+--------+-------------------------------------------------------+----------------------------+---------+---------------------------------+-------+-----------------------------+
现在,我查询的TONS似乎卡在了“排序结果”步骤中:
mysql> show processlist; +--------+------+-----------+------+---------+------+----------------+------------------------------------------------------------------------------------------------------+ | Id | User | Host | db | Command | Time | State | Info | +--------+------+-----------+------+---------+------+----------------+------------------------------------------------------------------------------------------------------+ | 460568 | paul | localhost | paul | Query | 0 | NULL | show processlist | | 460638 | paul | localhost | paul | Query | 0 | Sorting result | SELECT `metaward_achiever`.`id`, `metaward_achiever`.`modified`, `metaward_achiever`.`created`, `met | | 460710 | paul | localhost | paul | Query | 79 | Sending data | SELECT `metaward_achiever`.`id`, `metaward_achiever`.`modified`, `metaward_achiever`.`created`, `met | | 460722 | paul | localhost | paul | Query | 49 | Updating | UPDATE `metaward_alias` SET `modified` = '2009-09-15 12:43:50', `created` = '2009-08-24 11:55:24', ` | | 460732 | paul | localhost | paul | Query | 25 | Sorting result | SELECT `metaward_achiever`.`id`, `metaward_achiever`.`modified`, `metaward_achiever`.`created`, `met | +--------+------+-----------+------+---------+------+----------------+------------------------------------------------------------------------------------------------------+ 5 rows in set (0.00 sec)
为什么这个简单的更新会停留49秒?
如果有帮助,请参见以下架构:
| metaward_alias | CREATE TABLE `metaward_alias` ( `id` int(11) NOT NULL AUTO_INCREMENT, `modified` datetime NOT NULL, `created` datetime NOT NULL, `string_id` varchar(255) DEFAULT NULL, `shortname` varchar(100) NOT NULL, `remote_image` varchar(500) DEFAULT NULL, `image` varchar(100) NOT NULL, `user_id` int(11) DEFAULT NULL, `type_id` int(11) NOT NULL, `md5` varchar(32) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `string_id` (`string_id`), KEY `metaward_alias_user_id` (`user_id`), KEY `metaward_alias_type_id` (`type_id`) ) ENGINE=InnoDB AUTO_INCREMENT=858381 DEFAULT CHARSET=utf8 | | metaward_award | CREATE TABLE `metaward_award` ( `id` int(11) NOT NULL AUTO_INCREMENT, `modified` datetime NOT NULL, `created` datetime NOT NULL, `string_id` varchar(20) NOT NULL, `owner_id` int(11) NOT NULL, `name` varchar(100) NOT NULL, `description` longtext NOT NULL, `owner_points` int(11) NOT NULL, `url` varchar(500) NOT NULL, `remote_image` varchar(500) DEFAULT NULL, `image` varchar(100) NOT NULL, `parent_award_id` int(11) DEFAULT NULL, `slug` varchar(110) NOT NULL, `true_points` double DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `string_id` (`string_id`), KEY `metaward_award_owner_id` (`owner_id`), KEY `metaward_award_parent_award_id` (`parent_award_id`), KEY `metaward_award_slug` (`slug`), KEY `metaward_award_name` (`name`) ) ENGINE=InnoDB AUTO_INCREMENT=122176 DEFAULT CHARSET=utf8 | | metaward_achiever | CREATE TABLE `metaward_achiever` ( `id` int(11) NOT NULL AUTO_INCREMENT, `modified` datetime NOT NULL, `created` datetime NOT NULL, `award_id` int(11) NOT NULL, `alias_id` int(11) NOT NULL, `count` int(11) NOT NULL, PRIMARY KEY (`id`), KEY `metaward_achiever_award_id` (`award_id`), KEY `metaward_achiever_alias_id` (`alias_id`) ) ENGINE=InnoDB AUTO_INCREMENT=77175366 DEFAULT CHARSET=utf8 |
这些在我的my.cnf中
innodb_file_per_table innodb_buffer_pool_size = 2048M innodb_additional_mem_pool_size = 16M innodb_flush_method=O_DIRECT
这是一个很大的结果集(66,424行),MySQL必须手动对其进行排序。尝试将索引添加到metaward_achiever.modified。
MySQL 4.x有一个限制,即仅允许MySQL每个表使用一个索引。由于它使用metaward_achiever.award_id列上的索引进行WHERE选择,因此它也不能将metaward_achiever.modified上的索引用于排序。我希望您使用的是MySQL 5.x,它可能对此有所改善。
您可以通过对此简化查询进行解释来查看此内容:
SELECT * FROM `metaward_achiever` WHERE `metaward_achiever`.`award_id` = 1507 ORDER BY `metaward_achiever`.`modified` DESC LIMIT 100
如果可以在WHERE选择和排序中都使用索引来获得此设置,那么就可以开始设置了。
您还可以同时使用metaward_achiever.award_id和metaward_achiever创建复合索引。如果MySQL不使用它,则可以提示它或仅在award_id上删除它。
或者,如果您可以摆脱metaward_achiever.id并将metaward_achiever.award_id设置为主键,并在metaward_achiever.modified上添加键,或者更好的是使metaward_achiever.award_id与metaward.modified组合为主键,那么您将是真正的好的。
以下是有关文件排序的特别文章:http ://s.petrunia.net/blog/?p =24