[Senna-dev 619] Re: 複数カラムに対するOR検索時のパフォーマンス悪化について

Back to archive index

Tetsuro IKEDA ikdtt****@gmail*****
2007年 6月 26日 (火) 13:27:55 JST


こんにちは。池田@Tritonnです。

解決法については既に末永さんが提示されている方法が良いと思います。

ということで、なぜORだと遅いのかということですが・・・。

以下のようにMATCH検索をORでつなぐと、fulltext検索が行われず、
テーブルのFullScanとなってしまうようです。

SELECT ... WHERE MATCH(c1) AGAINST("key1") OR MATCH(c2) ATAINST("key2");

これはTritonnを使ったMySQL+Senna、あるいはオリジナルのMySQLであるかに
関わらず発生しました。

Explainを見ると、ANDの場合はfulltextインデックスが使用されるのですが、

[test] > explain select * from t1
where match(c1) against("hoge") and match(c2) against("fooo")\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
         type: fulltext
possible_keys: ft,ft2
          key: ft
      key_len: 0
          ref:
         rows: 1
        Extra: Using where
1 row in set (0.00 sec)

ORの場合は、type=ALLつまりFullScanとなってしまっています。

[test] > explain select * from t1
where match(c1) against("hoge") or match(c2) against("fooo")\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 524304
        Extra: Using where
1 row in set (0.00 sec)

異なるキーに対する絞りこみ結果をORで併せる場合、Btreeインデックス
であればIndex Mergeアルゴリズムにより双方のBtree検索結果のマージが
行われるのですが、Fulltext検索についてはマージするアルゴリズムが
MySQLにはまだ実装されていないという事情があります。

このあたりの事情を独自実装で改善するという試みが2ind機能なのですが、
このパタンには対応できていない(set senna_2ind=ONでも効果無し)ようです。

とりあえず、この現象が発生した理由の説明だけですが、
こんな感じです・・・。

07/06/25 に Yuki Horikoshi<horik****@maste*****> さんは書きました:
> 末永様
>
> 適切・迅速なご回答ありがとうございます。
> 内容についても大変わかりやすく、とても参考になりました。
>
> 今回は
> > CREATE TABLE TAB1 (COL1 TEXT, COL2 TEXT, FULLTEXT(COL1, COL2));
> にて高速な結果取得が可能になりました。
>
> > SELECT * FROM TAB1 FORCE INDEX (PRIMARY)
> >  WHERE MATCH(COL1) AGAINST ('検索語') OR
> >        MATCH(COL2) AGAINST ('検索語');
> こちらも若干の速度改善(10%程度)が見られましたが、
> like検索よりは時間がかかってしまうようでした。
>
> 取り急ぎ、インデックス形式の変更にて期待通りの結果が出ました。
> 本当にありがとうございました。
>
> > 未来検索ブラジルの末永です。
> > 複数カラムを対象としたOR検索が遅い件についてです。
> >
> > ●解決方法1
> >
> > まず、TAB1の定義を以下のように変更します。
> > CREATE TABLE TAB1 (COL1 TEXT, COL2 TEXT, FULLTEXT(COL1, COL2));
> >
> > そして、
> > SELECT * FROM TAB1 WHERE MATCH(COL1, COL2) AGAINST('検索語');
> > を実行すると所望の結果が得られます。
> >
> > 現在のTritonnの実装では、複数のカラムに対してインデックスを作成した場合、
> > SELECT CONCAT(COL2, " ", COL1) AS COL FROM TAB1;
> > で取得できる値COLをインデックスの対象にします。
> > (インデックス定義時のカラムの順番に対して逆順で連結しています)
> >
> > よって、COL1とCOL2に対してインデックスを作成して、
> > それに対して検索をかけることで、
> > COL1またはCOL2に検索単語が存在するレコードが取得できます。
> >
> > ●解決方法2
> > UNIONで高速ということであれば、
> > もしかしたら以下のクエリで速度が上がる可能性があります。
> >
> > SELECT * FROM TAB1 FORCE INDEX (PRIMARY)
> >  WHERE MATCH(COL1) AGAINST ('検索語') OR
> >        MATCH(COL2) AGAINST ('検索語');
> >
> > なお、この場合はSennaが2回呼ばれてしまうので、
> > 解決方法1よりも速度が劣ると思います。
> >
> > ●メモ
> > 一般的にOR検索は検索結果が増えてしまうので、
> > 処理速度が遅くなる傾向にあります。
> >
> > たとえば、
> > SELECT * FROM TAB1
> >  WHERE MATCH(COL1) AGAINST('未来 検索' IN BOOLEAN MODE);
> > と
> > SELECT * FROM TAB1
> >  WHERE MATCH(COL1) AGAINST('*D+未来 検索' IN BOOLEAN MODE);
> > では後者のほうが速く検索することができます。
>
> ---
> Yuki Horikoshi <horik****@maste*****>
>
> _______________________________________________
> Senna-dev mailing list
> Senna****@lists*****
> http://lists.sourceforge.jp/mailman/listinfo/senna-dev
>




Senna-dev メーリングリストの案内
Back to archive index