ホームページ 毎日のプログラミング mysqlの知識 SQLのパフォーマンスを分析する方法

SQLのパフォーマンスを分析する方法

Jun 18, 2019 pm 03:03 PM
sql パフォーマンス

SQLのパフォーマンスを分析する方法

#この記事では、Explain を使用して SQL を分析する方法を紹介します。

実際、インターネット上には Explain の使用法を詳細に紹介する記事がたくさんあります。この記事では、例と原則を組み合わせて、理解を深めていただけるように努めています。信じてください。真剣に考えてください。読んだ後に特別な利益があります。

explain は「説明する」と訳されます。これは mysql では実行プランと呼ばれます。つまり、このコマンドを使用すると、オプティマイザによる分析後に mysql が SQL の実行をどのように決定するかを確認できます。

オプティマイザーについて言えば、もう 1 つ言わせてください。MySQL には強力なオプティマイザーが組み込まれています。オプティマイザーの主なタスクは、作成した SQL を最適化し、可能な限り低コストで実行することです。たとえば、スキャンする行を減らし、並べ替えを避けるなどです。 SQL ステートメントを実行するときに何を経験しましたか?前回の記事でオプティマイザについて紹介しました。

あなたは、通常どのようなときに Explain を使用するのかと疑問に思われるかもしれませんが、ほとんどの場合、クエリ効率が比較的遅い SQL は、Explain 分析を使用するために mysql のスロー クエリ ログから抽出されます。 , インデックスを追加し、追加したインデックスがヒットするかどうかを Explain を使用して分析するなど、ビジネス開発中にニーズが満たされる場合は、Explain を使用していずれかを選択する必要がある場合があります。

では、Explain を使用するにはどうすればよいでしょうか? それは非常に簡単で、以下に示すように SQL の前に Explain を追加するだけです。

mysql> explain select * from t;
+----+-------------+-------+------+---------------+------+---------+------+--------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows   | Extra |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------+
|  1 | SIMPLE      | t     | ALL  | NULL          | NULL | NULL    | NULL | 100332 | NULL  |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------+
1 row in set (0.04 sec)
ログイン後にコピー
ご覧のとおり、explain は約 10 個のフィールドを返します。バージョンが異なると返されるフィールドは若干異なります。各フィールドは特定の意味を表します。この記事では各フィールドの詳細については説明しません。導入には多くの内容が含まれており、覚えるのは簡単ではないと思います。最初にいくつかの重要なフィールドを理解することをお勧めします。

フィールドの種類、キー、行、および追加の方が重要だと思います。これらのフィールドの意味をより深く理解できるように、具体的な例を使用します。

まず第一に、これらのフィールドの文字通りの意味を簡単に紹介する必要があります。

type は、MySQL がデータにアクセスする方法を表します。一般的なものには、フル テーブル スキャン (all)、インデックス トラバーサル (index)、間隔クエリ (範囲)、定数または同等のクエリ (ref、eq_ref)、主キーなどが含まれます。テーブル (システム) にレコードが 1 つだけある場合のクエリ (const)。以下は、最高から最低までの効率のランキングです。

system > const > eq_ref > ref > range > index > all
ログイン後にコピー
key は、クエリ プロセスで実際に使用されるインデックス名を表します。

rows は、クエリ プロセス中にスキャンする必要がある行数を表します。このデータは必ずしも正確ではなく、MySQL のサンプリング統計のデータです。

Extra は追加情報を表し、通常、インデックスが使用されているかどうか、並べ替えが必要かどうか、一時テーブルが使用されるかどうかなどを示します。

さて、サンプル分析を正式に始めましょう。

前回の記事で作成したストレージ エンジンを引き続き使用して、テスト テーブルを作成します。ここに 10 w 個のテスト データを挿入します。テーブルの構造は次のとおりです:

CREATE TABLE `t` (
  `id` int(11) NOT NULL,
  `a` int(11) DEFAULT NULL,
  `b` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;
ログイン後にコピー
次に、次のクエリ ステートメントでは、これに注意してください。テーブルには現在主キー インデックスが 1 つだけあり、通常のインデックスはまだ作成されていません。

mysql> alter table t add index a_index(a);
Query OK, 0 rows affected (0.19 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> alter table t add index b_index(b);
Query OK, 0 rows affected (0.20 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show index from t;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| t     |          0 | PRIMARY  |            1 | id          | A         |      100332 |     NULL | NULL   |      | BTREE      |         |               |
| t     |          1 | a_index  |            1 | a           | A         |      100332 |     NULL | NULL   | YES  | BTREE      |         |               |
| t     |          1 | b_index  |            1 | b           | A         |      100332 |     NULL | NULL   | YES  | BTREE      |         |               |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)
ログイン後にコピー
ログイン後にコピー
タイプの値は ALL で、テーブル全体がスキャンされたことを示します。行フィールドには 100,332 のエントリが表示されることに注意してください。実際、データは合計 100,000 個しかないため、このフィールドはmysql の単なる推定値であり、必ずしも正確であるとは限りません。このフルテーブルスキャンの効率は非常に低いため、最適化する必要があります。

次に、フィールド a とフィールド b にそれぞれ通常のインデックスを追加し、インデックスを追加した後のいくつかの SQL ステートメントを確認します。

mysql> alter table t add index a_index(a);
Query OK, 0 rows affected (0.19 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> alter table t add index b_index(b);
Query OK, 0 rows affected (0.20 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show index from t;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| t     |          0 | PRIMARY  |            1 | id          | A         |      100332 |     NULL | NULL   |      | BTREE      |         |               |
| t     |          1 | a_index  |            1 | a           | A         |      100332 |     NULL | NULL   | YES  | BTREE      |         |               |
| t     |          1 | b_index  |            1 | b           | A         |      100332 |     NULL | NULL   | YES  | BTREE      |         |               |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)
ログイン後にコピー
ログイン後にコピー
mysql> explain select * from t where a > 1000;
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | t     | ALL  | a_index       | NULL | NULL    | NULL | 100332 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
1 row in set (0.00 sec)
ログイン後にコピー
上記の SQL は少しわかりにくいと思いますか? type は実際にフィールド a にインデックスが追加されたことを示しており、 possible_keys も a_index が利用可能であることを示していますが、キーは null を示しており、mysql が実際にインデックスを使用していないのですが、なぜですか?

これは、* を選択した場合、b フィールドを見つけるために主キー インデックスに戻る必要があるためです。このプロセスはテーブル リターンと呼ばれます。このステートメントは、条件を満たす 90,000 個のデータをフィルターで除外します。つまり、これらの 9,000 個のデータはすべてテーブルを返す操作が必要であり、フル テーブル スキャンには 100,000 個のデータしか含まれていないため、MySQL オプティマイザの観点からは、直接のフル テーブルほど優れたものではありません。スキャンを実行すると、少なくともテーブルを返すプロセスが不要になります。

もちろん、これは、テーブルを返す操作がある限りインデックスにヒットしないという意味ではありません。インデックスを使用するかどうかの鍵は、mysql がどのクエリの方がコストが低いと考えるかによって決まります。上記の SQL の where 条件を少し変更してみましょう。

mysql> explain select * from t where a > 99000;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-----------------------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra                 |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-----------------------+
|  1 | SIMPLE      | t     | range | a_index       | a_index | 5       | NULL |  999 | Using index condition |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-----------------------+
1 row in set (0.00 sec)
ログイン後にコピー
今回のタイプ値は range で、キーは a_index です。これは、インデックスがヒットすることを意味します。この SQL 条件を満たすデータは 1000 個しかないため、これは適切な選択です。MySQLテーブルリターンはテーブル全体のスキャンよりもコストが低いので、mysql は実際には非常に賢い人です。

また、[Extra] フィールドの値が [インデックス条件を使用] であることもわかります。これは、インデックスは使用されていますが、テーブルを返す必要があることを意味します。次のステートメントを見てください。

mysql> explain select a from t where a > 99000;
+----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
|  1 | SIMPLE      | t     | range | a_index       | a_index | 5       | NULL |  999 | Using where; Using index |
+----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
1 row in set (0.00 sec)
ログイン後にコピー

这个 Extra 中的值为 Using where; Using index ,表示查询用到了索引,且要查询的字段在索引中就能拿到,不需要回表,显然这种效率比上面的要高,所以不要轻易写 select * ,只查询业务需要的字段即可,这样可以尽可能避免回表。

再来看一个需要排序的。

mysql> explain select a from t where a > 99000 order by b;
+----+-------------+-------+-------+---------------+---------+---------+------+------+---------------------------------------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra                                 |
+----+-------------+-------+-------+---------------+---------+---------+------+------+---------------------------------------+
|  1 | SIMPLE      | t     | range | a_index       | a_index | 5       | NULL |  999 | Using index condition; Using filesort |
+----+-------------+-------+-------+---------------+---------+---------+------+------+---------------------------------------+
1 row in set (0.00 sec)
ログイン後にコピー

这个 Extra 中返回了一个 Using filesort,意味着需要排序,这种是需要重点优化的的,也就是说查到数据后,还需要 mysql 在内存中对其进行排序,你要知道索引本身就是有序的,所以一般来讲要尽量利用索引的有序性,比如像下面这样写。

mysql> explain select a from t where a > 99990 order by a;
+----+-------------+-------+-------+------------------+---------+---------+------+------+--------------------------+
| id | select_type | table | type  | possible_keys    | key     | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+------------------+---------+---------+------+------+--------------------------+
|  1 | SIMPLE      | t     | range | a_index,ab_index | a_index | 5       | NULL |   10 | Using where; Using index |
+----+-------------+-------+-------+------------------+---------+---------+------+------+--------------------------+
1 row in set (0.00 sec)
ログイン後にコピー

我们再创建一个复合索引看看。

mysql> alter table t add index ab_index(a,b);
Query OK, 0 rows affected (0.19 sec)
Records: 0  Duplicates: 0  Warnings: 0
ログイン後にコピー
mysql> explain select * from t where a > 1000;
+----+-------------+-------+-------+------------------+----------+---------+------+-------+--------------------------+
| id | select_type | table | type  | possible_keys    | key      | key_len | ref  | rows  | Extra                    |
+----+-------------+-------+-------+------------------+----------+---------+------+-------+--------------------------+
|  1 | SIMPLE      | t     | range | a_index,ab_index | ab_index | 5       | NULL | 50166 | Using where; Using index |
+----+-------------+-------+-------+------------------+----------+---------+------+-------+--------------------------+
1 row in set (0.00 sec)
ログイン後にコピー

这条 sql 刚刚在上面也有讲到过,在没有创建复合索引的时候,是走的全表扫描,现在其实是利用了覆盖索引,同样是免去了回表过程,即在 (ab_index) 索引上就能找出要查询的字段。

这篇文章通过几个实例介绍了如何使用 explain 分析一条 sql 的执行计划,也提到了一些常见的索引优化,事实上还有更多的可能性,你也可以自己去写一个 sql ,然后使用 explain 分析,看看有哪些是可以被优化的。

这篇文章我断断续续写了有三四天了,本来准备了更多的例子,但每次都是写了一部分,思路也打乱了,好了,有问题欢迎在下面留言交流,文章对你有帮助,点个赞表示鼓励支持。

更多MySQL相关技术文章,请访问MySQL教程栏目进行学习!

以上がSQLのパフォーマンスを分析する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Hibernate フレームワークにおける HQL と SQL の違いは何ですか? Hibernate フレームワークにおける HQL と SQL の違いは何ですか? Apr 17, 2024 pm 02:57 PM

HQL と SQL は Hibernate フレームワークで比較されます。HQL (1. オブジェクト指向構文、2. データベースに依存しないクエリ、3. タイプ セーフティ)、SQL はデータベースを直接操作します (1. データベースに依存しない標準、2. 複雑な実行可能ファイル)。クエリとデータ操作)。

Embedding サービスのローカル実行パフォーマンスは OpenAI Text-Embedding-Ada-002 を上回っており、とても便利です。 Embedding サービスのローカル実行パフォーマンスは OpenAI Text-Embedding-Ada-002 を上回っており、とても便利です。 Apr 15, 2024 am 09:01 AM

Ollama は、Llama2、Mistral、Gemma などのオープンソース モデルをローカルで簡単に実行できるようにする非常に実用的なツールです。この記事では、Ollamaを使ってテキストをベクトル化する方法を紹介します。 Ollama をローカルにインストールしていない場合は、この記事を読んでください。この記事では、nomic-embed-text[2] モデルを使用します。これは、短いコンテキストおよび長いコンテキストのタスクにおいて OpenAI text-embedding-ada-002 および text-embedding-3-small よりも優れたパフォーマンスを発揮するテキスト エンコーダーです。 o が正常にインストールされたら、nomic-embed-text サービスを開始します。

さまざまな Java フレームワークのパフォーマンスの比較 さまざまな Java フレームワークのパフォーマンスの比較 Jun 05, 2024 pm 07:14 PM

さまざまな Java フレームワークのパフォーマンス比較: REST API リクエスト処理: Vert.x が最高で、リクエスト レートは SpringBoot の 2 倍、Dropwizard の 3 倍です。データベース クエリ: SpringBoot の HibernateORM は Vert.x や Dropwizard の ORM よりも優れています。キャッシュ操作: Vert.x の Hazelcast クライアントは、SpringBoot や Dropwizard のキャッシュ メカニズムよりも優れています。適切なフレームワーク: アプリケーションの要件に応じて選択します。Vert.x は高パフォーマンスの Web サービスに適しており、SpringBoot はデータ集約型のアプリケーションに適しており、Dropwizard はマイクロサービス アーキテクチャに適しています。

PHP 配列キー値の反転: さまざまな方法のパフォーマンス比較分析 PHP 配列キー値の反転: さまざまな方法のパフォーマンス比較分析 May 03, 2024 pm 09:03 PM

PHP の配列キー値の反転メソッドのパフォーマンスを比較すると、array_flip() 関数は、大規模な配列 (100 万要素以上) では for ループよりもパフォーマンスが良く、所要時間が短いことがわかります。キー値を手動で反転する for ループ方式は、比較的長い時間がかかります。

C++ でマルチスレッド プログラムのパフォーマンスを最適化するにはどうすればよいですか? C++ でマルチスレッド プログラムのパフォーマンスを最適化するにはどうすればよいですか? Jun 05, 2024 pm 02:04 PM

C++ マルチスレッドのパフォーマンスを最適化するための効果的な手法には、リソースの競合を避けるためにスレッドの数を制限することが含まれます。競合を軽減するには、軽量のミューテックス ロックを使用します。ロックの範囲を最適化し、待ち時間を最小限に抑えます。ロックフリーのデータ構造を使用して同時実行性を向上させます。ビジー待機を回避し、イベントを通じてリソースの可用性をスレッドに通知します。

PHP 関数のパフォーマンスはどの程度ですか? PHP 関数のパフォーマンスはどの程度ですか? Apr 18, 2024 pm 06:45 PM

さまざまな PHP 関数のパフォーマンスは、アプリケーションの効率にとって非常に重要です。パフォーマンスの良い関数には echo や print などがありますが、str_replace、array_merge、file_get_contents などの関数のパフォーマンスは低くなります。たとえば、str_replace 関数は文字列の置換に使用され、中程度のパフォーマンスを発揮しますが、sprintf 関数は文字列の書式設定に使用されます。パフォーマンス分析によると、1 つの例の実行にかかる時間はわずか 0.05 ミリ秒であり、関数が適切に実行されることが証明されています。したがって、関数を賢く使用すると、アプリケーションをより高速かつ効率的に実行できます。

C++ 静的関数のパフォーマンスに関する考慮事項は何ですか? C++ 静的関数のパフォーマンスに関する考慮事項は何ですか? Apr 16, 2024 am 10:51 AM

静的関数のパフォーマンスに関する考慮事項は次のとおりです。 コード サイズ: 静的関数にはメンバー変数が含まれないため、通常は小さくなります。メモリ占有: 特定のオブジェクトに属さず、オブジェクト メモリを占有しません。呼び出しオーバーヘッド: 低くなり、オブジェクト ポインターまたは参照を介して呼び出す必要がありません。マルチスレッド セーフ: クラス インスタンスに依存しないため、通常はスレッド セーフです。

ベンチマークを使用して Java 関数のパフォーマンスを評価するにはどうすればよいですか? ベンチマークを使用して Java 関数のパフォーマンスを評価するにはどうすればよいですか? Apr 19, 2024 pm 10:18 PM

Java 関数のパフォーマンスをベンチマークする方法は、Java Microbenchmark Suite (JMH) を使用することです。具体的な手順は次のとおりです。 JMH 依存関係をプロジェクトに追加します。新しい Java クラスを作成し、ベンチマーク メソッドを表す @State アノテーションを付けます。クラス内にベンチマーク メソッドを記述し、 @Benchmark アノテーションを付けます。 JMH コマンド ライン ツールを使用してベンチマークを実行します。

See all articles