2014年4月15日火曜日

MroongaのラッパーモードでInnoDBを使う落とし穴

Mroonga(ストレージモード)はトランザクション非対応だから、ラッパーモードでInnoDBにしてトランザクション…とか考えているとハマる(かもしれない)落とし穴。

Mroongaのラッパーモードは「データは任意のストレージエンジンに」「転置索引はGroonga上に」作るモードであって、飽くまでGroonga上ではトランザクションは利きません。つまり、こういうことが起こる。


mysql56> CREATE TABLE t1 (num int, val varchar(32), primary key(num), fulltext key(val)) Engine= Mroonga COMMENT= 'engine "innodb"';
Query OK, 0 rows affected (0.09 sec)

mysql56> INSERT INTO t1 VALUES (1, 'yoku0825');
Query OK, 1 row affected (0.01 sec)

mysql56> SELECT * FROM t1;
+-----+----------+
| num | val      |
+-----+----------+
|   1 | yoku0825 |
+-----+----------+
1 row in set (0.01 sec)

mysql56> SELECT * FROM t1 WHERE match(val) against('yoku');
+-----+----------+
| num | val      |
+-----+----------+
|   1 | yoku0825 |
+-----+----------+
1 row in set (0.00 sec)

mysql56> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql56> UPDATE t1 SET val= 'updated' WHERE num= 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql56> SELECT * FROM t1;
+-----+---------+
| num | val     |
+-----+---------+
|   1 | updated |
+-----+---------+
1 row in set (0.00 sec)

mysql56> SELECT * FROM t1 WHERE match(val) against('yoku');
Empty set (0.00 sec)

mysql56> SELECT * FROM t1 WHERE match(val) against('update');
+-----+---------+
| num | val     |
+-----+---------+
|   1 | updated |
+-----+---------+
1 row in set (0.00 sec)

mysql56> ROLLBACK;
Query OK, 0 rows affected (0.01 sec)

mysql56> SELECT * FROM t1;
+-----+----------+
| num | val      |
+-----+----------+
|   1 | yoku0825 |
+-----+----------+
1 row in set (0.00 sec)

mysql56> SELECT * FROM t1 WHERE match(val) against('yoku');
Empty set (0.00 sec)

mysql56> SELECT * FROM t1 WHERE match(val) against('update');
+-----+----------+
| num | val      |
+-----+----------+
|   1 | yoku0825 |
+-----+----------+
1 row in set (0.00 sec)

飽くまで転置索引は既に更新されていて、ROLLBACKが利くのは「データの格納されているInnoDB部分」だけ。この状態を解消するには、転置索引を作り直してやるしかない(と思う)

mysql56> ALTER TABLE t1 DISABLE KEYS;
Query OK, 0 rows affected (0.00 sec)

mysql56> ALTER TABLE t1 ENABLE KEYS;
Query OK, 0 rows affected (0.06 sec)

mysql56> SELECT * FROM t1 WHERE match(val) against('yoku');
+-----+----------+
| num | val      |
+-----+----------+
|   1 | yoku0825 |
+-----+----------+
1 row in set (0.01 sec)

mysql56> SELECT * FROM t1 WHERE match(val) against('update');
Empty set (0.00 sec)

飽くまで「こういうもの」として考えておかないと、ヒットする/しないがシビアなところだと失敗するかも知れません。基本的に俺はストレージモード推しです。

なお、「(パラメーターによるけど)InnoDBのトランザクション機能でデータ部分は保護される」のは事実なので、クラッシュしてGroonga部分が壊れても(ストレージモードだとここでバックアップからリストアコース)データ部分はリストアする必要がなく、転置索引さえ再作成すればOK、というのはありますね。転置索引に比べてデータ部分が十分大きい場合には、リカバリーの時間短縮と考えられるかも知れません(ちゃんと計ってない)

誰か計ったら教えてください :)


【2014/04/16 10:16】
中の人が教えてくだれました :)



ありがとうございます。

0 件のコメント :

コメントを投稿