23

フィールドにプレーンな INDEX がある場合、実際の経験のある人なら誰でも、速度と効率の観点から、数百万行のテーブルで MySQL で LIKE クエリを実行するにはどうすればよいでしょうか?

数百万行のテーブルでデータベース フィールド検索を実行するためのより良い代替手段 (FULLTEXT 50% ルールのように結果を除外しない) はありますか?

例:

Schema (comments table)

id (PRIMARY) title(INDEX) content time stamp

Query

SELECT * FROM 'comments' WHERE 'title' LIKE '%query%'
4

5 に答える 5

17

%パターンの先頭にがある場合、LIKE は完全なテーブル スキャンを実行します。

FULLTEXT をブール (自然言語ではなく) モードで使用して、50% ルールを回避できます。

ブール全文検索には、次の特徴があります。

50% のしきい値は使用しません。

http://dev.mysql.com/doc/refman/5.0/en/fulltext-boolean.html

于 2012-07-10T17:52:02.007 に答える
14

実際の経験を持つ人なら誰でも、フィールドにプレーンなINDEXがある場合、速度と効率の観点から、LIKEクエリはMySQLで数百万行のテーブルに対してどのように実行されますか?

あまりよくありません(私は900kの範囲でいくつかの検索を行ったと思いますが、数百万行のLIKEの経験があるとは言えません)。

通常、検索はできる限り制限する必要がありますが、これはテーブルの構造とアプリケーションのユースケースによって異なります。

また、一部のWebユースケースでは、個別のキーワードにインデックスを付け、キーワードテーブルとrows_contains_keyword(id_keyword、id_row)テーブルを作成するなど、いくつかのトリックを使用してパフォーマンスとユーザーエクスペリエンスを実際に向上させることができます。キーワードテーブルはAJAXで使用され、検索語(単純な単語)を提案し、それらを整数(id_keywords)にコンパイルします。その時点で、それらのキーワードを含む行を見つけるのは非常に速くなります。一度に1行ずつテーブルを更新することも、非常にパフォーマンスが高くなります。もちろん、バッチ更新は明確な「禁止」になります。

これは、+演算子のみを使用する場合、フルテキストMATCH..INBOOLEANMODEですでに実行されていることとそれほど変わりません。

SELECT * FROM arts WHERE MATCH (title) AGAINST ('+MySQL +RDBMS' IN BOOLEAN MODE);

おそらく、InnoDBテーブルでそれを実行する必要があります。

ブール全文検索には、次の特徴があります。

  • 関連性の高い順に行を自動的に並べ替えることはありません。..。
  • InnoDBテーブルでは、ブールクエリを実行するためにMATCH()式のすべての列にFULLTEXTインデックスが必要です。MyISAM検索インデックスに対するブールクエリは、FULLTEXTインデックスがなくても機能しますが、この方法で実行される検索は非常に遅くなります。..。
  • MyISAM検索インデックスに適用される50%のしきい値は使用しません。

特定のケースについて詳しく教えてください。

更新:AJAXの方法

セットアップ:すべてtitleのsを単語に分割します。title_wordsこれはすぐにあなたにテーブル( id integer not null autoincrement, word varchar(50) )と大きなテーブルを与えるでしょうtitle_contains_word ( word_id integer, title_id integer )

1000万のタイトルがあり、平均4語(本の場合は妥当ですが、論文の場合はそれほどではありません)の場合、5000行title_wordsのテーブルと2つのINTEGER列を含む4000万のテーブルが期待できます。これは約400MBの追加データです。

検索の場合、ユーザーは単語の入力を開始します。これは、タイトル単語からオートコンプリートできます。これが行われると、クエリは単語IDのリストになります。もちろん、タイトルに含まれていない単語も入力できないため、否定的な結果がすぐに無料で表示されます。

実際の検索はいくつかの方法で実行できるようになりましたが、私が気に入っている検索はSELECT COUNT(*) FROM title_contains_word WHERE word_id={id}、各ユーザーが選択した後、実際の検索が開始される前に実行されます。

これにより、最もまれな単語から開始して、複合クエリまたは共通テーブル式を作成できます。実際、単語の数が20未満の場合、(平均して)8つのTCW行をすべて選択し、関連するすべての単語のIDを取得してから、(MySQLの外部で)そのようなタイトルIDがあることを確認するだけです。クエリのすべてのwordIDにペア(titleID、wordID)が存在すること。

可能な限りラフな形に頼らなければならない場合でも、

SELECT a.title_id 
FROM title_contains_word AS tcw1
JOIN title_contains_word AS tcw2 USING (title_id)
JOIN title_contains_word AS tcw3 USING (title_id)
JOIN title_contains_word AS tcw4 USING (title_id)
...
WHERE (tcw1.word_id = {id1})
  AND (tcw2.word_id = {id2})
  ...

JOINは、スキャンにほとんど時間がかからない非常に小さな仮想バッファテーブルから作成されます。

関連するすべてのタイトルIDを取得したら、主キーtitle_idを使用して、数百万行の大規模DBからストレートSELECTを実行できます。この最後の検索も非常に高速であるはずです。

于 2012-07-10T17:56:42.710 に答える
8

LIKE '%something'完全なテーブル スキャンが保証されるため、他の句 (日付範囲など) によってもクエリを制限することをお勧めします。

于 2012-07-10T17:47:34.560 に答える
0

Workbench では、SELECT の前に EXPLAIN を使用して、検索語のさまざまな部分でワイルドカードを使用して、INDEX の有無にかかわらず、さまざまな条件の LIKE の使用をテストします。各ケースは特定のケースであるため、テストに基づいて独自の結論を得ることができます。

于 2019-12-05T10:56:19.710 に答える
0

最新のレジスタだけを取得するためにサブセレクトを実行できます。

select s.* from (select * from my_table order by "create" desc  limit 10) as s
where   s.event like '%status%'   
于 2021-05-31T16:24:15.970 に答える