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バインディングの実装プロセスの詳細な説明

推薦する

Windows での MySQL の使用: 自動スケジュールバックアップの実装

1. バックアップスクリプトを書く 著者:www.yumi-info.com 日付:20171222...

Vue大画面表示適応方法

この記事では、vueの大画面表示適応の具体的なコードを参考までに紹介します。具体的な内容は以下のとお...

HBuilderX で Tomcat 外部サーバーを設定して、JSP インターフェイスを表示および編集する方法の詳細な説明

1. 最初の方法は、ローカルのTomcatを起動してJSPを表示することです。 tomcatのweb...

MySQL スロークエリログの詳細な理解

目次スロークエリログとは何ですか?スロークエリを有効にする方法ログ分析ツール mysqldumpsh...

星のフラッシュ効果を実現するjs

この記事の例では、スターフラッシュ効果を実現するためのjsの具体的なコードを参考までに共有しています...

フレックスボックスレイアウトの最終行の左揃えの実装アイデア

フレックスレイアウトを使用すると、9つの正方形のグリッドであれば、図に示すように均等に分割できます。...

Docker に ElasticSearch 6.x をインストールする詳細なチュートリアル

まず、イメージをプルします(またはコンテナを作成するだけで、自然にプルされます)。 docker p...

MySQL 分離列とプレフィックスインデックスの使用の概要

目次データ列を分離するプレフィックスインデックスとインデックスの選択性データ列を分離するMySQL ...

VMware 仮想マシンに固定 IP アドレスを設定する方法 (グラフィック チュートリアル)

1. メニューバーで「編集」→「仮想ネットワーク エディター」を選択して仮想ネットワーク エディタ...

Docker で Maven プロジェクトをより速くビルドする

目次I. 概要2. 従来の多段階イメージ構築3. Buildkitを使用してイメージをビルドする4....

XHTML 入門チュートリアル: シンプルな Web ページの作成

1 分で最初の Web ページを作成します。簡単な Web ページを作ってみましょう。ぜひフォローし...

オーディオマニアにアピールするオーディオビジュアルLinuxディストリビューション

私は最近、多くの音楽に特化した Linux ディストリビューションの 1 つである Audiovis...

CentOS8.0ネットワーク設定の実装

1. CentOS 7 と CentOS 8 のネットワーク構成の違い: VMware Workst...

dig/nslookup コマンドを使用して DNS 解決手順を表示する方法

dig - DNS ルックアップ ユーティリティドメイン名のアクセス障害が発生した場合、ドメイン名の...

MySQL 文字列連結関数 GROUP_CONCAT の詳細な説明

前回の記事では、クロステーブル更新について書きました。自分が書いた SQL を見たとき、自分がバカみ...