当者比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)
例え、
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;
sen_skipmode_setというMySQLネイティブな関数を追加してます。
この関数に値を渡すことによりスキップモードが有効になります。
select sen_skipmode_set(1)
select sen_skipmode_set(0)
使用例は
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);
+ share->keyinfo[i].senna = sen_index_create(buf, sizeof(my_off_t), SEN_INDEX_NORMALIZE, 0, sen_enc_default);
しかもsennaのsvnに反映された後に思い出すなんてタイミング悪すぎる。
ほんとごめんなさい。