如何使用 InnoDB 表加速缓慢的 MySQL UPDATE 查询
How to speed up slow MySQL UPDATE queries with InnoDB tables
我在我的 InnoDB table 上有一个非常简单的 MySQL 更新查询。
UPDATE `players_teams` SET t_last_active=NOW() WHERE t_player_id=11225 AND t_team_id=6912 AND t_season_id=2002 LIMIT 1
我的 table 结构如下:
CREATE TABLE `players_teams` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`t_player_id` int(11) DEFAULT NULL,
`t_team_id` int(11) DEFAULT NULL,
`t_league_id` int(11) DEFAULT NULL,
`t_season_id` int(11) DEFAULT NULL,
`t_div` varchar(64) DEFAULT NULL,
`t_player_number` varchar(3) DEFAULT NULL,
`t_player_jersey_size` enum('UNKNOWN','XS','S','M','L','XL','XXL','XXXL') DEFAULT 'UNKNOWN',
`t_player_registration_number` varchar(64) DEFAULT NULL,
`t_player_class` enum('ROSTER','SPARE','COACH','INJURED','HOLIDAY','SUSPENDED','SCOREKEEPER') DEFAULT 'ROSTER',
`t_access_level` enum('PLAYER','MANAGER','ASSISTANT') DEFAULT 'PLAYER',
`t_player_position` enum('ANY','FORWARD','DEFENCE','GOALIE','PITCHER','CATCHER','FIRST BASE','SECOND BASE','THIRD BASE','SHORTSTOP','LEFT FIELD','CENTER FIELD','RIGHT FIELD') DEFAULT 'ANY',
`t_spare_status` enum('INVITED','IN','OUT') DEFAULT NULL,
`t_drink_next` int(1) DEFAULT '0',
`t_no_fees` tinyint(1) DEFAULT '0',
`t_no_drink` tinyint(1) DEFAULT '0',
`t_auto_check_in` tinyint(1) DEFAULT '0',
`t_print_reminder` tinyint(1) DEFAULT '0',
`t_notes` text,
`t_last_chatter_id` int(11) DEFAULT NULL,
`t_last_history_id` int(11) DEFAULT NULL,
`t_last_active` timestamp NULL DEFAULT NULL,
`t_status` enum('ACTIVE','INACTIVE','ARCHIVED') DEFAULT 'ACTIVE',
`t_added` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `t_player_id` (`t_player_id`),
KEY `t_team_id` (`t_team_id`),
KEY `t_season_id` (`t_season_id`),
KEY `t_player_id_2` (`t_player_id`,`t_team_id`,`t_season_id`),
KEY `Team/Player ID` (`t_team_id`,`t_player_id`),
KEY `UpdatePlayersDiv` (`t_team_id`,`t_season_id`)
) ENGINE=InnoDB AUTO_INCREMENT=23454 DEFAULT CHARSET=latin1;
这个简单的更新查询平均需要 3.5 秒?我 运行 在 MediaTemple MySQL GRID 容器上。
这是将 UPDATE 切换为 SELECT 时 EXPLAIN 的结果。
有人可以提供一些关于我如何不正确地做这件事的见解吗?
[编辑:添加了索引列表]
那么这是一堆乱七八糟的索引吗?我这里有一堆冗余索引吗?
干杯,
乔恩
它在 3 列上使用了错误的键而不是索引。您可以使用 USE KEY ...
语法提示索引。
https://dev.mysql.com/doc/refman/5.1/en/index-hints.html
您可能还想尝试对 3 列的密钥重新排序。通常,您希望最受限制的列在索引中排在第一位,然后是下一个最受限制的列,依此类推。
我在我的 InnoDB table 上有一个非常简单的 MySQL 更新查询。
UPDATE `players_teams` SET t_last_active=NOW() WHERE t_player_id=11225 AND t_team_id=6912 AND t_season_id=2002 LIMIT 1
我的 table 结构如下:
CREATE TABLE `players_teams` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`t_player_id` int(11) DEFAULT NULL,
`t_team_id` int(11) DEFAULT NULL,
`t_league_id` int(11) DEFAULT NULL,
`t_season_id` int(11) DEFAULT NULL,
`t_div` varchar(64) DEFAULT NULL,
`t_player_number` varchar(3) DEFAULT NULL,
`t_player_jersey_size` enum('UNKNOWN','XS','S','M','L','XL','XXL','XXXL') DEFAULT 'UNKNOWN',
`t_player_registration_number` varchar(64) DEFAULT NULL,
`t_player_class` enum('ROSTER','SPARE','COACH','INJURED','HOLIDAY','SUSPENDED','SCOREKEEPER') DEFAULT 'ROSTER',
`t_access_level` enum('PLAYER','MANAGER','ASSISTANT') DEFAULT 'PLAYER',
`t_player_position` enum('ANY','FORWARD','DEFENCE','GOALIE','PITCHER','CATCHER','FIRST BASE','SECOND BASE','THIRD BASE','SHORTSTOP','LEFT FIELD','CENTER FIELD','RIGHT FIELD') DEFAULT 'ANY',
`t_spare_status` enum('INVITED','IN','OUT') DEFAULT NULL,
`t_drink_next` int(1) DEFAULT '0',
`t_no_fees` tinyint(1) DEFAULT '0',
`t_no_drink` tinyint(1) DEFAULT '0',
`t_auto_check_in` tinyint(1) DEFAULT '0',
`t_print_reminder` tinyint(1) DEFAULT '0',
`t_notes` text,
`t_last_chatter_id` int(11) DEFAULT NULL,
`t_last_history_id` int(11) DEFAULT NULL,
`t_last_active` timestamp NULL DEFAULT NULL,
`t_status` enum('ACTIVE','INACTIVE','ARCHIVED') DEFAULT 'ACTIVE',
`t_added` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `t_player_id` (`t_player_id`),
KEY `t_team_id` (`t_team_id`),
KEY `t_season_id` (`t_season_id`),
KEY `t_player_id_2` (`t_player_id`,`t_team_id`,`t_season_id`),
KEY `Team/Player ID` (`t_team_id`,`t_player_id`),
KEY `UpdatePlayersDiv` (`t_team_id`,`t_season_id`)
) ENGINE=InnoDB AUTO_INCREMENT=23454 DEFAULT CHARSET=latin1;
这个简单的更新查询平均需要 3.5 秒?我 运行 在 MediaTemple MySQL GRID 容器上。
这是将 UPDATE 切换为 SELECT 时 EXPLAIN 的结果。
有人可以提供一些关于我如何不正确地做这件事的见解吗?
[编辑:添加了索引列表]
那么这是一堆乱七八糟的索引吗?我这里有一堆冗余索引吗?
干杯, 乔恩
它在 3 列上使用了错误的键而不是索引。您可以使用 USE KEY ...
语法提示索引。
https://dev.mysql.com/doc/refman/5.1/en/index-hints.html
您可能还想尝试对 3 列的密钥重新排序。通常,您希望最受限制的列在索引中排在第一位,然后是下一个最受限制的列,依此类推。