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


9

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

ここに画像の説明を入力してください

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

ここに画像の説明を入力してください

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

SELECT `indexVal` FROM `key_word` WHERE `hashed_word`='001'

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

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

ここに画像の説明を入力してください

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

SET profiling=1;
SELECT `indexVal` FROM `key_word` WHERE `hashed_word` = '001';
SHOW profile;

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

ここに画像の説明を入力してください

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

ここに画像の説明を入力してください

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


「ユニークなものがないため、このテーブルには主キーがありません。」ええ、そうです...デザインを再検討する時が来ました。すべてのテーブルには主(または一意の)キーが必要です。
ypercubeᵀᴹ

回答:


10

なぜこれに時間がかかりすぎるのですか?」また残念ながら、データを取得して表示するのに5秒以上かかりました」とも言っています。また、クエリのプロファイリング出力を報告しました。

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

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

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

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

したがって、上記のすべての後、元の質問を次のように再定式化できます。

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

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

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

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

繰り返しますが、非常に簡単です。単一のデータセット全体で336.052レコードのすべてが必要であることを本当に確信していますか?

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

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


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


オペレーションからの返信を期待しています。
Jnanaranjan

5
  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はインデックスのみからのクエリ要求を満たすことができるため、これははるかに効率的です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.