web-dev-qa-db-ja.com

複数の列の複数の値に一致するMySQL検索

検索をスピードアップする必要があります。現在、ユーザーに名前の入力を許可しています:John Doe

次に、Javaで、その文字列を分割して複数の値(または「用語」)["John"、 "Doe"]を作成し、提供された用語をループして、データベースで選択を行い、それを探します関連するいくつかの列の用語:

// For each term in the string[]
SELECT * 
  FROM Person p 
 WHERE (p.idNumber = #{term} 
          OR LOWER(p.firstName) LIKE LOWER(CONCAT('%', #{term}, '%'))
          OR LOWER(p.lastName) LIKE LOWER(CONCAT('%', #{term}, '%')) 
          OR LOWER(p.companyName) LIKE LOWER(CONCAT('%', #{term}, '%'))
          OR p.phone = #{term});

ループの最後で、Java=を使用して、一致した行を交差させ、すべての一致が一意になるようにします。

persons = (List<Person>)CollectionUtils.intersection(persons, tmpPersons);

これを動的SQLステートメントに変更して、1つのSQLステートメントで提供されるすべての用語に一致させ、CollectionUtils.intersectionを削除することを計画していますが、そのプロセスを実行する前に、これを実行して検索を高速化する別の方法がありますか?

Mysql 5.5とInnoDBテーブルを使用しています。

2
kasdega

正解です。FULLTEXT検索は、MySQL 5.6までInnoDBにヒットしませんでした。これにはいくつかのオプションがあります:

  1. MySQL 5.6に更新し、FULLTEXTインデックスを使用します
  2. 関数のコントラクトを変更して、プレフィックス検索のみを許可します。つまり、「term%」です。それはあなたのDBを保存しながら多くのユースケースを満たします。
  3. MyISAMテーブルに変換するか、検索専用に結合できるスペアのMyISAMテーブルを作成します。

Javaでクエリを構築しているので、CONCAT('%'sがすでに適用されている2番目の変数を作成することを優先して、%のものを削除することもお勧めします。これにより、DBを解析する余分な作業からDBを節約し、インデックスをより効率的に利用できるようになります。インデックスと言えば、可能であれば列にまたがるインデックスがあることを確認してください。

重複の削除については、Javaでの余分な労力とデータ転送を節約するためにGROUP BY p.idNumberを実行した方がよい場合があります。

1
xathien