隔週連載groonga

第6回 [実録] MySQL向け全文検索エンジン「Tritonn」から「mroonga」への移行ガイド(1)

この記事を読むのに必要な時間:およそ 6 分

ストレージエンジンをMyISAMからInnoDBへ切り替える際の注意

mroongaと間接的に関わる話として,MyISAMからInnoDBへ乗り換えるときにハマりやすい挙動の違いを紹介します。それは,Auto Incrementの挙動がMyISAMとInnoDBで異なるということです。 Tritonn/MyISAMを利用しているシステムをInnoDB化する際,次の2点について確認が必要です。

  • 以下に該当するクエリを利用している
    • INSERT IGNORE INTO ...
    • INSERT INTO ... ON DUPLICATE KEY UPDATE ...
    • LOAD DATA ... IGNORE INTO ...
  • 行削除するケースがある

具体的にどのような挙動の違いがあるか,次のテーブルを利用して説明します。

-- テーブルを作成
CREATE TABLE test (
  id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(10),
  UNIQUE INDEX (name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
IGNORE INTO文の動作の違い

INSERT IGNORE INTO ...を用いて解説します。なお,INSERT INTO ... ON DUPLICATE KEY UPDATE ...の挙動も同一です。

-- 1つめのレコードを入れます
mysql> INSERT IGNORE INTO test (name) VALUES('トマト');
Query OK, 1 row affected (0.00 sec)

-- 1件目なので,1が返ります
mysql> SELECT LAST_INSERT_ID()\G
*************************** 1. row ***************************
LAST_INSERT_ID(): 1
1 row in set (0.00 sec)

-- 重複のためスキップされるレコードを入れます
mysql> INSERT IGNORE INTO test (name) VALUES('トマト');
Query OK, 0 rows affected (0.00 sec)

-- 重複のため,1のままです
mysql> SELECT LAST_INSERT_ID()\G
*************************** 1. row ***************************
LAST_INSERT_ID(): 1
1 row in set (0.00 sec)

-- 重複とならないデータを追加します
mysql> INSERT IGNORE INTO test (name) VALUES('トマト2');
Query OK, 1 row affected (0.00 sec)

-- MyISAMではidが2となるのですが,InnoDBでは3となります
mysql> SELECT LAST_INSERT_ID()\G
*************************** 1. row ***************************
LAST_INSERT_ID(): 3
1 row in set (0.00 sec)

-- InnoDBのテーブル内容は以下の通りです
mysql> select * from test;
+----+------------+
| id | name       |
+----+------------+
|  1 | トマト     |
|  3 | トマト2    |
+----+------------+
2 rows in set (0.00 sec)
データを削除した時のプライマリキーの挙動の違い

InnoDBの場合,Auto Incrementで取る値は保持されません。MySQLを一度終了すると,実際に格納されている主キーの最大値+1に自動調整となる挙動を示します。

具体例とともに解説します。

-- まずは1件目のデータを挿入します
mysql> INSERT INTO test (name) VALUES('トマト1');
Query OK, 1 row affected (0.02 sec)

-- 続けて2件目のデータを挿入します
mysql> INSERT INTO test (name) VALUES('トマト2');
Query OK, 1 row affected (0.02 sec)

-- 期待通り,idは2となりました
mysql> SELECT LAST_INSERT_ID()\G
*************************** 1. row ***************************
LAST_INSERT_ID(): 2
1 row in set (0.00 sec)

-- idが2のデータを削除します
mysql> DELETE FROM test WHERE name IN('トマト2');
Query OK, 1 row affected (0.03 sec)

-- 続けて3件目のデータを挿入します
mysql> INSERT INTO test (name) VALUES('トマト3');
Query OK, 1 row affected (0.03 sec)

-- 期待通り,idは3となりました
mysql> SELECT LAST_INSERT_ID()\G
*************************** 1. row ***************************
LAST_INSERT_ID(): 3
1 row in set (0.00 sec)

-- idが3のデータを削除します
mysql> DELETE FROM test WHERE name IN('トマト3');
Query OK, 1 row affected (0.02 sec)

-- ここで,MySQLを再起動し,再度接続後に以下の行を挿入します
mysql> INSERT INTO test (name) VALUES('トマト4');
Query OK, 1 row affected (0.03 sec)

-- 再起動により,MyISAMでは4となる一方,InnoDBでは2となりました
mysql> SELECT LAST_INSERT_ID()\G
*************************** 1. row ***************************
LAST_INSERT_ID(): 2
1 row in set (0.00 sec)

-- InnoDBのテーブル内容は以下の通りです
mysql> select * from test;
+----+------------+
| id | name       |
+----+------------+
|  1 | トマト1    |
|  2 | トマト4    |
+----+------------+
2 rows in set (0.01 sec)

この挙動となる仕組みについては,MySQLリファレンスマニュアルのAUTO_INCREMENT カラムが InnoDB 内でどのように機能するかにて解説されています。

なお,mroongaのストレージモードも,このInnoDBと同じ挙動となります。これらの挙動によるトラブルが想定できる場合,ラッパーモードを利用した上でストレージエンジンをMyISAMにした方が良いでしょう。COMMENT='engine "myisam"'と指定することで,引き続きMyISAMを利用できます。

その他,MyISAMとInnoDBの違いを8つの角度から解説している漢(オトコ)のコンピュータ道: MyISAMからInnoDBへ切り替えるときの注意点も併せてご参照ください。

パーティショニング

InnoDBラッパーモードそのものでは,パーティショニングに対応していません。もしパーティショニングが必要な場合には,Spider 3.0と組み合わせることで実現できます。

具体的な方法に関しては,mroongaってなんじゃ?(Spiderで分散全文検索)を参照ください。

まとめと次回予告

今回はTritonnとmroongaそれぞれの紹介と移行時の要注意点,現在利用できる日本語全文検索ソリューションの比較を行いました。

次回は,より具体的なシステム移行に関するお話をお届けする予定です。ご期待ください。

groongaの利用事例を寄稿しませんか

連載の目的は「読者の皆さんがgroongaを使いたくなる!」ことです。そこで,すでにgroongaを使っており,groongaの利用事例を本連載で紹介していただける人を募集します。募集要項を参考にご連絡ください。お待ちしています!

著者プロフィール

吉田健太郎(Kentaro Yoshida)

株式会社リブセンス,Web系インフラの研究開発エンジニア。

ITベンチャー立ち上げに参画し,幅広い領域での経験を積むこと8年目。フルスタックエンジニアを目指して,湧き出るアイディアを形にする日々を過ごしている。

GitHub:https://github.com/y-ken/
ブログ:http://y-ken.hatenablog.com/