Почему добавление AUTO_INCREMENT занимает так много времени? - PullRequest
0 голосов
/ 12 января 2019

скажи, у меня есть стол

CREATE TABLE `tab_sample` (
  `id` bigint(20) NOT NULL,
  `something` char(2) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Я бы хотел превратить его в

CREATE TABLE `tab_sample` (
  `id` bigint(20) NOT NULL,
  `something` char(2) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Но

ALTER TABLE `tab_sample` MODIFY
  id bigint(20) NOT NULL AUTO_INCREMENT;

длится вечно, если таблица большая, потому что по какой-то причине MYSQL решает переписать все целиком (сначала скопировав во временную таблицу, ...).

Есть ли лучший способ сделать это? В конце концов, это должно просто изменить правило для значения по умолчанию id, не так ли?

1 Ответ

0 голосов
/ 13 января 2019

Вы ожидаете, что это изменение будет сделано только для метаданных, но не будет.

Вы можете проверить это, запросив изменение как внутреннее изменение и увидев ошибку, когда запрос не может быть удовлетворен.

mysql> alter table tab_sample modify id bigint not null auto_increment, algorithm=inplace;
ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.

InnoDB имеет ограниченное подмножество типов ALTER TABLE, которые могут быть выполнены как изменения на месте или только для метаданных. Смотри https://dev.mysql.com/doc/refman/5.6/en/innodb-online-ddl-operations.html

Запрашиваемое вами изменение, вероятно, считается «изменением типа данных столбца», даже если вы не меняете тип, а только изменяете параметр AUTO_INCREMENT.


Я думаю, что MySQL должен сделать копию таблицы для граничного случая, когда ваш столбец id содержит NULL или 0. В этом случае MySQL сгенерирует новое значение с автоматическим приращением и заменит NULL или 0.

mysql> insert into tab_sample (id) values (10),(20),(30),(0)

mysql> ALTER TABLE `tab_sample` MODIFY   id bigint(20) NOT NULL AUTO_INCREMENT;
Query OK, 4 rows affected (0.06 sec)

mysql> select * from tab_sample;
+----+-----------+
| id | something |
+----+-----------+
|  1 | NULL      |
| 10 | NULL      |
| 20 | NULL      |
| 30 | NULL      |
+----+-----------+

Смотрите, мой 0 был изменен на 1 с автоматическим приращением.

Другой крайний случай: столбец, возможно, не был уникальным ключом, поэтому он мог содержать много строк с 0 или NULL, и все они получили бы новые идентификаторы.

mysql> create table tab_sample2 ( id bigint, key(id));
Query OK, 0 rows affected (0.04 sec)

mysql> insert into tab_sample2 values (10),(20),(30),(0),(0),(0),(NULL),(NULL),(NULL);
Query OK, 9 rows affected (0.02 sec)
Records: 9  Duplicates: 0  Warnings: 0

mysql> alter table tab_sample2 modify column id bigint auto_increment;
Query OK, 9 rows affected (0.06 sec)
Records: 9  Duplicates: 0  Warnings: 0

mysql> select * from tab_sample2;
+----+
| id |
+----+
| 10 |
| 20 |
| 30 |
| 31 |
| 32 |
| 33 |
| 34 |
| 35 |
| 36 |
+----+

MySQL не знает, сколько строк в таблице будет нуждаться в новых значениях идентификатора. Это может быть каждая строка в таблице. Поэтому, чтобы быть в безопасности, он просто скопирует таблицу и заполнит значения auto-inc на столько строк, сколько потребуется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...