Mroongaの完全転置インデックスによる全文検索はどのくらい速いのか

2016/4/10 訂正
InnoDBは「転置インデックス」と書きましたがこれは誤りであり、InnoDBについても「完全転置インデックス」を採用しています。
このことは下記のサイトにも明示されています。
Groonga - InnoDB純正の全文検索エンジンInnoDB FTS

またMySQL公式ページでも「転置インデックス」とありますが、「単語のリスト、および単語ごとに、その単語が出現するドキュメントのリストが格納されます。」とあり、完全転置インデックスが採用されていることがわかります。
MySQL :: MySQL 5.6 リファレンスマニュアル :: 14.2.13.3 FULLTEXT インデックス

以上のことからInnoDBもMroongaも「完全転置インデックス」を採用しており、パフォーマンスの差は他に原因があると思われます。
なお記載した検証は実際に行って得られた結果であることは間違いないため、本記事の内容はMroongaの導入手順や、パフォーマンス比較の一例として参照いただければと思います。

前回の記事で全文検索には「転置インデックス」と「完全転置インデックス」があり、InnoDBでは前者を利用しているがためフレーズ検索のパフォーマンスが悪化することに触れました。
quotto.hatenablog.com


そこで今回は後者の「完全転置インデックス」を使ったフレーズ検索でどの程パフォーマンス向上ができるのか、インストールから順を追って検証してみます。

利用するストレージエンジンはMroongaです。
MroongaはGroongaという全文検索エンジンをベースとした、MySQL用のストレージエンジンであり完全転置インデックスが使われます。
Mroonga - MySQLで高速日本語全文検索

環境

OSはMacOS X、MySQL5.7で検証しました。

Mroongaの導入

インストール

MySQL5.1以降はプラグイン形式で導入可能となっており、
導入方法は公式サイトにプラットフォームごとの手順が掲載されています。
2. インストール — Mroonga v8.03 documentation

Macの場合は、homebrewでの導入となります。

% brew install https://raw.github.com/mroonga/homebrew/master/mroonga.rb --use-homebrew-mysql

ただしこの方法はhomebrewでMySQLとMroongaを同時にインストールする前提です。
homebrew以外で導入したMySQLに対してMroongaだけをインストールする場合は、以下のとおりとなります。
(一部抜粋。詳細は公式サイトのReadMeを参照。)

% brew tap mroonga/mroonga
% PATH="$HOME/local/mysql-5.5.24/bin:$PATH" brew install mroonga --with-mysql-source=MySQLインストールパス

GitHub - mroonga/homebrew-mroonga: The homebrew formula for Mroonga.

インストール確認

正常にインストールされれば、SHOW ENGINESで一覧に表示されます。

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         |
| Mroonga            | YES     | CJK-ready fulltext search, column store                        | NO           | NO   | NO         |
| PERFORMANCE_SCHEMA | YES     | Performance Schema                                             | NO           | NO   | NO         |
| FEDERATED          | NO      | Federated MySQL storage engine                                 | NULL         | NULL | NULL       |
| ARCHIVE            | YES     | Archive storage engine                                         | NO           | NO   | NO         |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+

もしここで一覧に表示されなければ、手動でプラグインのインストールを実行してみましょう。

mysql> INSTALL PLUGIN mroonga SONAME 'ha_mroonga.so';

※ここでエラーが出る場合は(例えば'ha_mroonga.so'が見つからないとか)最初のインストール手順からやり直してみましょう。

ストレージエンジンをMroongaへ切り替える

Mroongaが導入できたら、次はInnoDBをMroongaへ切替ます。
ストレージエンジンはテーブルごとに設定が可能であり、現在ストレージエンジンに何を採用しているかはSHOW CREATE TABLEで確認できます。

mysql> SHOW CREATE TABLE fruits_for_ngram;
+------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table            | Create Table                                                                                                                                                                                                                                             |
+------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| fruits_for_ngram | CREATE TABLE `fruits_for_ngram` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `desctext` text,
  PRIMARY KEY (`id`),
  FULLTEXT KEY `desctext` (`desctext`)
) ENGINE=InnoDB AUTO_INCREMENT=400001 DEFAULT CHARSET=utf8 |
+------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+


ストレージエンジンの切替はALTER TABLEで行えます。

mysql> ALTER TABLE fruits_for_ngram ENGINE=mroonga;
Query OK, 400000 rows affected (2 min 15.85 sec)
Records: 400000  Duplicates: 0  Warnings: 0

もう一度SHOW CREATE TABLEで確認すると、ENGINE=mroongaとなっています。

SHOW CREATE TABLE fruits_for_ngram;
+------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table            | Create Table                                                                                                                                                                                                                                              |
+------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| fruits_for_ngram | CREATE TABLE `fruits_for_ngram` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `desctext` text,
  PRIMARY KEY (`id`),
  FULLTEXT KEY `desctext` (`desctext`)
) ENGINE=Mroonga AUTO_INCREMENT=400001 DEFAULT CHARSET=utf8 |
+------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

パフォーマンスは改善されたのか

それでは早速、Mroonga(完全転置インデックス)でパフォーマンスが改善されているか確認してみます!
ちなみにInnoDBでの400,00件データの中から「メロン」を含むデータを抽出するフレーズ検索は、12秒かかっていました。
(詳細は冒頭で紹介した前回記事を参照。)

mysql> select count(*) from fruits_for_ngram where match(desctext) against('"メロ ロン"');
+----------+
| count(*) |
+----------+
|   100000 |
+----------+
1 row in set (12.25 sec)

ではMroongaではどうでしょう。

mysql> select count(*) from fruits_for_ngram where match(desctext) against('"メロ ロン"'); 
+----------+
| count(*) |
+----------+
|   100000 |
+----------+
1 row in set (0.09 sec)

は、速い!!

like検索に対してもパフォーマンス面では優位性を保っています。

mysql> select count(*) from fruits_for_or where desctext like ('%メロン%');                     
+----------+
| count(*) |
+----------+
|   100000 |
+----------+
1 row in set (1.30 sec)

まとめ

プラグインとして導入する面倒はありますが、データ量が多くなり特にフレーズ検索を利用するような場合はぜひMroongaを使いましょう!

基礎からのMySQL 改訂版 (基礎からシリーズ)

基礎からのMySQL 改訂版 (基礎からシリーズ)