4

このクエリを使用して、MySQLデータベースで全文検索を実行しています。

SELECT DISTINCT 
questions.id, 
questions.uniquecode, 
questions.spam,
questions.questiondate,
questions.userid,
questions.description,
users.login AS username,
questions.questiontext,
questions.totalvotes,
MATCH(questions.questiontext, questions.uniquecode) 
AGAINST ('rock guitarist chick*' IN BOOLEAN MODE) AS relevance 

FROM questions 

LEFT JOIN users ON questions.userid = users.id 
LEFT JOIN answer_mapping ON questions.id = answer_mapping.questionid 
LEFT JOIN answers ON answer_mapping.answerid = answers.id
LEFT JOIN tagmapping ON questions.id = tagmapping.questionid
LEFT JOIN tags ON tagmapping.tagid = tags.id 

WHERE questions.spam < 10 

AND 

(
  MATCH(questions.questiontext, questions.uniquecode) 
  AGAINST ('rock guitarist chick*' IN BOOLEAN MODE) 

OR MATCH(answers.answertext) AGAINST ('rock guitarist chick*' IN BOOLEAN MODE) 

OR MATCH (tags.tag) AGAINST ('rock guitarist chick*' IN BOOLEAN MODE)

) GROUP BY questions.id ORDER BY relevance DESC

結果は非常に関連性がありますが、検索は非常に遅く、テーブルが大きくなるにつれてますます遅くなっています。

テーブル統計:

質問-400レコード

インデックス

  • プライマリBTREE-id
  • BTREE-uniquecode
  • BTREE-質問日
  • BTREE-ユーザーID
  • フルテキスト-質問テキスト
  • フルテキスト-uniquecode

回答-3,635レコード

インデックス

  • PRIMARY-BTREE-id
  • BTREE-回答日
  • BTREE-questionid
  • フルテキスト-アンサーテキスト

answer_mapping -4,228レコード

インデックス

  • PRIMARY-BTREE-id
  • BTREE-answerid
  • BTREE-questionid
  • BTREE-ユーザーID

タグ-1,847レコード

インデックス

  • PRIMARY-BTREE-id
  • BTREE-タグ
  • フルテキスト-タグ

タグマッピング-3,389レコード

インデックス

  • PRIMARY-BTREE-id
  • BTREE-tagid
  • BTREE-questionid

なんらかの理由でタグマッピングタグを削除すると、検索が大幅に高速化されます。

このクエリを高速化するためのヒントはありますか?

前もって感謝します!

4

3 に答える 3

2

あなたも走ろうとするかもしれません OPTIMIZE TABLE questions

これは、私が取り組んでいるプロジェクトで同様のクエリを高速化するのに役立ちました。

参照を参照してください:https ://dev.mysql.com/doc/refman/5.7/en/fulltext-fine-tuning.html

于 2017-02-09T18:20:57.687 に答える
1

結合をキャッシュされたビューや追加のテーブルなどに組み合わせることができます。クエリキャッシュをアクティブにして、キャッシュできるように結合を選択として定義します。十分なメモリなどを確保しますが、それがボトルネックになることはありません。おそらくあなたの場合、それは... 400レコードしかないからですか?それは何もありません...そしてすでに遅いですか?残りはよさそうだから。どのような種類のハードウェア/構成を実行していますか?

しかしまあ、これは間違ったアプローチだと思います。mysqlはそのために設計されていません。実際、全文機能はmyisamに限定されています。

dismaxリクエストハンドラーを使用したlucene / solrの使用を検討する必要があります。数十万のドキュメントのインデックスを使用して、約50ミリ秒から100ミリ秒で良好な結果が得られるはずです。ある時点でシャーディングして、レコード数が実質的に無制限になるようにすることができます。さらに、より良いオプションがあり、より良い結果を達成できます。たとえば、あいまい一致を実行したり、新しいドキュメントに重みを付けたり、タイトルよりも関連性の高いタグを付けたり、クエリ後の分析やファセットなどを実行したりします。

于 2010-10-03T01:21:24.317 に答える
0

クエリの作成は複数の理由でゆっくりと機能しますが、詳細はわかりません。EXPLAIN FORMAT=JSON SELECT ...さらなる議論のために提供してください。

その間、より速く動作するようにクエリを書き直してみましょう。(そして、まだ遭遇していないバグを取り除くかもしれません。)

まず、これをデバッグしてみましょう。3つの別々のクエリで3つのFT検索を実行し、それぞれから()UNIONだけquestion_ids結合します。

    ( SELECT question_id,
         MATCH (... ) as relevance
         FROM questions
         WHERE MATCH (questiontext, ...) AGAINST ... )
    UNION ALL
    ( SELECT am.question_id,
         MATCH (... ) as relevance
         FROM answers AS a
         JOIN answer_mapping AS am ON am.answerid = a.id
         WHERE MATCH (a.answertext) AGAINST ... )
    UNION ALL
    ( SELECT tm.question_id,
         MATCH (... ) as relevance
         FROM tags AS t
         JOIN tagsmapping tm ON ...
         WHERE MATCH (t.tag) AGAINST ... )

各サブクエリが、FTインデックスを持つテーブルで始まりquestion_id、最後に。で終わるように設計されていることに注目してください。

さて、中間クエリ:

SELECT question_id,
         MAX(relevance)  -- (this fixes the unseen bug)
    FROM ( that query ) AS q1
    GROUP BY question_id
    ORDER BY relevance DESC  -- optional; needed for `LIMIT`
    LIMIT 20          -- to limit the rows, do it at this stage

それが十分に速くうまくいき、「正しい」を提供するなら、question_ids私たちは先に進むことができます...

これをサブクエリとして使用して、残りのデータを取得します。

SELECT .... -- the `questions` fields, using `q....`,
       ( SELECT login FROM users WHERE q.userid = id ) AS username
    FROM ( the intermediate query ) AS q2
    JOIN questions AS q
    questions q.spam < 10 
    ORDER BY q2.relevance

はい、これはJOINingに戻りますがquestions、より高速であることがわかります。

ここではが必要ではないことに注意してGROUP BYください。また、内部クエリにが含まれている場合、LIMITここでは必要ありません。

すべてが正しく行われなかった場合は、お詫び申し上げます。予想以上に多くの変化がありました。

于 2017-02-14T00:35:15.867 に答える