MySQLクエリプランでken_lenの値を計算する方法

MySQLクエリプランでken_lenの値を計算する方法

key_lenの意味

MySQL では、次に示すように、explain を使用して SQL ステートメントがたどったパスを表示できます。

mysql> テーブル t(a int 主キー、b int not null、c int not null、インデックス(b)) を作成します。
 クエリは正常、影響を受けた行は 0 行 (0.01 秒)
 mysql> explain t から b を選択します。
 +----+-------------+-------+-------+---------------+-------+-------+------+------------+------------+
 | id | select_type | テーブル | タイプ | possible_keys | key | key_len | ref | 行 | 追加 |
 +----+-------------+-------+-------+---------------+-------+-------+------+------------+------------+
 | 1 | SIMPLE | t | インデックス | NULL | b | 4 | NULL | 1 | インデックスの使用 |
 +----+-------------+-------+-------+---------------+-------+-------+------+------------+------------+
 セット内の 1 行 (0.00 秒)

このうち、key_len は使用されるインデックスの長さ(バイト単位)を表します。上記の例では、int 型が 4 バイトを占め、インデックスには 1 つの列のみが含まれるため、key_len は 4 になります。

共同インデックスは次のようになります。

mysql> テーブル t を変更し、インデックス ix(b, c) を追加します。
クエリは正常、影響を受けた行は 0 行 (0.03 秒)
レコード: 0 重複: 0 警告: 0
mysql> explain select b, c from t;
+----+-------------+-------+-------+---------------+-------+-------+------+------------+------------+
| id | select_type | テーブル | タイプ | possible_keys | key | key_len | ref | 行 | 追加 |
+----+-------------+-------+-------+---------------+-------+-------+------+------------+------------+
| 1 | SIMPLE | t | インデックス | NULL | ix | 8 | NULL | 1 | インデックスの使用 |
+----+-------------+-------+-------+---------------+-------+-------+------+------------+------------+
セット内の 1 行 (0.00 秒)

結合インデックス ix には 2 つの列が含まれており、両方が使用されているため、ken_len は 8 になります。

この時点で、key_lenの意味はすでに理解できており、これ以上言うことはないように思えます。しかし、MySQLにおけるkey_lenの計算には、まだ注意すべき点がたくさんあります。

たとえば、列 b の NOT NULL 制約を削除すると、ken_len は次のように予想したものと異なります。

mysql> テーブル t を変更して b int を変更します。
クエリは正常、影響を受けた行は 0 行 (0.01 秒)
レコード: 0 重複: 0 警告: 0
 
mysql> explain t から b を選択します。
+----+-------------+-------+-------+---------------+-------+-------+------+------------+------------+
| id | select_type | テーブル | タイプ | possible_keys | key | key_len | ref | 行 | 追加 |
+----+-------------+-------+-------+---------------+-------+-------+------+------------+------------+
| 1 | SIMPLE | t | インデックス | NULL | b | 5 | NULL | 1 | インデックスの使用 |
+----+-------------+-------+-------+---------------+-------+-------+------+------------+------------+
セット内の 1 行 (0.00 秒)

MySQL の key_len の計算ルール

MySQL では、key_len の計算規則は次のとおりです。

  • 列が空になる可能性がある場合は、データ型が占めるバイト数に 1 を加算します。たとえば、int 型が空になる可能性がない場合、key_len は 4 になり、空になる可能性がある場合は、key_len は 5 になります。
  • 列が可変長の場合は、データ列が占める基本バイト数に 2 を加算します。たとえば、varbinary(10) が空にできない場合、key_len は 10 + 2 になります。空にできる場合、key_len は 10+2+1 になります。
  • 文字型の場合は、文字セットも考慮する必要があります。たとえば、列が varchar(10) として定義され、utf8 であり、空にできない場合、key_len は 10 * 3 + 2 になります。空にできる場合、key_len は 10*3+2+1 になります。
  • また、小数列の計算方法は上記と同じです。空になる可能性がある場合は、データ型が占めるバイト数に 1 を加算します。ただし、小数自体が占めるバイト数の計算はより複雑です。

公式文書によると、小数は、decimal(M,D) と定義されています。ここで、M は合計桁数、D は小数点以下の桁数です。小数点の前後の数字は別々に格納され、9桁を1つにまとめて4バイトを使用して格納されます。9桁未満の数値の場合、必要なバイト数は次のとおりです。

残りの桁数 バイト数
-----------------------------
|0 |0 |
|1-2 |1 |
|3-4 |2 |
|5-6 |3 |
|7-9 |4 |
-----------------------------

例えば:

小数点(20,6) => 小数点の左側に14桁、小数点の右側に6桁 => 小数点の左側の数字は5 + 9にグループ化され、保存には3バイト + 4バイトが必要で、小数点は保存に3バイトにグループ化され => 合計10バイトが必要です
小数点(18,9) => 小数点の左側に9桁、小数点の右側に9桁 => それぞれ4バイトを使用して格納 => 合計8バイト
小数点の左側に16桁、小数点の右側に2桁 => 7 + 9としてグループ化され、保存に8バイト必要、小数点の右側に1バイト => 合計9バイト必要

key_lenによる結合インデックスを分析する

以下に示すように、4 つの列 a、b、c、d を含むテーブル t を定義します。

mysql> テーブル t\G の作成を表示します
************************** 1. 行 ****************************
    表: t
テーブルの作成: CREATE TABLE `t` (
 `a` int(11) NULLではない、
 `b` int(11) デフォルト NULL,
 `c` int(11) デフォルト NULL,
 `d` int(11) デフォルト NULL,
 主キー (`a`)、
 キー `ix_x` (`b`,`d`,`c`)
) エンジン=InnoDB デフォルト文字セット=utf8
セット内の 1 行 (0.00 秒)

実行される SQL ステートメントは次のようになります。

b = 5、d = 10 の場合に t から a を選択し、c で並べ替えます。

インデックス ix_x(b,d,c) があり、explain を通じて次の出力が返されるとします。

mysql> explain select a from t where b = 5 and d = 10 order by c;
+----+-------------+-------+-------+---------------+-------+-----------+------+----------------------------+
| id | select_type | テーブル | タイプ | possible_keys | key | key_len | ref | 行 | 追加 |
+----+-------------+-------+-------+---------------+-------+-----------+------+----------------------------+
| 1 | SIMPLE | t | ref | ix_x | ix_x | 10 | const,const | 1 | where の使用; index の使用 |
+----+-------------+-------+-------+---------------+-------+-----------+------+----------------------------+
セット内の 1 行 (0.00 秒)

ご覧のとおり、クエリ ステートメントは結合インデックスの b 列と d 列を使用してデータをフィルター処理します。

定義する結合インデックスが `ix_x(b, d, c)` ではなく `ix_x(b, c, d)` の場合、explain によって取得される入力は次のようになります。

mysql> テーブル t を変更してインデックス ix_x を削除します。
mysql> テーブル t を変更し、インデックス ix_x(b, c, d) を追加します。
mysql> explain select a from t where b = 5 and d = 10 order by c;
+----+-------------+-------+-------+---------------+-------+------+------+------+---------------------------+
| id | select_type | テーブル | タイプ | possible_keys | key | key_len | ref | 行 | 追加 |
+----+-------------+-------+-------+---------------+-------+------+------+------+---------------------------+
| 1 | SIMPLE | t | ref | ix_x | ix_x | 5 | const | 2 | where の使用; index の使用 |
+----+-------------+-------+-------+---------------+-------+------+------+------+---------------------------+
セット内の 1 行 (0.00 秒)

key_len は 5 です。つまり、結合インデックスの最初の列のみが使用されます。結合インデックスにはクエリするすべての列が含まれていますが、定義順序のため、SQL ステートメントはインデックスを十分に活用できないことがわかります。

以下もご興味があるかもしれません:
  • mysql 時間差計算関数
  • MySQL で誕生日から年齢を計算する複数の方法
  • PHP と MySql で時間差を計算する方法
  • MySQL 文字列長計算実装コード (gb2312+utf8)
  • MySQLデータベースのQPSとTPSの意味と計算方法
  • MySQL の重要なパフォーマンス インデックスの計算と最適化方法の概要
  • mysqlのkey_lenの計算方法についての簡単な説明
  • MySQLの日付と時刻の間隔計算の分析例
  • MySQLの日付加算と減算関数の詳細な説明
  • mysql トリガーの作成と使用例
  • MySQL トリガーの基本的な使い方(作成、表示、削除など)の詳細な説明
  • MySQL累積計算実装方法の詳しい説明

<<:  Docker で ElasticSearch をデプロイする方法

>>:  Javascript の奇妙な点をご存知ですか?

推薦する

HTML テーブルの境界線を設定する際のヒント

HTML を初めて使用する多くの人にとって、テーブル <table> は最もよく使用され...

MySQLがフルテーブルスキャンを実行するいくつかの状況

目次ケース1:ケース2:ケース3:簡単にまとめると:過去 2 日間で、完全なテーブル スキャンを引き...

HTML の著作権記号のフォント選択問題 (著作権記号をより美しくする方法)

1. 問題を発見する&copy; は HTML の著作権記号ですが、間違ったフォントを選択す...

JS オブジェクト配列の重複排除のための 3 つの方法の例と比較

目次1. 重複排除前後のデータの比較2. 使い方1. フィルターとマップを使用する2. 削減を使用す...

JavaScript の組み込み Date オブジェクトの詳細な説明

目次日付オブジェクト日付オブジェクトの作成新しい日付()日付を取得する()取得日()月を取得する()...

Node.js での SerialPort モジュールの使用

目次目的モジュールのインストール基本的な使い方ポートをスキャンする開いているポートデータの送信データ...

Vue でメニュー権限制御を実装するためのサンプルコード

バックエンド管理システムで作業している場合、通常、メニュー権限制御に関連する問題に遭遇します。もちろ...

JavaScript で最も高速なループはどれですか?

どの for ループまたは反復子がニーズに適しているかを知ることで、アプリケーションのパフォーマンス...

MySQL 接続例外とエラー 10061 の解決方法

MySQL は、スウェーデンの会社 MySQL AB によって開発されたリレーショナル データベース...

CentOS 7.2 は uniapp プロジェクトを展開するための nginx Web サーバーを構築します

Pantherは新人としてスタートし、今もまだ新人ですが、人々から学び、学んだことを時々皆さんと共有...

Vue3+Element+Tsは、フォームの基本的な検索リセットやその他の機能を実装します

Vue2 の記述スタイルから Vue3 の形式に切り替えると、記述スタイルとコード構造にいくつかの変...

キーフリーログインプロセスを実現するためのLinux構成の分析

1.sshコマンドLinux では、ssh コマンドを使用して別のサーバーにログインできます。 2 ...

JavaScriptスコープについての簡単な説明

目次1. 範囲1. グローバルな範囲2. ローカルスコープ2. 変数のスコープ1. グローバル変数2...

クラウドネイティブテクノロジー Kubernetes (K8S) の紹介

目次01 Kubernetes とは何ですか? 02 KubernetesとCompost+Swar...

Linux での MySQL のアンインストールとインストールのグラフィック チュートリアル

ブログを書くのは初めてです。開発に携わって2年になります。仕事の後に何か有意義なことを見つけたいと思...