MySQLクエリが遅い理由

MySQLクエリが遅い理由

MySQL のパフォーマンス最適化に関しては、クエリ最適化が最適化の源であり、システムが高速であるかどうかを示す最良の指標でもあります。この章と次の章では、クエリ パフォーマンスの最適化に焦点を当てます。MySQL が実際にクエリを実行する方法、クエリが遅い場所、クエリを高速化する方法、高効率と低効率の理由について理解を深めるために、いくつかのクエリ最適化手法を紹介します。これにより、クエリ SQL ステートメントをより適切に最適化できるようになります。

この章は「なぜクエリの速度が遅いのか」というところから始まり、クエリが遅くなる可能性がある場所を明確に把握できるようにします。これにより、クエリをより適切に最適化し、他の人よりも一歩先を行くことができます。

1. 遅いところはどこですか?

**クエリ速度の真の尺度は応答時間です。 **クエリをタスクとして考えると、一連のサブタスクで構成され、各サブタスクには一定の時間がかかります。クエリを最適化する場合、実際にはサブタスクの一部を削除するか、サブタスクの実行回数を減らすか、サブタスクの実行速度を上げるかのいずれかの方法で、サブタスクを最適化する必要があります。

MySQL がクエリを実行するとき、サブタスクとは何ですか? また、どのサブタスクに最も時間がかかりますか?これには、クエリを分析して速度が遅い箇所を特定するためのツールや方法 (実行プランなど) を使用する必要があります。

一般的に、クエリのライフ サイクルは、大まかに次の順序で考えることができます。**クライアントからサーバーへ、サーバー上で解析され、実行プランが生成され、実行され、結果がクライアントに返されます。 **その中でも、「実行」はライフサイクル全体の中で最も重要な段階であると考えられます。これには、データを取得するためのストレージ エンジンへの多数の呼び出しと、呼び出し後の並べ替え、グループ化などのデータ処理が含まれます。

これらのタスクを完了する際、クエリは、ネットワーク、CPU 計算、統計と実行プランの生成、ロック待機、その他の操作、特に基盤となるストレージ エンジンからデータを取得するための呼び出し操作など、さまざまな段階のさまざまな場所で時間を費やす必要があります。これらの呼び出しには、メモリ操作、CPU 操作が必要であり、大量のコンテキスト スイッチとシステム コールも生成される可能性があります。

上記のすべての操作では、多くの時間が消費され、不要な追加操作が発生することがあります。一部の操作は何度も繰り返され、一部の操作は非常に遅く実行される可能性があります。これはクエリが実際に遅くなる可能性がある場所であり、クエリ最適化の目的はこれらの操作に費やされる時間を削減または排除することです。

上記の分析を通じて、クエリ プロセスを包括的に理解し、クエリのどこに問題があるかを明確に把握して、最終的にクエリ全体の速度低下につながるかどうかを把握し、実際のクエリ最適化の方向性を示すことができます。

つまり、クエリの最適化は次の 2 つの観点から実行できます。

  • サブクエリの数を減らす
  • 余分な繰り返し操作を削減

クエリのパフォーマンスが低下する一般的な原因は、アクセスするデータが多すぎることです。データ量が少ない場合、クエリ速度は良好です。データ量が増えると、クエリ速度が劇的に変化し、人々を困惑させ、非常に悪い体験をもたらします。クエリの最適化については、次の側面から確認できます。

  • 不要なデータが照会されていますか?
  • 追加のレコードがスキャンされたかどうか

2. 不要なデータをクエリしましたか?

実際のクエリでは、実際に必要なデータがクエリされ、その後冗長なデータはアプリケーションによって破棄されることが多いです。これは MySQL の追加オーバーヘッドであり、アプリケーション サーバーの CPU およびメモリ リソースも消費します。

典型的なケースとしては、次のようなものがあります。

1. 不要なレコードをクエリする

これはよくある間違いです。MySQL は必要なデータのみを返すと誤解している人が多いのですが、実際には MySQL は計算を実行する前に結果セット全体を返します。

開発者は通常、SELECT ステートメントを使用して大量の結果をクエリし、アプリケーション クエリまたはフロントエンド表示レイヤーを使用して最初の N 行のデータを取得します。たとえば、ニュース Web サイトで 100 件のレコードがクエリされますが、ページに表示されるのは最初の 10 件だけです。

最も効果的な解決策は、必要な数のレコードをクエリすることです。通常は、クエリの後に LIMIT を追加します (つまり、ページ分割されたクエリ)。

2. 複数のテーブルが関連付けられている場合はすべての列を返す

映画「アカデミー・ダイナソー」に出演した俳優全員を検索する場合は、次の操作は行わないでください。

俳優aから*を選択
内部結合 film_actor fa.actorId = a.actorId
内部結合フィルム f f.filmId = fa.filmId
fa.title = 'アカデミー恐竜';

これにより、3 つのテーブルのすべてのデータ列が返されますが、実際の要件は俳優情報を照会することです。正しい書き方は次のとおりです。

俳優aからa.*を選択します
内部結合 film_actor fa.actorId = a.actorId
内部結合フィルム f f.filmId = fa.filmId
fa.title = 'アカデミー恐竜';

3. 常にすべての列をクエリする

select * を見るたびに、奇妙な表情で見てしまうはずです。本当にすべてのデータ列を返す必要があるのでしょうか?

ほとんどの場合、必要ありません。 Select * を実行するとテーブル全体がスキャンされ、オプティマイザがインデックス スキャンなどの最適化を完了できなくなります。列が多すぎると、サーバーの I/O、メモリ、CPU 消費量も増加します。実際にすべての列をクエリする必要がある場合でも、* ではなくすべての列を 1 つずつリストする必要があります。

4. 同じデータを繰り返しクエリする

注意しないと、同じクエリを何度も実行し、毎回まったく同じデータを返すという間違いを犯しやすくなります。

たとえば、ユーザーのコメント領域にあるユーザーのアバターの URL を照会する必要がある場合、ユーザーが複数回コメントすると、このデータを繰り返し照会する可能性があります。これを処理するより良い方法は、データが最初にクエリされたときにデータをキャッシュし、その後使用されるときにキャッシュから直接取得することです。

3. 追加のレコードはスキャンされますか?

クエリが必要なデータのみを検索していることを確認したら、次にクエリがスキャンするデータが多すぎないかどうかを確認する必要があります。 MySQL の場合、クエリのオーバーヘッドを測定するための最も単純な 3 つのメトリックは次のとおりです。

  • 応答時間
  • スキャンされた行数
  • 返される行数

単一のメトリックでクエリのコストを完全に測定することはできませんが、クエリを実行するときに MySQL がアクセスする必要があるデータの量を大まかに反映し、クエリの実行にかかる実際の時間を大まかに見積もることができます。これら 3 つのインジケーターは MySQL スロー ログに記録されるため、スロー ログ レコードを確認すると、スキャンする行数が多すぎるクエリを見つけることができます。

スロー クエリ: 応答時間がしきい値 (long_query_time、デフォルトでは 10 秒) を超える MySQL のステートメントを記録し、スロー ログにスロー クエリを記録するために使用されます。変数 slow_query_long を通じてスロー クエリを有効にすることができます。デフォルトでは閉じられています。スロー ログは、検査および分析のために slow_log テーブルまたはファイルに記録できます。

1. 応答時間

応答時間は、サービス時間とキュー時間という 2 つの部分の合計です。サービス時間とは、データベースがクエリを処理するのに実際にかかった時間を指します。キュー時間とは、サーバーが何らかのリソース(I/O 操作の待機、行ロックの待機など)を待機しているために、クエリを実際に実行しない時間を指します。

さまざまな種類のアプリケーション ストレス下での応答時間には、一貫したパターンや式はありません。ストレージ エンジン ロック (テーブル ロック、行ロック)、高同時実行リソースの競合、ハードウェア応答など、多くの要因が応答時間に影響する可能性があります。したがって、応答時間は、状況に応じて、問題の結果にも原因にもなり得ます。

クエリの応答時間を確認するときに最初に自問する必要があるのは、この応答時間が妥当な値であるかどうかです。

2. スキャンされた行数と返された行数

クエリを分析する場合、クエリによってスキャンされた行数を確認したり、追加のレコードがスキャンされたかどうかを分析したりすることが役立ちます。

すべての行のアクセスコストが同じではないため、このメトリックは不正なクエリを識別するのに最適ではない可能性があります。短い行は非常に速くアクセスされ、メモリ内の行はディスク上の行よりもはるかに速くアクセスできます。

**理想的には、スキャンされる行数と返される行数は同じである必要があります。 **しかし、現実には、このような美しさは一般的ではありません。たとえば、結合クエリを実行する場合、スキャンされた行数と返される行数の比率は通常非常に小さく、通常は 1:1 から 10:1 の間ですが、この値が非常に大きくなることもあります。

3. スキャンされた行数とアクセスタイプ

クエリのオーバーヘッドを評価するときは、テーブル内のデータ行を見つけるコストを考慮する必要があります。 MySQL には、結果の行を検索して返すことができるアクセス メソッドがいくつかあります。これらのアクセス メソッドでは、結果を返すために多くの行にアクセスする必要があり、一部のアクセス メソッドではスキャンせずに結果を返す場合があります。

実行プランの EXPLAIN ステートメントの type 列は、アクセス タイプを反映します。アクセスには、フルテーブルスキャンからインデックススキャン、範囲スキャン、ユニークインデックス、定数インデックスなど、さまざまな種類があります。ここでリストされている速度は遅いものから速いものまで、またスキャンされる行数は多いものから少ないものの順になっています。

クエリが適切なアクセス タイプを見つけられない場合、最善の解決策は通常、適切なインデックスを追加することです。これは、前に説明したインデックスの問題です。これで、クエリの最適化にとってインデックスがなぜそれほど重要なのかが明らかになったはずです。インデックスを使用すると、MySQL は最小限の行数をスキャンして、必要なレコードを最も効率的に見つけることができます。

クエリが大量のデータをスキャンしても、数行しか返さない場合は、通常、次の手法を試して最適化することができます。

  • インデックス カバーリング スキャンを使用して、必要なすべての列をインデックスに格納します。これにより、ストレージ エンジンは、テーブルに戻って対応する行を取得することなく結果を返すことができます。
  • テーブル構造を最適化します。たとえば、別のサマリー テーブルを使用してクエリを完了します。
  • MySQL オプティマイザーがより最適な方法でクエリを実行できるように、複雑なクエリを書き直します。

上記は、MySQL クエリ速度が遅い理由の詳細です。MySQL クエリ速度の詳細については、123WORDPRESS.COM の他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • Docker MySQL コンテナでスロークエリログを有効にする方法
  • MySQL の遅いクエリの最適化ソリューション
  • MySQL で遅いクエリ SQL を見つけて最適化する詳細な例
  • MySQL最適化ソリューション: スロークエリログを有効にする
  • MySQLスローログに関する知識のまとめ
  • MySQL の遅いクエリの落とし穴
  • MySQL スロークエリログの詳細な理解
  • MySQL で遅い SQL を素早く見つける方法

<<:  Vue 基本チュートリアル: 条件付きレンダリングとリストレンダリング

>>:  Better-scrollはメニューとコンテンツをリンクする効果を実現します

推薦する

HTMLで細い線のテーブルを作成する簡単な例

この細線の表を作成する方法については、Baidu で検索すると、表に対して border="...

MySQL ステートメントコメントの紹介

MySQL は次の 3 種類のコメントをサポートしています。 1. 行末の「#」文字から。 2. 「...

JavaScriptプロトタイプチェーンの詳細な説明

目次1. コンストラクタとインスタンス2. プロパティプロトタイプ3. プロパティ __proto_...

React のグローバル状態管理の 3 つの基本メカニズムの調査

目次序文小道具コンテクスト州要約する序文最新のフロントエンド フレームワークはすべて、コンポーネント...

Docker で Redis センチネル モードを構成する方法 (複数のサーバー上)

目次序文状態DockerをインストールするRedisのマスターノードとスレーブノードを構成する序文以...

MySQLファイルストレージの詳細な説明

ファイルシステムとは何かInnoDB や MyIASM などのストレージ エンジンはテーブルをディス...

Reactマウスの複数選択機能の設定方法

一般的に、リストには選択機能があり、単一選択、二重選択、複数選択が非常に一般的です。カスタム ループ...

一般的なSQL削除ステートメントの原則の違いを理解するだけです

この記事では主に、SQL 削除ステートメント DROP、TRUNCATE、および DELETE の違...

MySQL データベースでよく使用される SQL ステートメントの詳細と概要

この記事では、MySQL データベースでよく使用される SQL ステートメントを例を使用して説明しま...

webpackでHMRを手動で実装するいくつかの方法

目次1. はじめに2. GitHub 3. 基本構成プロジェクトディレクトリパッケージ.json c...

MySQLがトランザクション分離を実装する方法の簡単な分析

目次1. はじめに2. RC および RR 分離レベル2.1. RRトランザクション分離レベルでのク...

Mysql マスタースレーブ同期 Last_IO_Errno:1236 エラー解決

Mysql マスタースレーブ同期の Last_IO_Errno:1236 エラーの原因は何ですか? ...

SQL 実装 LeetCode (185. 部門内で最も給与の高い上位 3 名)

[LeetCode] 185. 部門別給与上位3位従業員テーブルにはすべての従業員が保持されます。...

CSS スティッキーフッタークラシックレイアウトの実装

スティッキーフッターレイアウトとは何ですか?一般的な Web ページのレイアウトは、通常、ヘッダー部...

MySQLデスクトップツールSQLyogのリソースとアクティベーション方法は、白黒のコマンドラインに別れを告げます

では、早速リソースについて見ていきましょう。 123WORDPRESS.COM ダウンロードSQLy...