简体   繁体   English

MySQL的alter table查询非常慢

[英]MySQL very slow for alter table query

Why is it taking more than an hour to simply update this table to add a column?为什么简单地更新此表以添加一列需要一个多小时? This table has 15M rows.该表有 15M 行。 It has 2 indexes and a single key primary key.它有 2 个索引和一个单键主键。 The ALTER TABLE query has been in "copy to tmp table" state for 1 hour 15 minutes now. ALTER TABLE 查询现在已经处于“复制到 tmp 表”状态 1 小时 15 分钟。

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

Table:桌子:

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's ALTER TABLE performance can become a problem with very large tables. MySQL的ALTER TABLE性能可能会成为非常大的表的问题。 MySQL performs most alterations by making an empty table with the desired new structure, inserting all the data from the old table into the new one, and deleting the old table. MySQL通过创建具有所需新结构的空表,将旧表中的所有数据插入新表并删除旧表来执行大多数更改。 This can take a very long time, especially if you're short on memory and the table is large and has lots of indexes. 这可能需要很长时间,特别是如果您的内存不足并且表很大并且有很多索引。 Many people have experience with ALTER TABLE operations that have taken hours or days to complete. 许多人都有使用ALTER TABLE操作的经验,这些操作需要数小时或数天才能完成。

Anyway if you need to proceed with alter table, maybe the following resources could help you: 无论如何,如果您需要继续使用alter table,可能以下资源可以帮助您:

If you don't care about downtime, my suggestion is using three separated ALTER TABLE statements. 如果您不关心停机时间,我的建议是使用三个单独的ALTER TABLE语句。 The first statement removes all existing secondary indexes. 第一个语句删除所有现有的二级索引。 The second statement applies all column related changes. 第二个语句应用所有与列相关的更改。 The last statement adds dropped secondary indexes back and applies other index changes. 最后一个语句将删除的二级索引添加回来并应用其他索引更改。

Another two tips: 另外两个提示:

  1. Before apply index changes, execute the two following statements and change the values back to 1 after finishing the index change. 在应用索引更改之前,请执行以下两个语句,并在完成索引更改后将值更改回1。

     SET unique_checks=0; SET foreign_key_checks=0; 
  2. When create multiple secondary indexes, put them in one ALTER TABLE statement rather than multiple separated ALTER TABLE statements. 创建多个二级索引时,请将它们放在一个ALTER TABLE语句中,而不是多个单独的ALTER TABLE语句中。

The following picture shows the performance difference. 下图显示了性能差异。 Approach 1 is your approach and approach 2 is my way. 方法1是你的方法,方法2是我的方式。 Approach 2 takes about 3.47% time comparing with approach 1 for a 50m table. 方法2与50米工作台的方法1相比花费约3.47%的时间。 The solution only works for MySQL (>=5.5) InnoDB engine. 该解决方案仅适用于MySQL(> = 5.5)InnoDB引擎。

在此输入图像描述

The Percona tools are a lifesaver for this stuff w/ big tables. Percona工具是大桌子的救星。

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

they basically: 他们基本上:

  1. create duplicate table 创建重复的表
  2. create trigger to sync tables 创建触发器以同步表
  3. bulk copy data 批量复制数据
  4. verify 校验
  5. swap tables 交换表

Takes forever, but who cares because this means you can change columns without downtime. 永远,但谁在乎,因为这意味着您可以在不停机的情况下更改列。

Your table has 15 million rows, which is something. 你的表有1500万行,这是一些东西。 The ALTER TABLE involves copying over all the data from the table and recreating the indexes. ALTER TABLE涉及复制表中的所有数据并重新创建索引。 As a first measurement try copying the data file (item_catalog_map.MYD if it's MyISAM) in your filesystem and see how long that takes. 作为第一个测量,尝试在文件系统中复制数据文件(item_catalog_map.MYD,如果它是MyISAM),并查看需要多长时间。 This is the time the ALTER TABLE will at least take. 这是ALTER TABLE 至少要采用的时间。

For minimize locking up of the large table that I want to alter, I do the following: 为了最大限度地减少我想要更改的大表的锁定,我执行以下操作:

  • Create a new empty table based on the existing table and alter this new empty table. 根据现有表创建一个新的空表,并更改此新的空表。
  • Do a mysqldump of the large table such that it has one complete insert statement per record in the large table (switches -c and --skip-extended-insert) 执行大表的mysqldump,使其在大表中的每个记录都有一个完整的insert语句(开关-c和--skip-extended-insert)
  • Import this mysqldump into a different (empty) database with the empty renamed large_table. 使用空重命名的large_table将此mysqldump导入另一个(空)数据库。
  • Take a mysqldump of this new rename table from the other database and import it into the original database 从另一个数据库中获取此新重命名表的mysqldump,并将其导入原始数据库
  • Rename large_table and large_table_new in the original database. 在原始数据库中重命名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 服务,此后立即执行了更改表命令。

I had a similar problem where an ALTER TABLE was incredibly slow for a table with 11 million rows running inside a MariaDB Docker container.我有一个类似的问题,对于在 MariaDB Docker 容器中运行的具有 1100 万行的表来说, ALTER TABLE的速度非常慢。 The same ALTER TABLE was lightning fast on an RDS instance also with 11 million rows.同样的ALTER TABLE在同样有 1100 万行的 RDS 实例上运行得非常快。

I'm running Mac OS 12.4 and the data for the Docker container lives on a filesystem volume.我正在运行 Mac OS 12.4,Docker 容器的数据位于文件系统卷上。 The bottleneck was the creation of the temporary table as other answers have noted.正如其他答案所指出的那样,瓶颈是临时表的创建。

The fix was to enable VirtioFS inside the Docker experimental settings.修复是在 Docker 实验设置中启用 VirtioFS。 The ALTER TABLE then took around 10 minutes instead of what was likely to take 8 hours.然后, ALTER TABLE大约需要 10 分钟,而不是可能需要 8 小时。

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

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