CHAR和VARCHAR類型在存儲和檢索方式上有相似之處,但在最大長度以及是否保留尾隨空格方面存在差異。
一、存儲方面
1、存儲對比
CHAR和VARCHAR類型的聲明包含一個長度,表示要存儲的最大字符數。例如,CHAR(30)可以容納最多30個字符。
CHAR列的長度在創建表時被固定為您聲明的長度。長度可以是從0到255的任何值。當存儲CHAR值時,它們會被右填充到指定的長度。當檢索CHAR值時,除非啟用了PAD_CHAR_TO_FULL_LENGTH SQL模式(默認沒啟用),否則會刪除尾隨空格。
VARCHAR列中的值是可變長度字符串。長度可以指定為0到65,535的值。VARCHAR的有效最大長度取決于最大行大小(65,535字節,這個大小被所有列共享)和所使用的字符集。
2、具體對比
假設當前一個表里包含類型為char(4)及varchar(4)的列(假設該列使用單字節字符集如latin1),則,存儲所需的大小對比如下:
注:
- 如果字符集為其他類型(utf8mb4),則根據存儲的內容進行換算即可
- 上例中為了演示,非嚴格模式時可以截斷存儲
二、顯示及檢索對比
本文后續案例是在utf8的字符集的實例上進行演示的
1、默認SQL模式
默認沒開啟PAD_CHAR_TO_FULL_LENGTH SQL模式的情況下,char及varchar的顯示幾乎沒有區別,例如:
MySQL> create table tb_char (id int primary key auto_increment, c_char char(10),c_varchar varchar(10));
Query OK, 0 rows affected (0.01 sec)
mysql> insert into tb_char (c_char,c_varchar) values ('a','a'),('張三','張三'),('tc一','tc一');
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
查詢顯示如下:
mysql> select * from tb_char;
+----+--------+-----------+
| id | c_char | c_varchar |
+----+--------+-----------+
| 1 | a | a |
| 2 | 張三 | 張三 |
| 3 | tc一 | tc一 |
+----+--------+-----------+
3 rows in set (0.00 sec)
查看長度如下:
mysql> select c_char,c_varchar, length(c_char)len_char,length(c_varchar)len_varchar,char_length(c_char),char_length(c_varchar) from tb_char;
+--------+-----------+----------+-------------+---------------------+------------------------+
| c_char | c_varchar | len_char | len_varchar | char_length(c_char) | char_length(c_varchar) |
+--------+-----------+----------+-------------+---------------------+------------------------+
| a | a | 1 | 1 | 1 | 1 |
| 張三 | 張三 | 6 | 6 | 2 | 2 |
| tc一 | tc一 | 5 | 5 | 3 | 3 |
+--------+-----------+----------+-------------+---------------------+------------------------+
3 rows in set (0.00 sec)
從顯示結果來看,char與varchar在此時看上去是一致的,即:查詢時,char類型的數據會將末尾空格去除。
此時,如果寫入末尾帶空格的值,則結果會如何呢?
mysql> insert into tb_char (c_char,c_varchar) values ('abc ','abc ');
Query OK, 1 row affected (0.01 sec)
mysql> select * from tb_char;
+----+--------+-----------+
| id | c_char | c_varchar |
+----+--------+-----------+
| 1 | a | a |
| 2 | 張三 | 張三 |
| 3 | tc一 | tc一 |
| 4 | abc | abc |
+----+--------+-----------+
4 rows in set (0.00 sec)
mysql> select c_char,c_varchar, length(c_char)len_char,length(c_varchar)len_varchar,char_length(c_char),char_length(c_varchar) from tb_char;
+--------+-----------+----------+-------------+---------------------+------------------------+
| c_char | c_varchar | len_char | len_varchar | char_length(c_char) | char_length(c_varchar) |
+--------+-----------+----------+-------------+---------------------+------------------------+
| a | a | 1 | 1 | 1 | 1 |
| 張三 | 張三 | 6 | 6 | 2 | 2 |
| tc一 | tc一 | 5 | 5 | 3 | 3 |
| abc | abc | 3 | 4 | 3 | 4 |
+--------+-----------+----------+-------------+---------------------+------------------------+
4 rows in set (0.00 sec)
此時,結果出現了不同,char類型的顯示依舊將末尾空格去除,而varchar則原樣顯示
如果此時按條件查詢‘abc’及‘abc ’,結果會如何?
mysql> select * from tb_char where c_char ='abc';
+----+--------+-----------+
| id | c_char | c_varchar |
+----+--------+-----------+
| 4 | abc | abc |
+----+--------+-----------+
1 row in set (0.00 sec)
mysql> select * from tb_char where c_varchar ='abc';
+----+--------+-----------+
| id | c_char | c_varchar |
+----+--------+-----------+
| 4 | abc | abc |
+----+--------+-----------+
1 row in set (0.00 sec)
mysql> select * from tb_char where c_char ='abc ';
+----+--------+-----------+
| id | c_char | c_varchar |
+----+--------+-----------+
| 4 | abc | abc |
+----+--------+-----------+
1 row in set (0.00 sec)
mysql> select * from tb_char where c_varchar ='abc ';
+----+--------+-----------+
| id | c_char | c_varchar |
+----+--------+-----------+
| 4 | abc | abc |
+----+--------+-----------+
1 row in set (0.00 sec)
結果是都可以顯示。
不過,如果做了concat操作,結果如下:
mysql> select c_char,c_varchar,concat(c_char,'concat'),concat(c_varchar,'concat') from tb_char;
+--------+-----------+-------------------------+----------------------------+
| c_char | c_varchar | concat(c_char,'concat') | concat(c_varchar,'concat') |
+--------+-----------+-------------------------+----------------------------+
| a | a | aconcat | aconcat |
| 張三 | 張三 | 張三concat | 張三concat |
| tc一 | tc一 | tc一concat | tc一concat |
| abc | abc | abcconcat | abc concat |
+--------+-----------+-------------------------+----------------------------+
2、PAD_CHAR_TO_FULL_LENGTH 模式
將SQL模式改為PAD_CHAR_TO_FULL_LENGTH后,再對比看一下。
mysql> set sql_mode = 'PAD_CHAR_TO_FULL_LENGTH';
Query OK, 0 rows affected (0.00 sec)
mysql> select * from tb_char;
+----+----------------+-----------+
| id | c_char | c_varchar |
+----+----------------+-----------+
| 1 | a | a |
| 2 | 張三 | 張三 |
| 3 | tc一 | tc一 |
| 4 | abc | abc |
+----+----------------+-----------+
4 rows in set (0.00 sec)
mysql> select c_char,c_varchar, length(c_char)len_char,length(c_varchar)len_varchar,char_length(c_char),char_length(c_varchar) from tb_char;
+----------------+-----------+----------+-------------+---------------------+------------------------+
| c_char | c_varchar | len_char | len_varchar | char_length(c_char) | char_length(c_varchar) |
+----------------+-----------+----------+-------------+---------------------+------------------------+
| a | a | 10 | 1 | 10 | 1 |
| 張三 | 張三 | 14 | 6 | 10 | 2 |
| tc一 | tc一 | 12 | 5 | 10 | 3 |
| abc | abc | 10 | 4 | 10 | 4 |
+----------------+-----------+----------+-------------+---------------------+------------------------+
4 rows in set (0.00 sec)
此時使用concat,結果如下:
mysql> select c_char,c_varchar,concat(c_char,'concat'),concat(c_varchar,'concat') from tb_char;
+----------------+-----------+-------------------------+----------------------------+
| c_char | c_varchar | concat(c_char,'concat') | concat(c_varchar,'concat') |
+----------------+-----------+-------------------------+----------------------------+
| a | a | a concat | aconcat |
| 張三 | 張三 | 張三 concat | 張三concat |
| tc一 | tc一 | tc一 concat | tc一concat |
| abc | abc | abc concat | abc concat |
+----------------+-----------+-------------------------+----------------------------+
4 rows in set (0.00 sec)
可見,此時char類型每一行的末尾都已經填充了空格。
使用‘abc’及‘abc ’查看結果:
mysql> select * from tb_char where c_char ='abc';
+----+------------+-----------+
| id | c_char | c_varchar |
+----+------------+-----------+
| 4 | abc | abc |
+----+------------+-----------+
1 row in set (0.00 sec)
mysql> select * from tb_char where c_varchar ='abc';
+----+------------+-----------+
| id | c_char | c_varchar |
+----+------------+-----------+
| 4 | abc | abc |
+----+------------+-----------+
1 row in set (0.00 sec)
mysql> select * from tb_char where c_char ='abc ';
+----+------------+-----------+
| id | c_char | c_varchar |
+----+------------+-----------+
| 4 | abc | abc |
+----+------------+-----------+
1 row in set (0.00 sec)
mysql> select * from tb_char where c_varchar ='abc ';
+----+------------+-----------+
| id | c_char | c_varchar |
+----+------------+-----------+
| 4 | abc | abc |
+----+------------+-----------+
1 row in set (0.00 sec)
mysql> select * from tb_char where c_char ='abc ';
+----+------------+-----------+
| id | c_char | c_varchar |
+----+------------+-----------+
| 4 | abc | abc |
+----+------------+-----------+
1 row in set (0.00 sec)
該結果是沒有區別的。
三、字符串長度查看函數
在MySQL中,字符串計算函數有如下幾種,在使用是注意區分。
1、LENGTH 函數
用于返回字符串的字節數。對于英文字符,一個字符占用一個字節;而對于一些多字節字符(如UTF-8編碼的中文字符),一個字符可能占用多個字節。
SELECT LENGTH('Hello'); -- 返回 5
SELECT LENGTH('你好'); -- 返回 6(UTF-8編碼中文字符占用3個字節)
2、CHAR_LENGTH 函數
用于返回字符串的字符數,而不是字節數。這意味著它會考慮字符的多字節性,確保正確地計算字符的數量。
SELECT CHAR_LENGTH('Hello'); -- 返回 5
SELECT CHAR_LENGTH('你好'); -- 返回 2(兩個中文字符)
3、CHARACTER_LENGTH 函數
與 CHAR_LENGTH 函數功能相似,也用于返回字符串的字符數。
SELECT CHARACTER_LENGTH('Hello'); -- 返回 5
SELECT CHARACTER_LENGTH('你好'); -- 返回 2
4、BIT_LENGTH 函數
返回字符串的位數,而不是字節數或字符數。
SELECT BIT_LENGTH('Hello'); -- 返回 40(5個英文字符,每個字符8位)
SELECT BIT_LENGTH('你好'); -- 返回 48(2個中文字符,每個字符24位)
四、結語
了解CHAR和VARCHAR類型的差異對于有效地設計和管理MySQL數據庫極為重要。選擇合適的數據類型和了解它們的行為有助于避免意外的數據處理問題。同時,開發人員應根據具體需求和預期行為來選擇合適的數據類型,以確保數據存儲和檢索的一致性和準確性。