繁体   English   中英

慢auto_increment重置

[英]Slow auto_increment reset

我有很多表,由于某些原因,我需要在应用程序启动时调整此表的自动增量值。

我试着这样做:

mysql> select max(id) from item;
+----------+
| max(id)  |
+----------+
| 97972232 |
+----------+
1 row in set (0.05 sec)

mysql> alter table item auto_increment=1097972232;

在另一场会议中:

afrolov@A1-DB1:~$ mysql -u root -e "show processlist" | grep auto_increment
472196  root    localhost       test    Query   39      copy to tmp table       alter table item auto_increment=1097972232

MySQL正在开始重建表! 为什么MySQL需要这样做? 如何在调整auto_increment值时避免重建大表?

MySQL 5.0,InnoDB。
表定义:

 CREATE TABLE `item` (
      `id` bigint(20) NOT NULL auto_increment,
      `item_res_id` int(11) NOT NULL default '0',
      `stack_count` int(11) NOT NULL default '0',
      `position` int(11) NOT NULL default '0',
      `place` varchar(15) NOT NULL default '',
      `counter` int(11) NOT NULL default '-1',
      `is_bound` tinyint(4) NOT NULL default '0',
      `remove_time` bigint(20) NOT NULL default '-1',
      `rune_res_id` int(11) default NULL,
      `rune_id` bigint(20) default NULL,
      `avatar_id` bigint(20) NOT NULL,
      `rune_slot_res_id` int(11) default NULL,
      `is_cursed` tinyint(4) NOT NULL,
      PRIMARY KEY  (`id`),
      UNIQUE KEY `avatar_id` (`avatar_id`,`place`,`position`),
      UNIQUE KEY `rune_id` (`rune_id`),
      KEY `idx_item_res_id` (`item_res_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=97972233 DEFAULT CHARSET=utf8;

关于我为什么要这样做。 长话短说我想解决关于在服务器重启时重置auto_increment值的mysql innodb问题。 有时我们将行从表中复制到另一个表,我们必须保持行ID不变。 当我们向table1添加一行(例如id = 1)时,将行复制到table2,从table1中删除行并重新启动MySQL,然后当我们在table1中创建一个新行时,此行也将获得id = 1。 因此,如果我们必须将行复制到table2,我们会遇到唯一的约束违规。 我们已经有很多代码,很难重写它们。 调整自动增量值似乎是解决此问题的最简单方法。

添加:

MySQL 5.5 - 完全相同:(

只需为每个表添加一个需要auto_increment_id-1的临时记录,然后删除记录,快速简便,但可能太脏了

例:

insert into item set id=1097972232-1;

执行后,下一个auto_increment将是1097972232,这是你想要的

这可以避免缓慢

这是MySQL记录的“功能”:

如果对RENAME以外的ALTER TABLE使用任何选项,MySQL总是会创建一个临时表,即使数据不需要严格复制(例如更改列的名称时)。 对于MyISAM表,您可以通过将myisam_sort_buffer_size系统变量设置为较高值来加快索引重新创建操作(这是更改过程中最慢的部分)。

http://dev.mysql.com/doc/refman/5.0/en/alter-table.html

MySQL 5.1和5.5支持一些临时表的更改表操作,但更改auto_increment没有记录为其中之一。

无论如何,为什么需要更改auto_increment值? 这不是你应该经常做的事情。

没有简单的方法来绕过MySQL中的AUTO_INCREMENT属性默认行为,即使你找到了办法,我也不建议你这样做,因为这是在短期内遇到问题的最佳方法。 AUTO_INCREMENT值无意在生产环境中进行调整或重置。

解决问题的一种可能方法是将模型非规范化。 我们的想法是将AUTO_INCREMENT字段移动到您不必复制或删除行的边表。 您需要做的就是在创建新项时从此边表获取新的id值,并在将行从一个表复制到另一个表时保留现有的id值。

为实现此目的,我们将使用一个触发器,为我们创建一个新的id并将其分配给我们的项目记录。 项目表的id字段必须可以为空才能使其工作,因此我们必须用唯一索引替换主键。

此模型更改对于您的应用程序完全透明的 ,因此您无需在应用程序代码中进行更改

以下是一些示例脚本。 假设我们的数据库中有两个项表,有一些常见的行,有些行需要从第一个表移到第二个表:

CREATE TABLE `item1` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `item_res_id` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `item2` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `item_res_id` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO item1 (item_res_id) VALUES (1);
INSERT INTO item1 (item_res_id) VALUES (2);
INSERT INTO item2 (item_res_id) VALUES (1);

如果我们尝试将一些数据从一个表移动到另一个表然后重新启动服务器,我们将遇到AUTO_INCREMENT值重置的问题。 所以我们将稍微修改我们的模型如下:

带边桌的新型号

我们将分几个步骤迁移我们的数据模型。 以下迁移脚本中的DDL语句是使用neXtep Designer IDE生成的。

  • 首先,我们创建一个新的item_keys表,它将保存AUTO_INCREMENT字段:
-- Creating table 'item_keys'
CREATE TABLE item_keys ( 
   id BIGINT(20) UNSIGNED NOT NULL
  ,key_ctime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
) Engine=InnoDB default charset=utf8;

-- Creating Primary Key constraint 'PRIMARY' on table 'item_keys'
ALTER TABLE item_keys ADD CONSTRAINT PRIMARY KEY (id);
  • 但在激活AUTO_INCREMENT属性之前,我们必须将现有ID插入到新表中:
-- Initializing item_keys with existing ids
INSERT INTO item_keys (id)
    SELECT i1.id
    FROM item1 i1
        LEFT JOIN item_keys ik ON ik.id = i1.id
    WHERE ik.id IS NULL
;

INSERT INTO item_keys (id)
    SELECT i2.id
    FROM item2 i2
        LEFT JOIN item_keys ik ON ik.id = i2.id
    WHERE ik.id IS NULL
;
  • 我们现在可以激活AUTO_INCREMENT属性,并为将来的插入初始化它的值:
-- Activating auto_increment constraint...
ALTER TABLE item_keys MODIFY id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT;

-- Initializing auto_increment value
SELECT @inc_value := MAX(id) FROM item_keys;
SET @alter_query = CONCAT('ALTER TABLE item_keys AUTO_INCREMENT=',@inc_value); 
PREPARE alter_query FROM @alter_query; 
EXECUTE alter_query; 
DEALLOCATE PREPARE alter_query;
  • 然后我们可以改变item1item2表以用唯一索引替换主键,并引用item_keys表的主键:
-- De-activating auto_increment constraint...
ALTER TABLE item1 MODIFY id BIGINT(20) UNSIGNED NOT NULL;
-- Dropping constraint 'PRIMARY'...
ALTER TABLE item1 DROP PRIMARY KEY;
ALTER TABLE item1 MODIFY id BIGINT(20) UNSIGNED NULL;
-- Creating index 'item1_uk'...
CREATE UNIQUE INDEX item1_uk ON item1 (id);
-- Creating Foreign Key constraint 'item1_keys_fk' on table 'item1'
ALTER TABLE item1 ADD 
   CONSTRAINT item1_keys_fk FOREIGN KEY item1_keys_fk
      (id) REFERENCES item_keys
      (id)
;
-- De-activating auto_increment constraint...
ALTER TABLE item2 MODIFY id BIGINT(20) UNSIGNED NOT NULL;
-- Dropping constraint 'PRIMARY'...
ALTER TABLE item2 DROP PRIMARY KEY;
ALTER TABLE item2 MODIFY id BIGINT(20) UNSIGNED NULL;
-- Creating index 'item2_uk'...
CREATE UNIQUE INDEX item2_uk ON item2 (id);
-- Creating Foreign Key constraint 'item2_keys_fk' on table 'item2'
ALTER TABLE item2 ADD 
   CONSTRAINT item2_keys_fk FOREIGN KEY item2_keys_fk
      (id) REFERENCES item_keys
      (id)
;
  • 最后,我们只需创建将为我们管理ID创建的触发器:
-- Creating trigger 'tr_item1_bi' on table 'item1'...
DELIMITER |;
CREATE TRIGGER tr_item1_bi BEFORE INSERT ON item1
FOR EACH ROW
BEGIN
   IF (NEW.id IS NULL) THEN

        -- If no item id has been specified in the INSERT statement, it
        -- means we want to create a new item. We insert a new record
        -- into the item_keys table to get an item id.
        INSERT INTO item_keys (
            key_ctime
          )
        VALUES (NOW());

        SET NEW.id = LAST_INSERT_ID();
    END IF;
END;
|;
-- Creating trigger 'tr_item2_bi' on table 'item2'...
DELIMITER |;
CREATE TRIGGER tr_item2_bi BEFORE INSERT ON item2
FOR EACH ROW
BEGIN
   IF (NEW.id IS NULL) THEN

        -- If no item id has been specified in the INSERT statement, it
        -- means we want to create a new item. We insert a new record
        -- into the item_keys table to get an item id.
        INSERT INTO item_keys (
            key_ctime
          )
        VALUES (NOW());

        SET NEW.id = LAST_INSERT_ID();
    END IF;
END;
|;

现在我们可以将数据从一个表移动到另一个表,保持id不变,如果我们重新启动服务器, item_keysAUTO_INCREMENT值将保持不变。

--------------
INSERT INTO item2
    SELECT i1.*
    FROM item1 i1
        LEFT JOIN item2 i2
            ON i2.id = i1.id
    WHERE i2.id IS NULL
--------------
Query OK, 1 row affected (0.04 sec)
Records: 1  Duplicates: 0  Warnings: 0

--------------
DELETE FROM item1
--------------
Query OK, 2 rows affected (0.00 sec)

--------------
INSERT INTO item1 (item_res_id) VALUES (3)
--------------
Query OK, 1 row affected (0.00 sec)

--------------
SELECT * FROM item1
--------------

+------+-------------+
| id   | item_res_id |
+------+-------------+
|    3 |           3 |
+------+-------------+
1 row in set (0.00 sec)

--------------
SELECT * FROM item2
--------------

+------+-------------+
| id   | item_res_id |
+------+-------------+
|    1 |           1 |
|    2 |           2 |
+------+-------------+
2 rows in set (0.00 sec)

--------------
SELECT * FROM item_keys
--------------

+----+---------------------+
| id | key_ctime           |
+----+---------------------+
|  1 | 2010-11-14 10:31:21 |
|  2 | 2010-11-14 10:31:21 |
|  3 | 2010-11-14 10:31:46 |
+----+---------------------+
3 rows in set (0.00 sec)

如果需要在两个或更多服务器之间维护唯一ID,请不要每次都使用此alter table方法重置auto_increment。 更改增量的增量会更容易,这样每个服务器都可以生成唯一的ID而无需干预。 对于两台服务器,您设置一个从0开始,一个从1开始,增量为2 - 之后一个将生成偶数ID,另一个将生成赔率。 使用3个或更多服务器时,您只需将初始值设置为0/1/2,增量为3,其中4为0/1/2/3,inc为4,等等...

有关服务器端设置的详细信息:

http://dev.mysql.com/doc/refman/5.1/en/replication-options-master.html#sysvar_auto_increment_increment

这样,您只需每个服务器每个表重置一次auto_increment,然后他们将自动处理唯一性问题。

不是吗

ALTER TABLE item AUTO_INCREMENT=1;

资源

暂无
暂无

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

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