MySQL对于alter表查询非常慢
为什么仅仅更新此表以添加列就要花费一个多小时?这张桌子有15米的行。它有两个索引和一个单键主键。ALTER TABLE查询已处于“复制到tmp TABLE”状态1小时15分钟MySQL对于alter表查询非常慢,mysql,sql,alter-table,Mysql,Sql,Alter Table,为什么仅仅更新此表以添加列就要花费一个多小时?这张桌子有15米的行。它有两个索引和一个单键主键。ALTER TABLE查询已处于“复制到tmp TABLE”状态1小时15分钟 ALTER TABLE `frugg`.`item_catalog_map` ADD COLUMN `conversion_url` TEXT NULL DEFAULT NULL 表: mysql> describe item_catalog_map; +------------------------+----
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 | |
+------------------+------------+----------------------+--------------+------------------------+-----------+-------------+----------+--------+------+------------+---------+
您的表有1500万行,这很重要。ALTER TABLE涉及复制表中的所有数据并重新创建索引。作为第一个度量,请尝试在文件系统中复制数据文件(item_catalog_map.MYD,如果它是MyISAM),并查看需要多长时间。这是ALTER TABLE至少需要花费的时间。MySQL的ALTER TABLE性能对于非常大的表来说可能会成为一个问题。MySQL执行 大多数更改是通过创建一个具有所需新结构的空表、将旧表中的所有数据插入新表以及删除旧表来实现的。这可能需要很长的时间,尤其是当内存不足、表很大且有很多索引时。许多人都有过ALTER TABLE操作的经验,这些操作需要数小时或数天才能完成 无论如何,如果您需要继续使用alter table,以下资源可能会帮助您:
- 基于现有表创建新的空表,并更改此新的空表
- 对大表执行mysqldump,使其在大表中的每条记录都有一个完整的insert语句(开关-c和--skip extended insert)
- 将此mysqldump导入另一个(空)数据库,并使用空的重命名大_表
- 从另一个数据库获取此新重命名表的mysqldump,并将其导入原始数据库
- 在原始数据库中重命名大_表和新的大_表
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;
mysql>创建表DATABASE\u NAME.LARGE\u table\u新建类似DATABASE\u NAME.LARGE\u table; mysql>alter table DATABASE\u NAME.LARGE\u table\u NEW add column\u NAME COL\u DATA\u TYPE(SIZE)默认为空; $mysqldump-c--无创建信息--跳过扩展插入--无创建db-u root-p数据库\u NAME LARGE\u TABLE>LARGE\u TABLE.sql mysql>创建表test.LARGE\u表,如数据库\u NAME.LARGE\u表; $mysql-u root-p-D test
将table test.LARGE\u table重命名为test.LARGE\u table\u NEW; $mysqldump-c--无创建信息--跳过扩展插入--无创建db-u root-p测试大表格\u NEW>LARGE\u TABLE\u NEW.sql $mysql-u root-p-D数据库\u NAME 将表DATABASE_NAME.LARGE_table重命名为DATABASE_NAME.LARGE_table_OLD,DATABASE_NAME.LARGE_table_NEW重命名为DATABASE_NAME.LARGE_table;
这需要花费很长时间,但谁在乎呢,因为这意味着您可以在不停机的情况下更改列。如果您不在乎停机时间,我的建议是使用三个独立的
ALTER TABLE
语句。第一条语句删除所有现有的二级索引。第二条语句应用所有与列相关的更改。最后一条语句将删除的二级索引添加回,并应用其他索引更改
另外两个小贴士:
SET unique_checks=0;
SET foreign_key_checks=0;
altertable
语句中,而不是放在多个分隔的altertable
语句中可能这个有类似问题的线程会帮你解决问题…也可以浏览这个线程…如果有某种进度条、状态消息或至少有一个旋转光标,LOL,那就太酷了。特别是在“修改列”之后已使我的网站脱机。如果需要这么长时间,您的存储系统出现问题,那不是MySQL问题。我正在从varchar更改为30行表中的文本,等待了20分钟,但仍在继续。可以是什么?VARCHAR存储在表中,而文本单独存储,引用存储在表中。所以他们非常不同。我假设是因为您有一个非常大的varchar,并且您希望允许更大的值,才提示进行更改。在这种情况下,它需要移动所有的值。@AndreKR-不,我认为这很明显是MySQL的问题。将一列添加到包含900MB数据的表中(大约25K行包含较小的blob)不会花费超过3个小时,这就是我现在的工作。我的存储系统也没有问题;数据库存储在一个相当好的SSD上,我有足够的可用RAM进行缓存。我认为InnoDB在这种操作过程中很难维护索引;我想它没有优化的大容量插入机制,所以每次只重建一行新索引。@Jules你可能是对的。我想,当我写评论时,我假设它是一个MyISAM表,因为我认为“复制到tmp表”不会发生在InnoDB上,但事实上,在问题中没有给出表类型。在InnoDB中,计划几天的ALTER TABLE操作是很正常的,这就是为什么有这样的软件存在的原因。如果表上有外键,则没有任何帮助,因为无法自动重命名两个表。显然,在不更改外键的另一侧的情况下,无法更改外键一侧的数据类型。这是必然的。然后必须删除外键,更改两列,并在之后重新引入外键。应为