繁体   English   中英

MySQL的alter table查询非常慢

[英]MySQL very slow for alter table query

为什么简单地更新此表以添加一列需要一个多小时? 该表有 15M 行。 它有 2 个索引和一个单键主键。 ALTER TABLE 查询现在已经处于“复制到 tmp 表”状态 1 小时 15 分钟。

ALTER TABLE `frugg`.`item_catalog_map` 
ADD COLUMN `conversion_url` TEXT NULL DEFAULT NULL

桌子:

mysql> describe item_catalog_map;
+------------------------+---------------+------+-----+---------+-------+
| Field                  | Type          | Null | Key | Default | Extra |
+------------------------+---------------+------+-----+---------+-------+
| catalog_unique_item_id | varchar(255)  | NO   | PRI | NULL    |       |
| catalog_id             | int(11)       | YES  | MUL | NULL    |       |
| item_id                | int(11)       | YES  | MUL | NULL    |       |
| price                  | decimal(10,2) | YES  |     | 0.00    |       |
+------------------------+---------------+------+-----+---------+-------+

mysql> show index from item_catalog_map;
+------------------+------------+----------------------+--------------+------------------------+-----------+-------------+----------+--------+------+------------+---------+
| Table            | Non_unique | Key_name             | Seq_in_index | Column_name            | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+------------------+------------+----------------------+--------------+------------------------+-----------+-------------+----------+--------+------+------------+---------+
| item_catalog_map |          0 | PRIMARY              |            1 | catalog_unique_item_id | A         |    15485115 |     NULL | NULL   |      | BTREE      |         |
| item_catalog_map |          1 | IDX_ACD6184FCC3C66FC |            1 | catalog_id             | A         |          18 |     NULL | NULL   | YES  | BTREE      |         |
| item_catalog_map |          1 | IDX_ACD6184F126F525E |            1 | item_id                | A         |    15485115 |     NULL | NULL   | YES  | BTREE      |         |
+------------------+------------+----------------------+--------------+------------------------+-----------+-------------+----------+--------+------+------------+---------+

MySQL的ALTER TABLE性能可能会成为非常大的表的问题。 MySQL通过创建具有所需新结构的空表,将旧表中的所有数据插入新表并删除旧表来执行大多数更改。 这可能需要很长时间,特别是如果您的内存不足并且表很大并且有很多索引。 许多人都有使用ALTER TABLE操作的经验,这些操作需要数小时或数天才能完成。

无论如何,如果您需要继续使用alter table,可能以下资源可以帮助您:

如果您不关心停机时间,我的建议是使用三个单独的ALTER TABLE语句。 第一个语句删除所有现有的二级索引。 第二个语句应用所有与列相关的更改。 最后一个语句将删除的二级索引添加回来并应用其他索引更改。

另外两个提示:

  1. 在应用索引更改之前,请执行以下两个语句,并在完成索引更改后将值更改回1。

     SET unique_checks=0; SET foreign_key_checks=0; 
  2. 创建多个二级索引时,请将它们放在一个ALTER TABLE语句中,而不是多个单独的ALTER TABLE语句中。

下图显示了性能差异。 方法1是你的方法,方法2是我的方式。 方法2与50米工作台的方法1相比花费约3.47%的时间。 该解决方案仅适用于MySQL(> = 5.5)InnoDB引擎。

在此输入图像描述

Percona工具是大桌子的救星。

http://www.percona.com/doc/percona-toolkit/2.1/pt-online-schema-change.html

他们基本上:

  1. 创建重复的表
  2. 创建触发器以同步表
  3. 批量复制数据
  4. 校验
  5. 交换表

永远,但谁在乎,因为这意味着您可以在不停机的情况下更改列。

你的表有1500万行,这是一些东西。 ALTER TABLE涉及复制表中的所有数据并重新创建索引。 作为第一个测量,尝试在文件系统中复制数据文件(item_catalog_map.MYD,如果它是MyISAM),并查看需要多长时间。 这是ALTER TABLE 至少要采用的时间。

为了最大限度地减少我想要更改的大表的锁定,我执行以下操作:

  • 根据现有表创建一个新的空表,并更改此新的空表。
  • 执行大表的mysqldump,使其在大表中的每个记录都有一个完整的insert语句(开关-c和--skip-extended-insert)
  • 使用空重命名的large_table将此mysqldump导入另一个(空)数据库。
  • 从另一个数据库中获取此新重命名表的mysqldump,并将其导入原始数据库
  • 在原始数据库中重命名large_table和large_table_new。

     mysql> create table DATABASE_NAME.LARGE_TABLE_NEW like DATABASE_NAME.LARGE_TABLE; mysql> alter table DATABASE_NAME.LARGE_TABLE_NEW add column NEW_COLUMN_NAME COL_DATA_TYPE(SIZE) default null; $ mysqldump -c --no-create-info --skip-extended-insert --no-create-db -u root -p DATABASE_NAME LARGE_TABLE > LARGE_TABLE.sql mysql> create table test.LARGE_TABLE like DATABASE_NAME.LARGE_TABLE; $ mysql -u root -p -D test < LARGE_TABLE.sql mysql> rename table test.LARGE_TABLE to test.LARGE_TABLE_NEW; $ mysqldump -c --no-create-info --skip-extended-insert --no-create-db -u root -p test LARGE_TABLE_NEW > LARGE_TABLE_NEW.sql $ mysql -u root -p -D DATABASE_NAME < LARGE_TABLE_NEW.sql mysql> rename table DATABASE_NAME.LARGE_TABLE to DATABASE_NAME.LARGE_TABLE_OLD, DATABASE_NAME.LARGE_TABLE_NEW to DATABASE_NAME.LARGE_TABLE; 

我遇到了同样的问题,我只是使用“sudo service mysql restart”[ubuntu] 重新启动了 mysql 服务,此后立即执行了更改表命令。

我有一个类似的问题,对于在 MariaDB Docker 容器中运行的具有 1100 万行的表来说, ALTER TABLE的速度非常慢。 同样的ALTER TABLE在同样有 1100 万行的 RDS 实例上运行得非常快。

我正在运行 Mac OS 12.4,Docker 容器的数据位于文件系统卷上。 正如其他答案所指出的那样,瓶颈是临时表的创建。

修复是在 Docker 实验设置中启用 VirtioFS。 然后, ALTER TABLE大约需要 10 分钟,而不是可能需要 8 小时。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM