MySQL InnoDB インデックス拡張の詳細な説明

MySQL InnoDB インデックス拡張の詳細な説明

インデックス拡張: InnoDB は、プライマリ キー列をそのインデックスに追加することで、各セカンダリ インデックスを自動的に拡張します。次のテーブル構造を作成します。

mysql> テーブル t1 を作成します (
  -> i1 INT NOT NULL デフォルト 0,
  -> i2 INT NOT NULL デフォルト 0,
  -> d 日付デフォルト NULL、
  -> 主キー (i1, i2)、
  -> インデックス k_d (d)
  ->) エンジン = InnoDB;

クエリは正常、影響を受けた行は 0 行 (0.14 秒)

テーブル t1 には、列 (​​i1、i2) に定義された主キーがあります。列 (d) にもセカンダリ インデックスが定義されていますが、InnoDB はこのインデックスを拡張し、(d,i1,i2) として扱います。

オプティマイザーは、インデックスの使用方法と使用の有無を決定する際に、拡張セカンダリ インデックスの主キー列を考慮します。これにより、クエリ実行プランの効率が向上し、パフォーマンスが向上します。

オプティマイザーは、ref、range、index_merge インデックス アクセス、ルーズ インデックス スキャン、結合およびソートの最適化、および MIN()/MAX() の最適化に拡張セカンダリ インデックスを使用できます。

次の例は、オプティマイザーが拡張セカンダリ インデックスを使用して実行プランに影響を与え、次のデータをテーブル t1 に挿入するかどうかを示します。

mysql> t1 に値 (1, 1, '1998-01-01')、(1, 2, '1999-01-01')、(1, 3, '2000-01-01')、(1, 4, '2001-01-01') を挿入します。
  ->(1, 5, '2002-01-01')、(2, 1, '1998-01-01')、(2, 2, '1999-01-01')、(2, 3, '2000-01-01')、(2, 4, '2001-01-01')、
  ->(2, 5, '2002-01-01')、(3, 1, '1998-01-01')、(3, 2, '1999-01-01')、(3, 3, '2000-01-01')、(3, 4, '2001-01-01')、
  ->(3, 5, '2002-01-01')、(4, 1, '1998-01-01')、(4, 2, '1999-01-01')、(4, 3, '2000-01-01')、(4, 4, '2001-01-01')、
  ->(4, 5, '2002-01-01')、(5, 1, '1998-01-01')、(5, 2, '1999-01-01')、(5, 3, '2000-01-01')、(5, 4, '2001-01-01')、
  ->(5, 5, '2002-01-01');
クエリは正常、25 行が影響を受けました (0.05 秒)
記録: 25 重複: 0 警告: 0

次のクエリが実行されるとします。

optimizer_switch を 'use_index_extensions=off' に設定します。
i1=3かつd= '2000-01-01'の場合、t1からcount(*)を選択します。

この場合、主キーに列 (i1、i2) が含まれており、クエリが i2 を参照していないため、オプティマイザーは主キーを使用できません。代わりに、オプティマイザは列 (d) のセカンダリ インデックス k_d を使用することができ、実行プランは拡張インデックスが使用されるかどうかによって異なります。

オプティマイザがインデックス拡張を考慮しない場合、インデックスk_dは単に(d)として扱われます。

mysql> SET optimizer_switch = 'use_index_extensions=off';
クエリは正常、影響を受けた行は 0 行 (0.00 秒)

mysql> explain select count(*) from t1 where i1=3 and d= '2000-01-01' \G;
************************** 1. 行 ****************************
      id: 1
 選択タイプ: シンプル
    テーブル: t1
  パーティション: NULL
     タイプ: ref
可能なキー: PRIMARY、k_d
     キー: PRIMARY
   キーの長さ: 4
     参照: 定数
     行数: 5
   フィルター: 20.00
    追加: where の使用
セットに 1 行、警告 1 件 (0.00 秒)

オプティマイザがインデックス拡張を考慮する場合、k_d は (d, i1, i2) であるとみなします。この場合、左端のインデックス プレフィックス (d, i1) を使用して、より適切な実行プランを生成できます。

mysql> SET optimizer_switch = 'use_index_extensions=on';
クエリは正常、影響を受けた行は 0 行 (0.00 秒)

mysql> explain select count(*) from t1 where i1=3 and d= '2000-01-01' \G;
************************** 1. 行 ****************************
      id: 1
 選択タイプ: シンプル
    テーブル: t1
  パーティション: NULL
     タイプ: ref
可能なキー: PRIMARY、k_d
     キー: k_d
   キーの長さ: 8
     参照: const、const
     行数: 1
   フィルター: 100.00
    追加: インデックスの使用
セットに 1 行、警告 1 件 (0.00 秒)

どちらの場合も、 key はオプティマイザーがセカンダリ インデックス k_d を使用することを示していますが、 EXPLAIN 出力には拡張インデックスの使用による次の改善が示されています。

.key_len が 4 バイトから 8 バイトに変更されました。これは、キー検索で d だけでなく列 d と i1 が使用されることを示しています。

キー検索では 1 つのキー列ではなく 2 つのキー列が使用されるため、.ref の値は const から const,const に変わります。

.rows: 5 から 1 に減少し、InnoDB がクエリ結果を生成するために検査する行数が少なくなることを示します。

.Extra 値が、Using where; Using index から Using index に変更されました。つまり、レコードをクエリするには、データ行レコードをクエリするのではなく、インデックスのみを使用する必要があります。

show status を使用すると、拡張インデックスを使用したオプティマイザーと使用しないオプティマイザーの違いを確認できます。

mysql> テーブル t1 をフラッシュします。
クエリは正常、影響を受けた行は 0 行 (0.01 秒)

mysql> ステータスをフラッシュします。
クエリは正常、影響を受けた行は 0 行 (0.03 秒)

上記の flush table および flush status ステートメントは、テーブル キャッシュをクリアし、ステータス統計をクリアするために使用されます。

インデックス拡張を使用しない場合の show status の結果は次のとおりです。

mysql> SET optimizer_switch = 'use_index_extensions=off';
クエリは正常、影響を受けた行は 0 行 (0.01 秒)

mysql> t1 から count(*) を選択します。ここで、i1=3、d= '2000-01-01' です。
+----------+
| カウント(*) |
+----------+
| 1 |
+----------+
セット内の 1 行 (0.00 秒)

mysql> 'handler_read%' のようなステータスを表示します。
+-----------------------+-------+
| 変数名 | 値 |
+-----------------------+-------+
| ハンドラー_read_first | 0 |
| ハンドラー読み取りキー | 1 |
| ハンドラー_read_last | 0 |
| ハンドラー_read_next | 5 |
| ハンドラー_read_prev | 0 |
| ハンドラー読み取り回数 | 0 |
| ハンドラー_read_rnd_next | 0 |
+-----------------------+-------+
セット内の行数は 7 です (0.00 秒)

インデックス拡張を使用すると、show status は次の結果を生成し、handler_read_next の値が 5 から 1 に減少し、このインデックスを使用する方が効率的であることを示します。

mysql> テーブル t1 をフラッシュします。
クエリは正常、影響を受けた行は 0 行 (0.01 秒)

mysql> フラッシュステータス
  -> ;
クエリは正常、影響を受けた行は 0 行 (0.02 秒)

mysql> SET optimizer_switch = 'use_index_extensions=on';
クエリは正常、影響を受けた行は 0 行 (0.00 秒)

mysql> t1 から count(*) を選択します。ここで、i1=3、d= '2000-01-01' です。
+----------+
| カウント(*) |
+----------+
| 1 |
+----------+
セット内の 1 行 (0.00 秒)

mysql> 'handler_read%' のようなステータスを表示します。
+-----------------------+-------+
| 変数名 | 値 |
+-----------------------+-------+
| ハンドラー_read_first | 0 |
| ハンドラー読み取りキー | 1 |
| ハンドラー_read_last | 0 |
| ハンドラー_read_next | 1 |
| ハンドラー_read_prev | 0 |
| ハンドラー読み取り回数 | 0 |
| ハンドラー_read_rnd_next | 0 |
+-----------------------+-------+
セット内の行数は 7 です (0.01 秒)

optimizer_switch システム変数の use_index_extensions フラグを使用すると、オプティマイザは InnoDB テーブルのセカンダリ インデックスの使用方法を決定する際に、プライマリ キー列を考慮から除外できます。デフォルトでは、use_index_extensions は有効になっています。インデックス拡張を無効にするとパフォーマンスが向上するかどうかを確認するには、次のステートメントを実行します。

mysql> SET optimizer_switch = 'use_index_extensions=off';
クエリは正常、影響を受けた行は 0 行 (0.01 秒)

以上がMySQL InnoDBインデックス拡張の詳細な説明です。MySQLインデックス拡張の詳細については、123WORDPRESS.COMの他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • MySQL InnoDBエンジンのインデックスとストレージ構造の詳細な説明
  • MySQL InnoDBセカンダリインデックスのソート例の詳細な説明
  • MySQL Innodbインデックスの原理の詳細な説明
  • MySQL Innodb インデックス メカニズムの詳細な紹介
  • Mysql Innodb ストレージ エンジン インデックスとアルゴリズム

<<:  Linux zabbix エージェントの展開と設定方法の詳細な説明

>>:  Nginx の動的および静的分離実装ケースのコード分析

推薦する

CSS 前景と背景の自動カラーマッチング技術の紹介 (デモ)

1. カラーマッチング効果のプレビュー下の GIF に示すように、ボタンの背景色が徐々に薄くなると...

CSS で波の効果を作成するためのアイデア

以前、純粋な CSS を使用して波の効果を実現する方法をいくつか紹介しました。それらについては、次の...

選択ドロップダウンメニューのテキストを左右にスクロールするように設定する

marquee タグを使用してフォントのスクロールを設定したいです。コードは次のように記述しましたが...

タブバーの切り替え効果を実現するJavaScript

タブバー: 異なるタブをクリックすると異なるコンテンツが表示され、クリックしたタブのスタイルが変更さ...

DockerはMysql、.Net6、Sqlserverなどのコンテナをデプロイします

目次CentOS 8にDockerをインストールする1. yumを更新する2. containerd...

nginxアクセス制御の実装例

高性能で軽量なウェブサービスソフトウェアであるNginxについて高い安定性 システムリソースの消費量...

Nginx リバース プロキシから go-fastdfs へのケースの説明

背景go-fastdfs は、http プロトコルをサポートする分散ファイルシステムです。一般的なプ...

RedHat 6.5/CentOS 6.5 に MySQL 5.7.20 をインストールするための詳細なチュートリアル

rpmインストールパッケージをダウンロードするMySQL公式サイト: https://dev.mys...

vue3 でブロック崩しゲームを開発する方法をステップバイステップで教えます

序文vue3 を使った例をいくつか書いてみましたが、Vue3 のコンポジション API はよく設計さ...

MySQL 5.7 の Docker バージョンを MySQL 8.0.13 にアップグレードし、データを移行する

目次1. 古いMySQL5.7データをバックアップする2. MySQL8.0.13のイメージをプルし...

指定された期間内のすべての日付または月を取得する MySQL ステートメント (ストアド プロシージャの設定やテーブルの追加は不要)

mysql は期間内のすべての日付または月を取得します1: mysqlは期間内のすべての月を取得し...

vue3.0共通コンポーネントの自動インポート方法の例

1. 前提条件インポートには require.context メソッドを使用します。vite で作成...

フロントエンド Vue ユニットテストを始める

目次1. ユニットテストはなぜ必要なのでしょうか? 2. ユニットテストの書き方3. テストツール4...

JavaScript - Vue でのスロットの使用: スロット

目次Vue でのスロットの使用: slotスコープ付きスロット: テンプレートタグで囲む要約するVu...

MySQL実行計画の詳細な分析

序文前回の面接では、実行計画について質問されたとき、多くの人がそれが何なのか知りませんでした。実行計...