web-dev-qa-db-ja.com

選択クエリは必要以上に時間がかかります

私は、MySQLデータベーステーブルに2300万近くのレコードがあります。一意のものがないため、このテーブルには主キーがありません。 2つの列があり、両方にインデックスが付けられています。以下はその構造です。

enter image description here

以下はそのデータの一部です。

enter image description here

今、私は簡単なクエリを実行しました:

SELECT `indexVal` FROM `key_Word` WHERE `hashed_Word`='001'

残念ながら、データを取得して表示するのに5秒以上かかりました。私の将来のテーブルには1500億のレコードがあるため、今回は非常に高いです。

Explainコマンドを実行して、何が起こっているのかを確認しました。結果は以下のとおりです。

enter image description here

次に、以下のコマンドを使用してプロファイルを実行しました。

SET profiling=1;
SELECT `indexVal` FROM `key_Word` WHERE `hashed_Word` = '001';
SHOW profile;

以下はプロファイリングの結果です。

enter image description here

以下は私のテーブルに関するいくつかの詳細です:

enter image description here

では、なぜこれほど時間がかかるのでしょうか。それらもインデックス化されています!将来的には、たくさんのLIKEコマンドを実行する必要があるため、これには時間がかかりすぎます。何が悪いのでしょうか?

9
Lemon Juice

時間がかかりすぎる理由?」と尋ねました。また、「残念ながら、データを取得して表示するのに5秒以上かかりました」。また、クエリのプロファイリング出力を報告しました。

ご覧のとおり、プロファイラーによって報告された各ステップの合計時間は0.000154秒です。したがって、プロファイラーの観点からは、クエリはそのような時間(0.000154)で完了しました。

では、なぜ「... 5秒以上?」という結果が得られるのでしょうか。

あなたは、3文字のフィールドを持つ2,300万件のレコードテーブルをフィルタリングしていると言いました。残念ながら、クエリが返すレコードの数を教えてくれません...しかし、提供されたEXPLAIN SELECTのおかげで、クエリが336052レコードを返したようです。

また、すべてのアクティビティがGUI(PHPMyAdmin?)を介して実行されているようです。

以上のことから、元の質問を次のように再定式化できます。

「関連するクエリのMySQL実行時間が0.000154秒であるのに、GUI内で336.052レコードが5秒以上表示されるのはなぜですか?」

私の意見では、答えは非常に単純です。5秒は、336.052レコードがパスに沿って移動するための(実際には非常に短い)時間です。MySQLエンジン=> MySQLクライアントライブラリ=> PHP MySQLモジュール=> Apache =>ネットワーク=> PC TCP/IPスタック=>ブラウザ=> DOMパーサー/ビルダー/ etc。=>レンダリングされたHTMLページ。

私の以前の経験と同様に、結果の送信に必要な時間は、「通常」、そのようなデータを取得するために必要な時間よりもはるかに長くなります。これは、PHP-MySQLやPerl-DBD-MySQLなどのライブラリが関係している場合に特に当てはまります。レコードを取得するには、lot時間が必要ですafterMySQLはそれらすべてを適切に識別(および抽出)しました。

この問題を解決するには?

繰り返しますが、非常に簡単です。単一の336.052レコードの[〜#〜] all [〜#〜]が本当に必要かどうか、全体、データセット?

  • あなたの答えが本当に「はい!私はそれらすべてが必要です」である場合、アプリケーションが単独でPAGINATIONおよび/またはUSER-Interactionを処理し、そのようなデータのすべてを収集すると、おそらく多くの時間を費やすことになります。ユーザーとの対話なしMySQLとのさらなる対話を必要としません。このような場合、5秒(またはそれ以上)待機しても問題はありません。

  • 答えが「いいえ、より「人間的な」データセットサイズに対処したい」場合は、クエリを調整して(少なくとも)より「人間的な」データセット(数十、または最大で数百のレコード)。そのような場合、あなたはより短い時間であなたの結果を得るでしょう。


ところで:これは、ServerFaultで この他の投稿 で経験した問題とまったく同じです:132Mのレコードが.... not-mysql-strictly-related magic pathに沿って移動できるようにするための88秒

10
  1. Mysql innodb_buffer_pool_sizeを確認します。十分な大きさである必要があります-多いほど良いです。ただし、OSスワッピングを回避することはそれほど多くありません。

    show variables like 'innodb_buffer_pool_size'
    

    バッファサイズをバイト単位で表示します。

  2. クエリを複数回チェックしてください。データをディスクからメモリに読み込む必要があるため、最初の実行が長すぎる可能性があります。初めてクエリを実行しているとき、データはまだinnodbバッファーになく、ディスクから読み取る必要があります。これは、データがすでにキャッシュにある場合よりもはるかに遅くなります。したがって、クエリを数回実行して、キャッシュから提供されることを確認します。

  3. 後続の各実行はクエリキャッシュから実行され、テストの結果にバイアスがかかるため、クエリキャッシュを無効にします。 MySQLには、「クエリキャッシュ」と呼ばれるメカニズムがあり、その結果とともにクエリを格納するように設計されています。そのため、MySQLがクエリの実行を2回要求されたときに、実行をバイパスしてクエリキャッシュから結果を取得できます。

  4. 「カバリングインデックス」の使用を検討してください。

    ALTER TABLE key_Word ADD KEY IX_hashed_Word_indexVal (hashed_Word, indexVal);
    

MySQLはインデックスのみからのクエリ要求を満たすことができるため、これははるかに効率的です。

5
Boris