MySQL インデックスを 1 つの記事で読む

1 インデックス作成の概要

1.1 MySQL インデックスとは

公式定義: インデックスは、MySQL がデータを効率的に取得するのに役立つデータ構造です。

上記の定義から、インデックスは本質的にデータ構造であることがわかります。その機能は、データを効率的に取得するのに役立つことです。インデックスを正式に導入する前に、まず基本的なデータ構造を理解しましょう。

2 インデックスのデータ構造

2.1 ハッシュインデックス

ハッシュインデックスは比較的一般的なインデックスで、レコードに対応するハッシュ値を計算し、計算結果に応じて対応する場所に格納します。クエリを実行すると、ハッシュ値に基づいて場所がすぐに見つかります。彼の単一レコード クエリは非常に効率的で、時間計算量は 1 です。ただし、ハッシュ インデックスはデータベース インデックスの最も一般的に使用されるタイプではありません。特に、一般的に使用される Mysql Innodb エンジンはハッシュ インデックスをサポートしていません。

ハッシュ インデックスは同等のクエリでは高速ですが、次の 2 つの問題があります。

  • 範囲クエリはサポートされていません
  • ハッシュの競合、2 つのレコードのハッシュ値が同じ場合、ハッシュの競合が発生し、後でリンクされたリストに保存する必要があります。

画像-20220919121130111

2.2 二分木

2.2.1 古典的なバイナリ ツリー

1. ノードは 2 つの子ノードのみを持つことができます

2. 左側の子ノードの値が親ノードの値より小さく、右側の子ノードの値が親ノードの値より大きい場合は、二分探索が使用されるため、高速です。

画像-20220919121926581

古典的なバイナリ ツリーの極端な例はリンク リストであり、ノード データはますます大きくなります。この場合、二分木探索のパフォーマンスが低下します。

画像-20220919122203129

2.2.2 バランスの取れた二分木

バランスの取れたバイナリ ツリーは AVL ツリーとも呼ばれます空のツリー、または次のプロパティを持つバイナリでソートされたツリーにすることができます

  • 左のサブツリーと右のサブツリーの高さの差の絶対値 (バランス係数) が 1 を超えないこと
  • その左側のサブツリーと右側のサブツリーは両方ともバランスの取れたバイナリ ツリーです。

1 ~ 6 の数字は、次のようにバランスのとれた二分木で示されます。

画像-20220919122445172

2.3 B ツリー

B ツリーは、バランス型マルチウェイ検索ツリーとも呼ばれるマルチフォーク ツリーであり、複数のフォークを持つことができ、次の特性があります。

(1) ソート方法: すべてのノードのキーワードは昇順に配置され、左側に小さく、右側に大きいという原則に従います。

(2) 子ノード数: 空のツリーを除く、非リーフノード(根ノードおよび枝ノード)の子ノード数> 1、および子ノード数 <= M および M > = 2 : M オーダーは、ツリー ノードが最も多くの探索パスを持っていることを意味します。M=M パス、M=2 がバイナリ ツリーの場合、M=3 は 3 フォークです)。

(3) キーワードの数: ブランチ ノード内のキーワードの数は ceil(m/2)-1 以上、M-1 以下です (注: ceil() は正の方向に四捨五入される関数です)無限大 (ceil(1.1 ) の結果は 2);

(4) すべてのリーフ ノードは同じレイヤ上にあります。キーワードとキーワード レコードへのポインタに加えて、リーフ ノードは子ノードへのポインタも持ちますが、そのポインタ アドレスはすべて null で、ノードの最後のレイヤのスペースに対応します。下の図の息子。

画像-20220919130308858

MySQL の B ツリー ストレージ構造は次のとおりです。

画像-20220919131013045

2.4B+ ツリー

B+ ツリーは、B ツリーをベースにしたもう 1 つの改良であり、主に 2 つの側面が改善され、1 つはクエリの安定性、もう 1 つはデータの並べ替えがより容易になります。MySQL インデックスの基礎となるデータ構造は B+ ツリーです

(1) B+ ツリーの非葉ノードは特定のデータを保存せず、キーワードのインデックスのみを保存し、最終的にすべてのデータが葉ノードに保存されます。すべてのデータはリーフノードから取得する必要があるため、毎回のデータクエリ数は同じであるため、B+ツリーのクエリ速度は比較的安定しており、Bツリーの検索プロセスでは、異なるキーワード検索が行われます。回数は異なる可能性が高いため (一部のデータはルート ノードにあり、一部のデータは最下位のリーフ ノードにある可能性があります)、データベースのアプリケーション レベルでは、B+ ツリーの方が適しています。

(2) B+ツリーの葉ノードのキーワードを小さい順に並べ、左端のデータは右ノードの先頭のデータへのポインタを保存します。リーフ ノードが規則正しく配置されているため、B+ ツリーはデータの並べ替えをより適切にサポートします。

画像-20220919131322779

2.5B*ツリー

B ツリーは B+ ツリーの変形であり、B+ ツリーに基づいており、インデックス レイヤーをポインターで接続します (B+ ツリーはデータ レイヤーをポインターで接続するだけです)。値の検索が高速になります。

画像-20220919132355520

要約する

上記のデータ構造を分析した結果、MySQL はインデックスの保存に B+ ツリーを使用しており、総合的なレベルでこのクエリ効率が最も優れています。Oracle は B* ツリーを使用します

3 指数の分類

MySQLのインデックスには主に以下の種類があります。

  • 主キーインデックス
  • 一意のインデックス
  • 通常のインデックス
  • 複合インデックス
  • 全文インデックス

3.1 主キーインデックス

主キー インデックスは特別なインデックスであり、通常、テーブルの作成時にテーブルに主キーが設定され、MySQL はデフォルトで主キーにインデックスを追加します。主キー インデックスのリーフノードは、データ テーブルにデータ行を格納しますテーブルが主キー インデックスを作成しない場合、InnDB はクラスター化インデックスを構築するための ROWID フィールドを自動的に作成します。ルールは次のとおりです。

  1. テーブルに主キー PRIMARY KEY を定義すると、InnoDB は主キー インデックスをクラスター化インデックスとして使用します。
  2. テーブルに主キーが定義されていない場合、InnoDB は NULL ではない最初の一意のインデックス列をクラスター化インデックスとして選択します。
  3. 上記 2 つのどちらも使用できない場合、InnoDB は 6 バイト長の整数の暗黙的フィールド ROWID フィールドを使用してクラスター化インデックスを構築します。ROWID フィールドは、新しい行が挿入されると自動的に増加します。

作成方法:

CREATE TABLE `user` (
    `id` int(11) NOT NULL AUTO_INCREMENT ,
    `name` varchar(255) NOT NULL ,
    PRIMARY KEY (`id`)
);

MySQL がテーブル作成時に主キーを指定せずにデフォルトで暗黙的フィールド ROWID を使用してクラスター化インデックスを構築するのはなぜですか? これについては後で説明します

3.2 固有のインデックス

前述の通常のインデックスと同様に、インデックス列の値は一意である必要があるが、NULL 値が許可される点が異なります。複合インデックスの場合、列値の組み合わせは一意である必要があります。

作成方法

CREATE UNIQUE INDEX indexName ON user(column)
或者
ALTER TABLE table_name ADD UNIQUE indexName ON (column)

3.3 共通インデックス

MySQL の基本インデックス、制限なし

作成方法:

CREATE INDEX index_name ON user(column)
或者
ALTER TABLE user ADD INDEX index_name ON (column)

3.4 複合インデックス

複合インデックスは、名前が示すように、MySQL の複数のフィールドに同時にインデックスを追加します。使用する場合は、左端の一致原則に従う必要があります。

作成方法:

CREATE INDEX index_name ON user(column1,column2) -- 给 column1 和 column2 加上索引

3.5 全文インデックス作成

フルテキスト インデックスは主にテキスト内のキーワードを検索するために使用され、インデックス値と直接比較されるものではありません。これは、一般的な検索エンジン (elasticsearch、solr など) と機能的に似ています。MySQL のフルテキスト インデックスのパフォーマンスは平均的であるため、理解するためにのみ使用されることは一般的ではありません。

作成方法:

CREATE FULLTEXT INDEX index_column ON user(column)
或者
ALTER TABLE user ADD FULLTEXT index_column(column)

4 インデックスの設計

4.1 サムスン指数

Samsung インデックスは MySQL インデックスを設計する際の仕様であり、通常は Samsung インデックスに準拠したインデックス設計の方が優れた設計になります。

星 1 つ: インデックス内のクエリに関連するインデックス行が連続しているか、少なくとも十分に近接している

2 つ星: インデックス内のデータ列の順序は、ルックアップの並べ替え順序と同じです。

Samsung: インデックス内の列には、クエリに必要なすべての列が含まれています。インデックスにはクエリに必要なデータ列が含まれており、テーブル全体の検索やテーブルの戻り操作は実行されなくなります。

サムスン指数がどのようなものかを紹介する例をあげましょう。

次の構造のテーブルができました。

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) NOT NULL,
  `age` int(10) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

一つ星

年齢をインデックス化しました

create index idx_age on user (age);

お問い合わせ

select * from user where age in (10,20,35,43)

年齢には範囲があり、データが分散している可能性があるため、このステートメントは必ずしも 1 つの星と一致するとは限りません。

select * from user where age = 20;

このステートメントは 1 つの星と一致しています。インデックスは年齢によって小さいものから大きいものへと並べ替えられているため、年齢 = 20 のデータは一緒になる必要があります。

2 つ星

select * from user where age = 20 order by name;

データ列の順序は年齢によって並べ替えられているため、このステートメントは 1 つの星には適合しますが、2 つの星には適合しません。名前によって並べ替えられている場合、インデックスの順序は並べ替え結果による順序と異なる場合があります。結果は次のようになります。

画像-20220919144629595

画像-20220919144651218

select * from user where age = 20 order by age

このクエリ ステートメントは 1 つ星および 2 つ星に準拠しています。

サムスン

select * from user where age = 20

このステートメントは Samsung に準拠していません。インデックス列には id と age のみがあり、名前がありません。

select age from user where age = 20

このステートメントは Samsung の意見に沿っています。年齢のみがクエリされ、年齢はインデックスに存在し、テーブルを返す必要がないからです。

4.2 返品フォーム

上記のサムスン指数では返品フォームについて言及されていましたが、返品フォームとは何ですか?

簡単に言うと、クエリ ステートメントで必要な列はインデックスに含まれていないため、それらを取得するには主キー ID に従って再度クエリを実行する必要があります。テーブルに戻ることはもう 1 つのクエリに相当するため、再度クエリを実行するときにテーブルに戻ることを避けるようにする必要があります。

年齢インデックスなど、通常のインデックスには対応するカラムと主キーの値のみが含まれるため、年齢インデックスに含まれるデータには年齢と ID が含まれます。この時点で名前が必要な場合は、最初に age インデックスを通じて対応する ID を見つけてから、行内のすべてのレコードの値が含まれる主キー インデックスで名前を見つける必要があります。主キー インデックスの子ノードにはすべてのデータが含まれているため、なぜ MySQL に主キー インデックスが必要なのかという上記の質問に対する答えは次のとおりです。

画像-20220919151148480

4.3 インデックスのカバレッジ

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) NOT NULL,
  `age` int(1) DEFAULT NULL,
  `sex` varchar(2) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_name_age` (`name`,`age`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;


select name,age from user where name = "张三"
-- 这条语句就使用了索引覆盖,因为 name 和 age 再 idx_name_age 索引中都有,不需要回表查询
select name,age,sex from user where name = "张三"
-- 如果加上了 sex,那么就需要回表查询了,因为索引中不存在 sex 字段

5 インデックスの最適化

5.1 遅いクエリ

5.1.1 はじめに

スロークエリログは、スロークエリの時間しきい値をlong_query_timeに設定することで、MySQLが提供するすべてのスローSQLステートメントを記録するログレコードです。スロー クエリ ログを通じて、最適化する必要がある SQL を見つけることができます。次のステップは、SQL を最適化することです。

5.1.2 遅いクエリの設定

ステップ 1: 「slow_query_log」ステートメントのような show 変数を使用して、スロー クエリが有効かどうかを確認できます。デフォルトはオフです。

画像-20221002093201220

throw_query_log_file は、スロー クエリ ログが保存される場所です。ウィンドウの場合は、通常、インストール フォルダーの Data ディレクトリにあります。

ステップ 2: 低速クエリを開く

set global slow_query_log  = 1;

ステップ 3: 低速クエリのしきい値を設定する

どのようなクエリをスロークエリと呼びますか? 1 秒、5 秒、または 10 秒、MySQL はこれを認識しないため、構成を通じて long_query_time パラメータを設定する必要があります

画像-20221002094056353

'%long_query_time%' のようなコマンド show 変数を使用して、クエリ時間が遅いことを確認します。デフォルトは 10 秒です。

変更する必要がある場合は、コマンドでset global long_query_time = 5設定できます

画像-20221002094328461

**注意:**set global long_query_time = 5ここでスロークエリタイムを設定した後、再度確認したところスロークエリタイムは10秒のままでしたが、設定が反映されていないのでしょうか?

このコマンドを使用して変更した後、変更された構成を確認するには、再接続するか新しいセッションを開く必要があります。

画像-20221002094619080

またはshow global variables like '%long_query_time%'コマンドで確認してください

5.1.3 スロークエリログ分析

低速クエリのしきい値を 5 秒に設定したところです。次のような SQL ステートメントを実行します。

select sleep(6); 

このステートメントの実行時間は 6 秒です。スロー クエリ ログを開くと、いくつかのデータが追加されていることがわかります。

# Time: 2022-10-02T09:16:23.194396Z
# User@Host: root[root] @ localhost [::1]  Id:     6
# Query_time: 6.011569  Lock_time: 0.000000 Rows_sent: 1  Rows_examined: 0
SET timestamp=1664675770;
select sleep(6);

各行が何を表しているのかを 1 つずつ分析してみましょう。

User@Host: SQL を実行するユーザーと低速クエリの IP アドレス

Query_time: ステートメントの実行時間

Lock_time: ロックを取得する時間の長さ

Rows_sent: MySQL によってクライアントに返された行の数

Rows_examined: MySQL によってスキャンされた行の数

タイムスタンプ: 遅い SQL レコードのタイムスタンプを示します。

select sleep(6): クエリ SQL が遅いです

実際に遅いクエリ SQL、前のテストの SQL ステートメントを分析してみましょう

# Time: 2022-07-27T09:26:44.440318Z
# User@Host: root[root] @ localhost [127.0.0.1]  Id:   249
# Query_time: 68.461112  Lock_time: 0.000938 Rows_sent: 877281  Rows_examined: 877303
SET timestamp=1658914004;
SELECT  id,prd_line_id,shift_name,shift_id,app_id,weight,upload_time,operator,status,prd_line_name  FROM prd_weight 
WHERE (upload_time > '2022-07-27 00:00' AND upload_time < '2022-07-27 17:24');

Query_time: 合計クエリ時間 68.461112s

ロック時間:0.000938s

Rows_examined: スキャンされた行 877281

Rows_sent: 877303 が返されました

もちろん、これはテスト用であり、このようなとんでもない SQL ステートメントは通常、本番環境には表示されません。

5.1.4 注意事項


  1. MySQL では、テーブルの変更、テーブルの分析、テーブルのチェックなどの管理ステートメントは、デフォルトではスロー クエリ ログに記録されません。ただし、次のプロパティを使用して設定できます:
    set global log_slow_admin_statements = "ON"
  2. MySQL では、インデックスが作成されていない SQL ステートメントをスロー ログ クエリ ファイルに記録するように設定することもできます (デフォルトはオフ)。これは、次のプロパティを通じて設定できます:
    set global log_queries_not_using_indexes = "ON"
  3. MySQL では、ログ出力形式として FILE (デフォルト) と TABLE がサポートされており、組み合わせて使用​​できます。以下のように:
    set global log_output = "FILE, TABLE"
    この設定は、MySQL ライブラリの FILE とslow_log テーブルに同時に書き込まれます。ただし、システムの専用ログ テーブルへのログ記録は、ファイルへのログ記録よりも多くのシステム リソースを消費するため、低速クエリ ログを有効にしてより高いシステム パフォーマンスを得る必要がある場合は、最初にファイルへのログ記録を行うことをお勧めします。

5.2 実行計画の説明

上記の遅いクエリのログ分析を通じて、どのような遅い SQL ステートメントがあるかを知ることができます。ただし、これらの SQL が遅い場合とその最適化方法については、より詳細な分析計画も必要です。ここで、MySQL は SQL ステートメントの詳細な実行情報を分析できる Explain キーワードを提供します。

5.2.1 Explain の使用法

テスト用にデータベースにユーザーテーブルを作成します

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `password` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `sex` varchar(2) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `phone` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `dept_id` int(10) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `idx_name`(`name`) USING BTREE,
  INDEX `idx_dept_id`(`dept_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, '张三', '123', '男', '12323432', 1);
INSERT INTO `user` VALUES (2, '李四', '456', '男', '178873937', 1);
INSERT INTO `user` VALUES (3, '小花', '123', '女', '1988334554', 2);
INSERT INTO `user` VALUES (4, '小芳', '334', '女', '18765287937', 2);
INSERT INTO `user` VALUES (5, NULL, '122', NULL, NULL, NULL);


DROP TABLE IF EXISTS `dept`;
CREATE TABLE `dept`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `dept_name` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of dept
-- ----------------------------
INSERT INTO `dept` VALUES (1, '开发部');
INSERT INTO `dept` VALUES (2, '销售部');

Explain の使い方も非常に簡単で、クエリ ステートメントの前に Explain キーワードを追加するだけです。

EXPLAIN SELECT * FROM user where id = 1;

画像-20221002104547978

この図から、MySQL がレコードの行を返すことがわかります。各フィールドの意味を分析してみましょう。

分野 意味
ID クエリプロセス内の選択ステートメントの一意の識別子
選択タイプ クエリ タイプ (単純、プライマリ、サブクエリ、派生の 4 つを含む)
テーブル どのテーブルがクエリされるか
パーティション テーブルパーティション情報
タイプ アクセスタイプ、分析パフォーマンスは主にこのフィールドを介して行われます
possible_keys 使用できるインデックス
実際に使用されるインデックス
key_len インデックスで使用されるバイト数
参照 この列には、キー列レコードのインデックス内のテーブル検索値に使用される列または定数が表示されます。
MySQL の推定スキャン行数
フィルタリングされた MySQLフィルタリング後、条件を満たすレコード数の割合
余分な いくつかの追加情報を示します

5.2.2 詳しく説明する

1、ID

id はクエリ ステートメント内の一意の識別子です。id の値が大きいほど、id に対応する SQL ステートメントがより早く実行されます。

explain select * from dept where id = (select dept_id from user where id = 1);

画像-20221002111658358

実行プランの観点から見ると、外側のクエリにはこのクエリ ステートメントの結果が必要であるため、ステートメント select dept_id from user where id = 1 が最初に実行されます。

2、タイプの選択

クエリ タイプ (4 つを含む)

シンプル: 単純なクエリ。クエリにサブクエリとユニオンが含まれていません

画像-20221002112227619

プライマリ: 複雑なクエリの最も外側の選択

画像-20221002111658358

subquery: select に含まれるサブクエリ (from 句には含まれていません)

画像-20221002111658358

派生: from 句に含まれるサブクエリ。MySQL は結果を一時テーブル (派生テーブル (派生の英語の意味) とも呼ばれます) に保存します。

3、テーブル

どのテーブルがクエリされているかを理解しやすくなります

4、パーティション

クエリ中に一致したパーティション情報。非パーティション テーブルの値は NULL です。クエリがパーティション テーブルの場合、パーティションには、パーティション テーブルによってヒットしたパーティションが表示されます。

5、タイプ

type: 使用されているクエリのタイプ。これは SQL 最適化において非常に重要な指標です。次のパフォーマンスは良いものから悪いものの順に表示されます。system > const > eq_ref > ref > ref_or_null > range > index > ALL

  • system は const の特殊なケースです。つまり、テーブルにレコードが 1 つだけある場合、タイプは system です。

  • const、定数クエリ、id は主キー、すべての情報は id を通じてクエリ可能

    画像-20221002113133121

  • eq_ref、接続クエリでは、主キーまたは一意のキー インデックスのすべての部分が接続で使用されます。

注: ここでは、dept の ID とユーザーの ID は関係ありません。単にクエリの種類を示すためです。

画像-20221002113825037

user の ID と dept の ID は両方とも主キーであり、接続クエリでは両方の主キーが使用されます

  • ref、一意のインデックスは使用しません。共通インデックスまたは一意のインデックスを使用します。複数の条件の値が見つかる可能性があります。idx_name は共通インデックスです。

画像-20221002114115876

  • ref_of_null は、ref 関数と似ていますが、インデックスが NULL を含む値をさらに検索する点と、名前フィールドが通常のインデックスであり、データベース内に名前が null のデータが存在する点が異なります。

画像-20221002114412412

  • 範囲、インデックス フィールドで範囲クエリを使用します。一般的なクエリは >、<、in、like などです。

画像-20221002145754924

  • インデックス、インデックス ツリーによるフル テーブル スキャン

画像-20221002150036038

  • ALL、完全なテーブル スキャン、これは select * クエリであるため、インデックス ツリーを渡しません。

画像-20221002150112138

6、可能なキー

MySQL は、このクエリで使用される可能性があるインデックスを分析しますが、実際のクエリでは使用されない可能性があります。

画像-20221002150344478

分析では idx_name インデックスが使用される場合がありますが、このインデックスは実際のクエリでは使用されず、テーブル全体のスキャンが実行されます。

7、キー

クエリで実際に使用されるキー

画像-20221002150558281

インデックス idx_name はクエリで実際に使用されます。

8、ケンレン

クエリで使用されるインデックス列の長さを示します。

画像-20221002150558281

このインデックスを使用して分析します。key_len が 63 からどのように由来するのか?

画像-20221002151036404

ユーザーテーブルを作成する際、nameの文字セットがutf8であることに気づきましたか?

MySQL バージョン 5.0 以降では、utf8 文字セットの各文字は 3 バイトを占有し、varchar(20) は 60 バイトを占有します。同時に、varchar は可変長文字列であるため、長さを格納するには追加のバイトが必要です文字の合計 2 バイトに加え、名前フィールドは NULL 値にすることができ、NULL 値は 1 バイトだけを占有し、合計で最大 63 バイトになります。

9、参照

インデックス列の等価一致条件を使用してクエリを実行する場合、つまり、アクセス方法がconsteq_refrefref_or_nullのいずれかの場合unique_subquery列にはインデックス列と同等の特定の情報 (定数のみ、またはカラム。index_subqueryref

画像-20221002152423370

10、行

スキャンされることが予想される関数

11、フィルター済み

filtered これは、条件を満たすテーブル内のレコード数のパーセンテージを表すパーセンテージ値です。簡単に言うと、このフィールドは、ストレージ エンジンから返されたデータをフィルター処理した後に条件を満たすレコード数の割合を示します。

12、番外編

Extraクエリをより正確に理解できるように、ある程度の情報を説明するために使用されます。

5.3 高パフォーマンスのインデックス使用戦略

5.3.1 インデックス付き列に対して操作を実行しない

explain select * from user where left(name,2) = '小芳';

画像-20221002153601423

この SQL は名前フィールドに対して関数操作を実行するため、インデックスが失敗します。

5.3.2 左端のプレフィックスルール

結合インデックス クエリを使用する場合は、左端のプレフィックスの原則に従う必要があります。つまり、クエリはインデックスの最前列の左端から開始され、インデックス内の列をスキップしません。

名前、価格、マークの 3 つのフィールドを含むジョイント インデックスを持つ商品テーブルを作成します。

DROP TABLE IF EXISTS `goods`;
CREATE TABLE `goods`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `price` int(10) NULL DEFAULT NULL,
  `mark` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `idx_all`(`name`, `price`, `mark`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of goods
-- ----------------------------
INSERT INTO `goods` VALUES (1, '手机', 5678, '华为手机');
INSERT INTO `goods` VALUES (2, '电脑', 9888, '苹果电脑');
INSERT INTO `goods` VALUES (3, '衣服', 199, '好看的衣服');

次のクエリ ステートメントを実行します。

explain select * from goods where name = '手机' and price = 5678 and mark = '华为手机';

画像-20221002155147045

上の図から、タイプが ref であることがわかります。

ここで、クエリを左端から開始するのではなく、名前フィールドをスキップするだけです。

explain select * from goods where price = 5678 and mark = '华为手机';

画像-20221002155322785

型が ref から Index に変更されました。これは、MySQL が複合インデックス内のフィールドの順序に従って結合インデックス内のフィールドを並べ替えるためです。中央のフィールドがスキップされた場合、必ずしも順序どおりであるとは限りません。

5.3.3 カバリングインデックスを使ってみる

インデックスをカバーし、クエリが必要なフィールドはすべてインデックス列に含まれており、クエリのためにテーブルに戻る必要はありません。

おすすめ

転載: blog.csdn.net/wgzblog/article/details/127259013
おすすめ