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 >