記事ディレクトリ
1. 事業背景
一般に、プロジェクト開発では、報告および分析する必要がある統計データが多数あります。一般に、分析後、ページで表示する操作や製品のバックグラウンドに表示されます。最も一般的なのは、日付でフィルターします。この種の統計データのサイズは時間の経過とともに徐々に増加し、数百万、数千万のデータに達するのは時間の問題です。
2. ボトルネックの再現
ユーザーテーブルを作成し、create_time フィールドにインデックスを追加しました。そしてテーブルに100wのデータを追加しました。
ここでは、制限ページング方式を使用して、最初の 5 個のデータと最後の 5 個のデータの間のクエリ時間の差をクエリします。
最初の 10 項目のクエリには基本的に時間はかかりません
50w+ からデータをフェッチすると、クエリに 1 秒かかります。
キーワード SQL_NO_CACHE は、SQL クエリがキャッシュされないようにします。
同じ SQL ステートメント、異なるページング条件、および 2 つのパフォーマンスの差が非常に大きいため、データ量が増加するにつれて、後続のページのクエリに費やされる時間も論理的に増加します。
3. 問題分析
返品フォーム
通常、クエリ頻度が高いフィールドに対してインデックスを作成します。インデックスによりクエリの効率が向上します。上記のステートメントでは SELECT * FROM user を使用していますが、すべてのフィールドにインデックスが付けられているわけではありません。修飾されたデータをインデックス ファイルからクエリした後、インデックスが作成されていないフィールドをデータ ファイルからクエリすることも必要です。次に、このプロセスがテーブルにコールバックされます。
カバーインデックス
SELECT create_time FROM user など、クエリされたフィールドにインデックスが作成されている場合、クエリしたフィールドは作成したインデックスであるため、この時点でデータ ファイル内でクエリを実行する必要はなく、返す必要もありません。テーブルへ。この場合、それをカバリングインデックスと呼びます。
IO
テーブルの戻り操作は通常、 IO 操作です。これは、インデックスに従ってデータ行を見つけてから、クラスター化インデックスに移動して、データ行の主キーまたは一意のインデックスに従って特定のデータ行を見つける必要があるためです。クラスター化インデックスは通常、ディスクに保存されるデータ ファイルであるため、テーブルを返す操作を実行するときにディスクからデータを読み取る必要があり、ディスク IO は比較的遅い操作です。
リムティ2000,10 ?
LIMIT 2000, 10 が 1 ~ 2000 行をスキャンするかどうか考えたことはありますか? 以前に私と同じように、データは 2000 行から直接フェッチされ、前のデータはまったくスキャンされないか、データに返されないと考えたことはありませんか?テーブル。実際、この書き方では、完全なプロセスはデータをクエリすることですが、インデックスをカバーできない場合は、テーブルに戻ってデータをクエリする必要があります。
これで、後ろに行くにつれてクエリが遅くなる理由がわかりました。
4. 問題の概要
これで、後続のクエリが発生すると LIMIT のパフォーマンスが低下することがわかりました。パフォーマンスが低下する理由は、テーブルに戻る必要があるためです。問題が見つかったので、あとはクエリの回数を減らすだけです。テーブルに戻ってクエリのパフォーマンスを向上させます。
5. 解決策
カバーリングインデックスを使用するとデータがテーブルに戻らなくなる可能性があるため、まず主キー ID (主キーインデックス) を見つけて、見つかったデータを一時テーブルとして使用し、元のテーブルに JOIN することができます。処理する必要があるクエリ結果は 5 つだけです。 データはテーブルに返されるため、IO 操作が大幅に削減されます。
最適化前後のパフォーマンスの比較
実行効果を見てみましょう。
最適化前:1.4秒
最適化後:0.2秒
時間のかかるクエリのパフォーマンスが大幅に改善されました。このようにして、ページングされたデータが大きい場合でも、通常の制限クエリほど遅くはなりません。