在 MySQL 上更新索引值极其缓慢

Update index values extremely slow on MySQL

我有三个 table,一个在数据库 db1 中,两个在数据库 db2 中,都在同一个 MySQL 服务器上:

CREATE TABLE `db1`.`user` (
  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  `user_name` varchar(20) NOT NULL,
  `password_hash` varchar(71) DEFAULT NULL,
  `email_address` varchar(100) NOT NULL,
  `registration_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `registration_hash` char(16) DEFAULT NULL,
  `active` bit(1) NOT NULL DEFAULT b'0',
  `public` bit(1) NOT NULL DEFAULT b'0',
  `show_name` bit(1) NOT NULL DEFAULT b'0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `user_name` (`user_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `db2`.`ref` (
  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `db2`.`combination` (
  `ref_id` bigint(20) UNSIGNED NOT NULL,
  `user_id` bigint(20) UNSIGNED NOT NULL,
  `arbitrary_number` tinyint(3) UNSIGNED NOT NULL DEFAULT '0',
  PRIMARY KEY (`figurine_id`,`user_id`),
  KEY `combination_user` (`user_id`),
  KEY `combination_number` (`user_id`,`arbitrary_number`),
  CONSTRAINT `combination_ref` FOREIGN KEY (`ref_id`) REFERENCES `ref` (`id`) ON UPDATE CASCADE,
  CONSTRAINT `combination_user` FOREIGN KEY (`user_id`) REFERENCES `db1`.`user` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

table db1.user 有大约 600 条记录,table db2.ref 有大约 800 条记录, table db2.combination 有大约 30 万条记录。

现在使用 Perl 和 DBD::mysql 我执行以下查询:

UPDATE `db1`.`user` SET `id` = (`id` + 1000)
ORDER BY `id` DESC

但是,此查询总是停止提及与 MySQL 服务器的连接已丢失。通过 PhpMyAdmin 执行相同的查询也会导致超时。不知何故,查询只需要很长时间才能执行。我猜是因为所有外键值都需要更新。

FOREIGN_KEY_CHECKS 变量设置为 OFF 将不会更新 db.combination table 中的 user_id 列,该列确实需要更新。

我也尝试过操纵不同的超时(如整个互联网所建议的那样),如下所示:

SET SESSION net_read_timeout=3000;
SET SESSION net_write_timeout=3000;
SET SESSION wait_timeout=6000;

我已经通过再次检索值验证了新值确实已设置。然而,即使有这么长的超时,查询仍然无法执行,并且在大约 30 秒后与 MySQL 服务器的连接再次丢失(在执行 UPDATE 查询时)

我们非常欢迎任何关于如何加速此查询的建议。

顺便说一句:PK 列具有非常大的整数类型。我还将使这种类型更小(更改为 INT)。这种类型的改变是否也能显着提高速度?

更新 我还为查询执行了 EXPLAIN,它在 Extra 列中提到查询正在执行文件排序。我本以为由于 table 上的索引(添加了它们,因为它们一开始就不存在),不会发生文件排序。

300K CASCADEs 可能是任务中最慢的部分。所以,让我们避免它。 (但是,可能会检查验证生成的链接;这应该不会太慢。)

  1. 禁用FOREIGN KEY处理

  2. 创建新表FOREIGN KEYs。 new_user、new_combination。 (不知道是否需要new_ref)

  3. 执行此操作以填充表格:

     INSERT INTO new_xx (user_id, ...)
         SELECT user_id + 1000, ...;
    
  4. ALTER TABLE new_xx ADD FOREIGN KEY ...;(每个xx)

  5. `RENAME TABLE xx TO old_xx, new_xx TO xx;

  6. `DROP TABLE old_xx;

  7. 启用FOREIGN KEY处理