为什么仅仅更新此表以添加列就需要一个多小时?该表有 15M 行。它有 2 个索引和一个单键主键。 ALTER TABLE 查询现在已处于“复制到临时表”状态 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
语句。第一条语句删除所有现有的二级索引。第二条语句应用所有与列相关的更改。最后一条语句将删除的二级索引添加回来并应用其他索引更改。
另外两个提示:
在应用索引更改之前,执行以下两条语句,并在完成索引更改后将值更改回1。
SET unique_checks=0;
SET foreign_key_checks=0;
创建多个二级索引时,请将它们放在一个
ALTER TABLE
语句中,而不是多个单独的 ALTER TABLE
语句。下图展示了性能差异。方法1是你的方法,方法2是我的方法。 对于 50m 的表,与方法 1 相比,方法 2 大约需要 3.47% 的时间。 该解决方案仅适用于 MySQL(>=5.5)InnoDB 引擎。
为了最大限度地减少我想要更改的大表的锁定,我执行以下操作:
将原数据库中的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;
Percona 工具是这些带有大桌子的东西的救星。
http://www.percona.com/doc/percona-toolkit/2.1/pt-online-schema-change.html
他们基本上:
需要很长时间,但谁在乎呢,因为这意味着您可以在不停机的情况下更换色谱柱。
你的表有 1500 万行,这很了不起。 ALTER TABLE 涉及复制表中的所有数据并重新创建索引。作为第一个测量,请尝试将数据文件(如果是 MyISAM,则为 item_catalog_map.MYD)复制到文件系统中,并查看需要多长时间。这是 ALTER TABLE 至少花费的时间。
我遇到了同样的问题,我只是使用以下命令重新启动了 MySQL 服务:
sudo service mysql restart
在 Ubuntu 中,此后
ALTER TABLE
命令立即执行。
我遇到了类似的问题,对于在 MariaDB Docker 容器内运行的包含 1100 万行的表来说,
ALTER TABLE
的速度非常慢。同样的 ALTER TABLE
在同样具有 1100 万行的 RDS 实例上也快如闪电。
我正在运行 Mac OS 12.4,Docker 容器的数据位于文件系统卷上。正如其他答案所指出的,瓶颈是临时表的创建。
修复方法是在 Docker 实验设置中启用 VirtioFS。
ALTER TABLE
然后花费了大约 10 分钟,而不是可能需要 8 小时。
我通过以下步骤解决了问题:
暂时删除了常规检查。
设置 unique_checks=0; 设置foreign_key_checks = 0;
增加了此帖子之后的资源。 从约 9 小时减少到约 37 秒