このエントリーをはてなブックマークに追加

2016年12月26日月曜日

InnoDBでauto_incrementの値が戻る?

Taroです、最近寒くて朝が辛いです。
本日は実際に困って調べた話にしたいと思います。
タイトルですが、InnoDBだとDBを再起動した際にauto_incrementが最適化されてしまうとのこと。
すでに多くの知見があるようですが、今回は実際に試してみました。
5.5.9のリリースにて、最適化にてリセットされる問題は解消されたようですが、今回は試しにやってみたいと思います。
Changes in MySQL 5.5.9 (2011-02-07, General Availability)

準備


MySQLのバージョンは5.7.14になります。
$ mysql --version
mysql  Ver 14.14 Distrib 5.7.14, for osx10.10 (x86_64) using  EditLine wrapper
とりあえず、テスト用のDBを作成します。
mysql> create database test;
ストレージエンジンの一覧を見てみます。
現在はInnoDBがデフォルトですね。(というより、こんなにたくさんあるんですね。。。)
mysql> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine             | Support | Comment                                                        | Transactions | XA   | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| InnoDB             | DEFAULT | Supports transactions, row-level locking, and foreign keys     | YES          | YES  | YES        |
| MRG_MYISAM         | YES     | Collection of identical MyISAM tables                          | NO           | NO   | NO         |
| MEMORY             | YES     | Hash based, stored in memory, useful for temporary tables      | NO           | NO   | NO         |
| BLACKHOLE          | YES     | /dev/null storage engine (anything you write to it disappears) | NO           | NO   | NO         |
| MyISAM             | YES     | MyISAM storage engine                                          | NO           | NO   | NO         |
| CSV                | YES     | CSV storage engine                                             | NO           | NO   | NO         |
| ARCHIVE            | YES     | Archive storage engine                                         | NO           | NO   | NO         |
| PERFORMANCE_SCHEMA | YES     | Performance Schema                                             | NO           | NO   | NO         |
| FEDERATED          | NO      | Federated MySQL storage engine                                 | NULL         | NULL | NULL       |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
今回はInnoDBとよく比較されるMyISAMでも試したいと思います。
InnoDBとMyISAMの簡単な特徴は下記になります。
  • InnoDBはレコード単位でロックされるが、MyISAMはテーブル単位。
  • トランザクション機能がMyISAMにはない。
  • InnoDBはMyISAMに比べてデータサイズが大きくなる。
  • InnoDBは更新系、MyISAMは参照系が得意。

それでは実際にそれぞれのエンジンのテーブルを作成します。
mysql> create table innodb_test (id int primary key auto_increment) engine=InnoDB;
mysql> create table myisam_test (id int primary key auto_increment) engine=MyISAM;
実際に各テーブルのストレージエンジンはinformation_schemaに移動すれば見ることができます。
mysql> use information_schema;
mysql> select table_name, engine from tables where table_schema = "test";
+-------------+--------+
| table_name  | engine |
+-------------+--------+
| innodb_test | InnoDB |
| myisam_test | MyISAM |
+-------------+--------+

レコード作成


それぞれのテーブルにレコードを作成します。
mysql> insert into innodb_test (id) values (0), (0), (0), (0), (0);
mysql> insert into myisam_test (id) values (0), (0), (0), (0), (0);
mysql> select * from innodb_test;
mysql> select * from myisam_test;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  4 |
|  5 |
+----+
とりあえず、2つレコードを削除しておきます。
mysql> delete from innodb_test where id in (4, 5);
mysql> delete from myisam_test where id in (4, 5);

テーブル最適化


それでは最適化してみます。
まずはInnoDBから。
mysql> optimize table innodb_test;
+------------------+----------+----------+-------------------------------------------------------------------+
| Table            | Op       | Msg_type | Msg_text                                                          |
+------------------+----------+----------+-------------------------------------------------------------------+
| test.innodb_test | optimize | note     | Table does not support optimize, doing recreate + analyze instead |
| test.innodb_test | optimize | status   | OK                                                                |
+------------------+----------+----------+-------------------------------------------------------------------+
およ、何かメッセージがでています。
どうやらInnoDBではoptimizeコマンドはALTER TABLEとして実行されるそうです。(その通知メッセージのようです。)
14.7.2.4 OPTIMIZE TABLE Syntax

続きましてMyISAMです。
mysql> optimize table myisam_test;
+------------------+----------+----------+----------+
| Table            | Op       | Msg_type | Msg_text |
+------------------+----------+----------+----------+
| test.myisam_test | optimize | status   | OK       |
+------------------+----------+----------+----------+
それでは、再度インサートします。
mysql> insert into innodb_test (id) values (0), (0);
mysql> insert into myisam_test (id) values (0), (0);
mysql> select * from innodb_test;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  6 |
|  7 |
+----+
mysql> select * from myisam_test;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  6 |
|  7 |
+----+
最適化ではやはり戻らないですね。
次は再起動を試してみます。

MySQL再起動


それでは再起動後にインサートしてみます。(再起動前はauto_incrementの値が13でした。)
mysql> select * from innodb_test;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  4 |
|  5 |
+----+

mysql> select * from myisam_test;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
| 13 |
| 14 |
+----+
InnoDBの方はauto incrementが戻っていました。
実際、テーブル情報を見ると、戻っていました。
mysql> show table status like 'innodb_test' \G;
*************************** 1. row ***************************
           Name: innodb_test
         Engine: InnoDB
        Version: 10
     Row_format: Dynamic
           Rows: 3
 Avg_row_length: 5461
    Data_length: 16384
Max_data_length: 0
   Index_length: 0
      Data_free: 0
 Auto_increment: 4
    Create_time: 2016-12-15 23:38:15
    Update_time: NULL
     Check_time: NULL
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options: 
        Comment: 

mysql> show table status like 'myisam_test' \G;
*************************** 1. row ***************************
           Name: myisam_test
         Engine: MyISAM
        Version: 10
     Row_format: Fixed
           Rows: 3
 Avg_row_length: 7
    Data_length: 56
Max_data_length: 1970324836974591
   Index_length: 2048
      Data_free: 35
 Auto_increment: 13
    Create_time: 2016-12-15 19:30:36
    Update_time: 2016-12-15 23:52:41
     Check_time: 2016-12-15 23:38:22
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options: 
        Comment: 


最適化では確認できませんでしたが、再起動ではInnoDBの方はauto_incrementの値が戻っておりました。
InnoDBではauto incrementのカラムをメモリ上のみに持ち、再起動のタイミングで以下で値を取得しているようです。
SELECT MAX(ai_col) FROM table_name FOR UPDATE;

参考資料
15.8.6 AUTO_INCREMENT Handling in InnoDB
【MySQL】AUTO_INCREMENTの値が戻る@InnoDBエンジンのテーブル
Changes in MySQL 5.5.9 (2011-02-07, General Availability)
MySQLの「InnoDB」と「MyISAM」についての易しめな違い
14.7.2.4 OPTIMIZE TABLE Syntax

0 件のコメント:

コメントを投稿