The Wayback Machine - https://web.archive.org/web/20140317033549/http://blog.yappo.jp:80/yappo/archives/000264.html

2005年07月01日

当者比50~100倍程のスピードアップ(クエリ/テーブル構造による)のパッチです。

MySQL(特にFullText boolean mode)のlimitの実装はある意味効率の悪い実装になっている。
例えば、limit 100000,100といったクエリを投げると100100行分のデータをディスクから読み込むのである。
まぁ、whereなどの条件に一致する100000件のレコードを先に確定させなければいけない訳で当然といえば当然である。
order byとか使ってたらなおさら。
無論SQL_CALC_FOUND_ROWSなんか使ってると全件確定させなきゃいけないから大変。
当然これらはindexを使用していない時の挙動だと思う。
indexのみが使われたクエリの挙動は未確認だけど。

さて、ここから本題。


では、Senna+MySQLの挙動はどうなっているのか?(in boolean mode)
例え、select * from table where match(field) against('key' in boolean mode) limit 10000,10といったクエリを投げると、必ず10010件の行を読むのである。
limitで絞って高速だぜYeha!なんて思っても思い通りに行かないのである。
いくら、and/orなどの演算子の結合処理などをMySQL側にやらせているからといってあんまり。
各単語のポジションリストだけ見れば、行データを見なくても一致行を確定できるのに。
そりゃ、order byしちゃったり他のフィールドを見たりしたら駄目だけど
見る必要も無いデータを読むなんて無駄杉。

って事で、in boolean mode限定で高速モードを実装しました。
意図した数の行しかディスクアクセスしなくなります。
ヒット件数が多いクエリの

select * from table where match(field) against('+key' in boolean mode) limit 1000, 10;


select sql_calc_found_rows * from table where match(field) against('+key' in boolean mode) limit 10;

等に効果があります。
whereにmatch以外を用いたり、order byしたり、group byしたり、havingした場合の障害には、さらに責任持ちません。

sen_skipmode_setというMySQLネイティブな関数を追加してます。
この関数に値を渡すことによりスキップモードが有効になります。

select sen_skipmode_set(1)

で、スキップモードon
select sen_skipmode_set(0)

で、スキップモードoffです。

使用例は


select sen_skipmode_set(1);
select sql_calc_found_rows title, comment from sites where match(keywords) against('+key +key2' in boolean mode) limit 10000, 100;
select sen_skipmode_set(0);
select found_rows();

って感じでしょうね。


実装方法は、pthread_key_*系のスレッド内のグローバル変数を使って簡潔に仕上げてます。
sen_skipmode_setでの値をグローバル領域に保存しつつ、sql_select.cc内にて、limitの値をグローバル領域に保存して
ft_boolean_search.cでは受け取った値を元にディスクアクセスするかどうかを決定する感じです。

in boolean modeじゃ無い方には対応してません。

現在は、linux上のMySQL4.0.24のみでの動作を確認中むしろ問題なく動いています。
インストールの仕方は、素のMySQLソースにパッチしてください。
mysql-4.0.24.senna.sen_skipmode_set.diff

7/1 17:40追記:
やってしまった。。。
このパッチが

+              share->keyinfo[i].senna = sen_index_create(buf, sizeof(my_off_t), SEN_INDEX_NORMALIZE | SEN_INDEX_NGRAM | SEN_INDEX_SPLIT_ALPHA | SEN_INDEX_SPLIT_DIGIT | SEN_INDEX_SPLIT_SYMBOL, 0, sen_enc_default);

になってた。。。
要するにMeCabを使わずにN-Gramでindexを作るモードです。
iYappoでの導入のために、Sennaのpatchファイルをいじっていたのを忘れてました。。。
いじくってるのはここだけなので、あとは大丈夫です。
問題の行を
+              share->keyinfo[i].senna = sen_index_create(buf, sizeof(my_off_t), SEN_INDEX_NORMALIZE, 0, sen_enc_default);

に書き換えてアップしなおしています。
もし17時40分以前のパッチをお使いの方がいらしたら、再度作り直しをお願いします。

しかもsennaのsvnに反映された後に思い出すなんてタイミング悪すぎる。
ほんとごめんなさい。

Posted by Yappo at 2005年07月01日 05:02 | TrackBack | 検索システム構築
Comments
Post a comment









Remember personal info?






コメントを投稿する前に↓の場所にnospamと入力してください。