MySQL CHARとVARCHARの保存と読み取りの違い

MySQL CHARとVARCHARの保存と読み取りの違い

導入

保存時と読み取り時に CHAR 型と VARCHAR 型の違いを本当にご存知ですか?

まずいくつかの結論を述べたいと思います。

1. CHAR は、ユーザーがデータを挿入するときに末尾にスペースを含めるかどうかに関係なく、保存する前に常にスペースで埋められます。

2. VARCHAR は格納時にスペースを埋めて格納しませんが、挿入時にユーザーが明示的にスペースを追加した場合は、そのまま格納され、削除されません。

3. データを読み取るとき、CHAR は常に末尾のスペースを削除します (書き込み時にスペースが含まれている場合でも)。

4. データを読み取るとき、VARCHAR は常に以前に格納された値を忠実に取得します (格納時に末尾のスペースがある場合、それは保持され続け、CHAR のように末尾のスペースは削除されません)。

以下はテスト検証プロセスです。

1. CHAR型をテストする

テーブル構造:

テーブル `tchar` を作成します (
 `id` int(10) unsigned NOT NULL DEFAULT '0',
 `c1` char(20) NOT NULL デフォルト ''
 主キー (`id`)
)ENGINE=InnoDB デフォルト文字セット=utf8mb4;

いくつかのレコードを挿入します:

tchar値に挿入します(1、concat('a'、repeat(' '、19)));
tchar値に挿入します(2、concat(' '、repeat('a'、19)));
tchar値に挿入します(3、 'a');
tchar値に挿入します(4、 ' ');
tchar値に挿入(5、'');

ストレージ構造を表示します。

(1) INFIMUMレコードオフセット:99 ヒープ番号:0 ...
(2) SUPREMUMレコードオフセット:112 ヒープ番号:1 ...
(3)通常レコード オフセット:126 ヒープ番号:2 ... <- id=1
(4) 通常レコード オフセット:169 ヒープ番号:3 ... <- id=2
(5) 通常レコード オフセット:212 ヒープ番号:4 ... <- id=3
(6) 通常レコード オフセット:255 ヒープ番号:5 ... <- id=4
(7) 通常レコード オフセット:298 ヒープ番号:6 ... <- id=5

これを見ると少し混乱しますか? 私がお勧めしたツールを覚えていますか? こちらをご覧ください: innblock | InnoDB ページ監視ツール。

ご覧のとおり、文字列の長さに関係なく、各レコードは実際には 43 (169-126=43) バイトを占めます。したがって、結論1が成り立ちます。
簡単に言うと、43 バイトの起源は次のとおりです。
DB_TRX_ID、6 バイト。
DB_ROLL_PTR、7 バイト。
id、int、4 バイト。
c1、char(20)、20バイト。CHAR型なので、追加のバイトが必要です。
各レコードには、常に追加の 5 バイトのヘッダー情報 (行ヘッダー) が必要です。
合計は 43 バイトになります。

tchar テーブルを読み取った結果を見てみましょう。

tcharからid、concat('000'、c1、'$$$')、length(c1)を選択します。
+----+----------------------------+------------+
| id | 連結('000',c1,'$$$') | 長さ(c1) |
+----+----------------------------+------------+
| 1 | 000a$$$ | 1 | <- 末尾のスペースを削除 | 2 | 000 aaaaaaaaaaaaaaaaaaaa$$$ | 20 |
| 3 | 000a$$$ | 1 |
| 4 | 000$$$ | 0 | <- 末尾のスペースを削除すると、結果は id=5 と同じになります | 5 | 000$$$ | 0 |
+----+----------------------------+------------+

2. VARCHAR型のテスト

テーブル構造:

テーブル `tvarchar` を作成します (
 `id` int(10) unsigned NOT NULL DEFAULT '0',
 `c1` varchar(20) NOT NULL デフォルト ''
 主キー (`id`)
) エンジン=InnoDB デフォルト文字セット=utf8mb4

いくつかのレコードを挿入します:

tvarchar値に挿入します(1、concat('a'、repeat(' '、19)));
tvarchar値に挿入します(2、concat(' '、repeat('a'、19)));
tvarchar値に挿入します(3、 'a');
tvarchar値に挿入します(4、 ' ');
tvarchar値に挿入(5、'');
tvarchar値に挿入(6、'');

ストレージ構造を表示します。

(1) INFIMUMレコードオフセット:99 ヒープ番号:0 ...
(2) SUPREMUMレコードオフセット:112 ヒープ番号:1 ...
(3)通常レコード オフセット:126 ヒープ番号:2 ... <- id=1
(4) 通常レコード オフセット:169 ヒープ番号:3 ... <- id=2
(5) 通常レコード オフセット:212 ヒープ番号:4 ... <- id=3
(6) 通常レコード オフセット:236 ヒープ番号:5 ... <- id=4
(7) 通常レコード オフセット:260 ヒープ番号:6 ... <- id=5
(8) 通常レコード オフセット:283 ヒープ番号:7 ... <- id=6

いくつかのレコードのバイト数は 43、43、24、24、23、23 であることがわかります (最後のレコードは id=5 のレコードと同じです)。
上記の結果は少し意外ですね。特に、id=1 のレコード ('a... の後に 19 個のスペースが挿入されています) は 43 バイトを消費します。これは、上記の結論 2 を証明しています。
同様に、id=3 と id=4 の 2 つのレコードはどちらも 24 バイトを占め、id=5 と id=6 の 2 つのレコードはどちらも 23 バイトを占めます (文字列を格納するための追加のバイト数はなく、id 列用の 4 バイトのみです)。

tvarchar テーブルを読み取った結果を見てみましょう。

tvarchar から id、concat('000'、c1、'$$$')、length(c1) を選択します。
+----+----------------------------+------------+
| id | 連結('000',c1,'$$$') | 長さ(c1) |
+----+----------------------------+------------+
| 1 | 000a $$$ | 20 | <- 読み取り結果では末尾のスペースは削除されません | 2 | 000 aaaaaaaaaaaaaaaaaa$$$ | 20 |
| 3 | 000a$$$ | 1 |
| 4 | 000 $$$ | 1 | <- このスペースは読み取り結果では削除されません | 5 | 000$$$ | 0 |
| 6 | 000$$$ | 0 |
+----+----------------------------+------------+

一般的に、2 つの結論を導き出すことができます。
1. 読み取り結果から、CHAR 型の列は保存時にスペースを食っているように見えますが、実際には読み取り時にのみ食われています (表示レベルでスペースは削除されます)。
2. 読み取り結果から、VARCHAR 型の列に余分なスペースが残っているように見えます。実際には、これらのスペースは読み取り時にのみ復元されます (ただし、実際の物理ストレージではこれらのスペースは削除されます)。

最後に、ドキュメントに何が書かれているか見てみましょう。

CHAR値が保存されるとき、右側にスペースが埋め込まれ、
つまり、CHAR 列は長さを補うために末尾にスペースが入った状態で保存されます。

CHAR値が取得されると、末尾のスペースは削除されます。
PAD_CHAR_TO_FULL_LENGTH SQL モードが有効になっています。
つまり、sql_mode 値 PAD_CHAR_TO_FULL_LENGTH=1 が設定されていない限り、CHAR 列は末尾のスペースが削除されて読み取られます。

VARCHAR 値は保存時にパディングされません。
つまり、VARCHAR を保存するときに末尾のスペースは追加されません。

末尾のスペースは、値が保存および取得されるときに保持されます。
標準 SQL に準拠しています。つまり、VARCHAR が読み取られるときにスペースが表示されます。

上記のテストで使用されたバージョンと環境は次のとおりです。

mysql> バージョンを選択()\G
...
バージョン(): 8.0.15

mysql> @@sql_mode\G を選択
...
@@sql_mode: ONLY_FULL_GROUP_BY、STRICT_TRANS_TABLES、NO_ZERO_IN_DATE、NO_ZERO_DATE、ERROR_FOR_DIVISION_BY_ZERO、NO_ENGINE_SUBSTITUTION

参照ドキュメント

11.4.1 CHAR 型と VARCHAR 型、https://dev.mysql.com/doc/refman/5.7/en/char.html

上記はMySQL CHARとVARCHARストレージの違いの詳細な内容です。MySQL CHARとVARCHARの詳細については、123WORDPRESS.COMの他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • MySQL CHARとVARCHARの選択方法
  • Mysql の varchar 型に関する注意点
  • MYSQL における char と varchar の違い
  • MySQL の char、varchar、text フィールド タイプの違い
  • Mysql varchar型の合計操作例
  • MySQL の int、char、varchar のパフォーマンスを比較する
  • MySQL で varchar の長さを動的に変更する方法
  • Mysqlでvarcharの長さを設定する方法
  • Mysql データベースで varchar 型を int 型に変換する方法
  • MySQLはvarchar型とnvarchar型の特殊文字をどのように処理しますか
  • 面接官がmysqlのcharとvarcharの違いを尋ねたとき

<<:  jsを使用してスライダーをドラッグする効果を実現します

>>:  ServerSocketのデフォルトIPバインディングの実装プロセスの詳細な説明

推薦する

Vue ページ スタック マネージャーの詳細

目次2. 試した方法2.1 キープアライブ2.2 ネストされたルートを持つ CSS 3. 機能説明4...

MySQL 5.7 のスロークエリログの時間がシステム時間より 8 時間遅れている理由の詳細な説明

遅いクエリをチェックすると、時間が正しくなく、システム時間とちょうど 8 時間異なっていることがわか...

mysql 5.7.18 winx64 パスワード変更

MySQL 5.7.18 が正常にインストールされた後、バージョン 5.7 では空のパスワードでのロ...

CSS3のtext-fill-colorプロパティの詳細な説明

text-fill-color とは何を意味しますか?文字通りの意味から言えば、「テキストの塗りつぶ...

Linux 環境変数とプロセス アドレス空間の概要

目次Linux 環境変数とプロセスアドレス空間コードを通じて環境変数を取得するプロセスアドレス空間な...

Vue v-for ループを書く 7 つの方法

目次1. v-forループでは常にキーを使用する2. 特定のスコープ内でv-forループを使用する3...

HTML の iframe と frame の違いを例を使って説明します

プロジェクトで frameset 属性を使用したことがあるかどうかはわかりません。昨年、オンライン ...

CentOS 6.8 での Hadoop 3.1.1 完全分散インストール ガイド (推奨)

上記:このドキュメントは、3 台の仮想マシンが相互に ping を実行できること、ファイアウォールが...

MySQLストアドプロシージャの原理と使用法の詳細な説明

この記事では、例を使用して、MySQL ストアド プロシージャの原理と使用方法を説明します。ご参考ま...

MySQL の完全なデータベース バックアップ データを使用して単一のテーブル データを復元する方法

序文データベースをバックアップするときは、データベース全体のバックアップを使用します。ただし、何らか...

画像を読み込むための JavaScript キャンバス

この記事では、画像を読み込むためのJavaScriptキャンバスの具体的なコードを参考までに紹介しま...

Vue の基本リスナーの詳細な説明

目次Vueのリスナーとは何かリスナーの使い方vue リスナーウォッチVue リスナー - ディープリ...

Vueの監視プロパティの詳細

目次1.watchは一般的なデータ(数値、文字列、ブール値)の変更を監視します。 1. 数値2. 文...