mysql:11706
From: Kenta Hashimoto <Kenta Hashimoto <kem@xxxxxxxxxx>>
Date: Thu, 07 Jul 2005 20:18:56 +0900
Subject: [mysql 11706] Re: 全文検索と他条件の組み合わせ
佐々木様、宇野様、ありがとうございます。 質問内容が漠然としてしまっており、すみませんでした。 また、お返事が遅くなり、すみません。 データの量は、約13万行で、容量は245MBほどです。 MySQLのバージョンは、4.1.10aで、CentOS上で動かしています。 実行速度としては、以下のとおりでした。 単純化のために、CategoryBの条件は抜かしました。 <クエリ1> SELECT ID FROM Recipe WHERE MATCH( Title,Description ) AGAINST( '+"じゃがいも"' IN BOOLEAN MODE ) AND CategoryA = 4 LIMIT 10 の場合、145ms <クエリ2> SELECT ID FROM Recipe WHERE MATCH( Title ) AGAINST( '+"じゃがいも"' IN BOOLEAN MODE ) LIMIT 10 の場合、1ms <クエリ3> SELECT ID FROM Recipe WHERE CategoryA = 4 LIMIT 10 の場合、1msです。 >>CagetoryA、CategoryB について、インデックスを使用できない >>でいることが、クエリが遅い原因だと考えています。 > > 何故そう思いました? EXPLAINをつけて調べた結果、 使用しているキーが、全文検索のインデックスだったからです。 で、いろいろ調べるうちに、一つのクエリに使用できるインデックスは 一つのみだということがわかり、上記の書き方では、全文検索のインデックス のみしか使用されていないということがわかりました。 副問い合わせを用いたクエリでは、より遅くなってしまいました。 <クエリ4> SELECT ID FROM Recipe WHERE MATCH( Title ) AGAINST( '+"じゃがいも"' IN BOOLEAN MODE ) AND ID IN ( SELECT ID FROM Recipe WHERE CategoryA=4 ) LIMIT 10 これで、232msかかりました。 副問い合わせ部分を逆に全文検索にしてみると、810msかかります。 これは、副問い合わせ部分に、LIMITをつけれないからではないかと 思います。 考えたのですが、もしかして、この速度の違いは、LIMITによる 制限のせいでしょうか? つまり、上記のクエリ1では、見つかるレシピ数が 少なくなるために、10個目のレシピが見つかるまで時間がかかるが、 クエリ2、クエリ3では、見つかるレシピが多いため、 10個目のレシピがすぐにみつかり、処理がそこで打ち切られる ということでしょうか? 実際、クエリ1の形で、より多くのレシピが該当するような 値で検索した場合は、6ms程度で済みました。 > はしけむさんの案1のように、 > 全 Category を文字列として結合したキー項目を一つ用意して、 > その項目にインデックスを作成するという手も有効です。 > 副問合せの部分が速くなると思います。 > この場合 FULLTEXT じゃなくて INDEX の方ですね。 副問い合わせを使うと、副問い合わせ部分にLIMITが かけれないと思うので、副問い合わせは使わない方法で 考えたほうがよいかと思っています。 となると、 FULLTEXT( Title,Description,CategoryString ) という形で、全文検索に含めてしまったほうがいいかと思いますが、 この場合には、もしかして「カーディナリティ値」の問題が 出てきてしまいますでしょうか。 具体的には、 「CategoryA4 CategoryB2」などの、TitleやDescriptionには 通常含まれない単語を、CategoryStringに登録して、全文検索の 対象にしようかと考えています。 T.Sasaki wrote: > 佐々木といいます。 > > >>CagetoryA、CategoryB について、インデックスを使用できない >>でいることが、クエリが遅い原因だと考えています。 > > 何故そう思いました? > > >>Categoryは、9種類あり、それぞれ、2〜8種類の値が入ります。 > > レコード数が10万なら各 Category のカーディナリティ値が低すぎますので、 > FULLTEXT 以外のインデックスは複数の項目から構成されているものと仮定します。 > (一つの問合せで使用できるインデックスは一つだけですから) > > その上で、純粋に SQL だけで解決するなら・・・。 > > SELECT ID FROM Recipe > WHERE MATCH (Title, Description) AGAINST('+"じゃがいも"' IN BOOLEAN MODE) > AND ID IN (SELECT ID FROM Recipe WHERE CategoryA = 4 AND CategorB = 2); > > MySQL のオプティマイザ次第ですが、 > 副問合せを利用すれば両方のインデックスが活用できます。 > (MySQL 4.1 以上) > > はしけむさんの案1のように、 > 全 Category を文字列として結合したキー項目を一つ用意して、 > その項目にインデックスを作成するという手も有効です。 > 副問合せの部分が速くなると思います。 > この場合 FULLTEXT じゃなくて INDEX の方ですね。 > > また、全文検索だと該当レコードが膨大な数になる可能性が高いため、 > LIMIT 句等を使用して取得レコード数の上限を制限する必要があるでしょう。 > > とりあえず、全文検索と通常の検索を切り離して、個々に検索時間を計測し、 > 遅い方の SQL を EXPLAIN 等でコストを見つつ、許容範囲内に収まるよう、 > データベース環境を含め調整していくのが良いのではと考えます。 > それから上記のような形で2つの SQL を結合してはどうでしょうか。 > > 尚、私の環境は senna のMySQLバインディングを > 無理やり MySQL 5.0 へ埋め込んだものなので、ネイティブの > 全文検索機能と結果が異なる可能性があります。:-)
11693 2005-07-06 16:07 [Kenta Hashimoto <kem] 全文検索と他条件の組み合わせ 11694 2005-07-07 00:55 ┣[UNO Shintaro <uno@xx] 11697 2005-07-07 09:58 ┗["T.Sasaki" <papasan2] -> 11706 2005-07-07 20:18 ┗[Kenta Hashimoto <kem] 11707 2005-07-07 20:47 ┗["T.Sasaki" <papasan2] 11712 2005-07-07 21:39 ┗[Kenta Hashimoto <kem] 11713 2005-07-07 21:58 ┗["T.Sasaki" <papasan2] 11714 2005-07-07 22:14 ┗[Kenta Hashimoto <kem] 11715 2005-07-07 22:56 ┗["T.Sasaki" <papasan2] 11716 2005-07-07 23:10 ┣[Kenta Hashimoto <kem] 11717 2005-07-07 23:17 ┗[Kazuhiro Osawa <ko@x] 11719 2005-07-08 00:14 ┣[Kenta Hashimoto <kem] 11720 2005-07-08 06:25 ┗["T.Sasaki" <papasan2] 11734 2005-07-09 13:45 ┗[Kazuhiro Osawa <ko@x] 11735 2005-07-09 20:31 ┣["T.Sasaki" <papasan2] 11736 2005-07-12 15:33 ┗["Naoi Masaaki" <naoi] MySQLでの最大項目数につきまして 11737 2005-07-12 16:33 ┣[Tetsuro IKEDA <ikdtt] 11739 2005-07-12 17:42 ┃┗["Naoi Masaaki" <naoi] 11738 2005-07-12 17:10 ┗[Hiroshi Moriyama <mt] 11740 2005-07-12 17:47 ┣["Naoi Masaaki" <naoi] 11742 2005-07-13 20:08 ┗["T.Sasaki" <papasan2]