導讀
你真的知道CHAR和VARCHAR類型在存儲和讀取時的區別嗎?
還是先拋幾條結論吧:
1、存儲的時候,CHAR總是會補足空格后再存儲,不管用戶插入數據時尾部有沒有包含空格。
2、存儲的時候,VARCHAR不會先補足空格后再存儲,但如果是用戶在插入時特地加了空格那就會如實存儲,而不會給刪除。
3、讀取數據時,CHAR總是會刪除尾部空格(哪怕是寫入時包含空格)。
4、讀取數據時,VARCHAR總是如實取出之前存入的值(如果存儲時尾部包含空格,就會繼續保留著,不會像CHAR那樣刪除尾部空格)。
下面是測試驗證過程。
1、測試CHAR類型
表結構:
CREATE TABLE `tchar` (
`id` int(10) unsigned NOT NULL DEFAULT '0',
`c1` char(20) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
插入幾條記錄:
insert into tchar values (1, concat('a', repeat(' ',19)));
insert into tchar values (2, concat(' ', repeat('a',19)));
insert into tchar values (3, 'a');
insert into tchar values (4, ' ');
insert into tchar values (5, '');
查看存儲結構:
(1) INFIMUM record offset:99 heapno:0 ...
(2) SUPREMUM record offset:112 heapno:1 ...
(3) normal record offset:126 heapno:2 ... - id=1
(4) normal record offset:169 heapno:3 ... - id=2
(5) normal record offset:212 heapno:4 ... - id=3
(6) normal record offset:255 heapno:5 ... - id=4
(7) normal record offset:298 heapno:6 ... - id=5
看到這坨東西有點懵是不是,還記得我給你們安利過的一個工具不,看這里:innblock | InnoDB page觀察利器。
可以看到,無論我們存儲多長的字符串進去,每條記錄實際都是占用43(169-126=43)字節。由此結論1成立。
簡單說下,43字節的由來:
DB_TRX_ID, 6字節。
DB_ROLL_PTR, 7字節。
id, int, 4字節。
c1, char(20), 20字節;因為是CHAR類型,還需要額外1字節。
每條記錄總是需要額外5字節頭信息(row header)。
這樣總的加起來就是43字節了。
再看下讀取tchar表的結果:
select id,concat('000',c1,'$$$'),length(c1) from tchar ;
+----+----------------------------+------------+
| id | concat('000',c1,'$$$') | length(c1) |
+----+----------------------------+------------+
| 1 | 000a$$$ | 1 | - 刪除尾部空格
| 2 | 000 aaaaaaaaaaaaaaaaaaa$$$ | 20 |
| 3 | 000a$$$ | 1 |
| 4 | 000$$$ | 0 | - 刪除尾部空格,結果和id=5一樣
| 5 | 000$$$ | 0 |
+----+----------------------------+------------+
2、測試VARCHAR類型
表結構:
CREATE TABLE `tvarchar` (
`id` int(10) unsigned NOT NULL DEFAULT '0',
`c1` varchar(20) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
插入幾條記錄:
insert into tvarchar values (1, concat('a', repeat(' ',19)));
insert into tvarchar values (2, concat(' ', repeat('a',19)));
insert into tvarchar values (3, 'a');
insert into tvarchar values (4, ' ');
insert into tvarchar values (5, '');
insert into tvarchar values (6, '');
查看存儲結構:
(1) INFIMUM record offset:99 heapno:0 ...
(2) SUPREMUM record offset:112 heapno:1 ...
(3) normal record offset:126 heapno:2 ... - id=1
(4) normal record offset:169 heapno:3 ... - id=2
(5) normal record offset:212 heapno:4 ... - id=3
(6) normal record offset:236 heapno:5 ... - id=4
(7) normal record offset:260 heapno:6 ... - id=5
(8) normal record offset:283 heapno:7 ... - id=6
可以看到,幾條記錄的字節數分別是:43、43、24、24、23、23(最后一條記錄和id=5那條記錄一樣)。
對上面這個結果有點詫異是不是,尤其是id=1的記錄(插入的是'a…后面19個空格'),居然也要消耗43字節,這就佐證了上面的結論2。
同樣的,id=3和id=4這兩條記錄都是占用24字節,而id=5和id=6這兩條記錄都是占用23字節(沒有額外存儲字符串的字節數,只有id列4個字節)。
再看下讀取tvarchar表的結果:
select id,concat('000',c1,'$$$'),length(c1) from tvarchar;
+----+----------------------------+------------+
| id | concat('000',c1,'$$$') | length(c1) |
+----+----------------------------+------------+
| 1 | 000a $$$ | 20 | - 讀取結果中沒有刪除尾部的空格
| 2 | 000 aaaaaaaaaaaaaaaaaaa$$$ | 20 |
| 3 | 000a$$$ | 1 |
| 4 | 000 $$$ | 1 | - 讀取結果中沒有刪除此空格
| 5 | 000$$$ | 0 |
| 6 | 000$$$ | 0 |
+----+----------------------------+------------+
總的來說,可以總結成兩條結論:
1、從讀取的結果來看,CHAR類型列看起來像是在存儲時把空格給吃了,但實際上只是在讀取時才給吃了(顯示層面上把空格刪除了)。
2、從讀取的結果來看,VARCHAR類型列看起來像是反倒保留了多余的空格,實際上也是只在讀取時才恢復這些空格(但實際物理存儲時還是會刪掉這些空格)。
最后,來看下文檔里怎么說的:
When CHAR values are stored, they are right-padded with spaces to the
specified length. 簡言之,CHAR列在存儲時尾部加空格補齊長度。
When CHAR values are retrieved, trailing spaces are removed unless the
PAD_CHAR_TO_FULL_LENGTH SQL mode is enabled.
簡言之,CHAR列在讀取時會去掉尾部空格,除非設置sql_mode值PAD_CHAR_TO_FULL_LENGTH=1。
VARCHAR values are not padded when they are stored.
簡言之,存VARCHAR時尾部不加空格。
Trailing spaces are retained when values are stored and retrieved, in
conformance with standard SQL. 簡言之,讀取VARCHAR時會顯示空格。
以上測試使用的版本及環境:
mysql> select version()\G
...
version(): 8.0.15
mysql> select @@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 The CHAR and VARCHAR Types,https://dev.mysql.com/doc/refman/5.7/en/char.html
以上就是MySQL CHAR和VARCHAR存儲的差別的詳細內容,更多關于MySQL CHAR和VARCHAR的資料請關注腳本之家其它相關文章!
您可能感興趣的文章:- 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的區別