mysql中 char 和 varchar 的區(qū)別解析
這是一個在 MySQL 面試和日常開發(fā)中非常經(jīng)典的問題。CHAR 和 VARCHAR 是兩種最常用的字符串數(shù)據(jù)類型,它們的核心區(qū)別在于存儲和檢索的方式。
下面我將從多個維度詳細解釋它們的區(qū)別,并給出選擇建議。
核心區(qū)別總結
| 特性 | CHAR | VARCHAR |
|---|---|---|
| 長度處理 | 固定長度 | 可變長度 |
| 存儲方式 | 分配定義的全部空間,不足部分用空格填充 | 只存儲實際字符數(shù)(+1或+2字節(jié)存儲長度信息) |
| 存儲空間 | 固定,為聲明的長度 | 可變,為實際字符串長度 + 長度前綴 |
| 尾部空格 | 檢索時會自動刪除 | 檢索時會保留 |
| 讀取速度 | 較快(固定長度,無需計算) | 稍慢(需要根據(jù)長度信息讀?。?/td> |
| 適用場景 | 長度固定或近乎固定的數(shù)據(jù)(如MD5、UUID、狀態(tài)碼) | 長度變化較大的數(shù)據(jù)(如姓名、地址、描述) |
詳細解釋
1. 存儲方式與空間占用
CHAR(n):- 你聲明一個
CHAR(10)的列,無論你存入"hi"(2字符)還是"hello"(5字符),MySQL 都會在磁盤上分配并占用 10 個字符的空間。 - 如果存入的字符串長度不足,MySQL 會在其右側用空格填充到指定長度。
- 例如,存儲
"A"到CHAR(4)列,實際存儲的是"A "。
- 你聲明一個
VARCHAR(n):- 你聲明一個
VARCHAR(10)的列,存入"hi"大約占用 3 個字節(jié)(2個字符 + 1字節(jié)的長度前綴),存入"hello"大約占用 6 個字節(jié)(5個字符 + 1字節(jié)的長度前綴)。 VARCHAR需要使用額外的 1 或 2 個字節(jié)來存儲“字符串的長度”這個信息。- 如果聲明的最大長度
n<= 255,則使用 1 個字節(jié) 作為長度前綴。 - 如果聲明的最大長度
n> 255,則使用 2 個字節(jié) 作為長度前綴。
- 如果聲明的最大長度
- 你聲明一個
- 它只存儲實際的字符串內(nèi)容,不會用空格填充。
2. 尾部空格的處理(關鍵行為差異)
這是另一個非常重要的區(qū)別,尤其是在進行字符串比較時。
CHAR:在檢索(SELECT)時會自動移除存儲時填充的尾部空格。
-- 假設有一個 CHAR(5) 的列
INSERT INTO table (char_column) VALUES ('abc '); -- 存儲為 'abc '
SELECT char_column, LENGTH(char_column) FROM table;
-- 檢索結果:'abc',長度為 3(尾部空格被移除)VARCHAR:在檢索時會保留尾部空格。
-- 假設有一個 VARCHAR(5) 的列
INSERT INTO table (varchar_column) VALUES ('abc '); -- 存儲 'abc ' 及其長度信息
SELECT varchar_column, LENGTH(varchar_column) FROM table;
-- 檢索結果:'abc ',長度為 5(尾部空格被保留)注意:由于
CHAR的這種行為,當使用=比較時:
'abc '(CHAR)和'abc'(CHAR)是相等的;
'abc '(CHAR)和'abc'(VARCHAR)是相等的;
'abc '(VARCHAR)和'abc'(VARCHAR)是不相等的。
3. 性能考量
CHAR:- 優(yōu)點:由于長度固定,在磁盤上的記錄也是定長的,所以讀寫速度通常更快。MySQL 可以很容易地計算出第 N 條記錄的位置,尤其是在 MyISAM 這種存儲引擎中,對于全表掃描或頻繁更新的場景有優(yōu)勢。
- 缺點:可能會浪費存儲空間,尤其是當存儲的數(shù)據(jù)長度遠小于定義長度時。
VARCHAR:- 優(yōu)點:節(jié)省存儲空間。
- 缺點:由于記錄長度可變,更新數(shù)據(jù)可能會導致行的大小發(fā)生變化,從而可能引發(fā)頁分裂(對于 InnoDB),影響一點性能。此外,讀取時需要先讀取長度信息,再讀取具體數(shù)據(jù),過程稍復雜。
如何選擇?
請根據(jù)你的業(yè)務場景來決定:
- 使用
CHAR的情況:- 存儲的字符串長度非常固定或變化極小。
- 經(jīng)典例子:
- MD5/SHA1 哈希值(長度固定,如 MD5 總是 32字符)
- UUID(雖然可以用
CHAR(36),但現(xiàn)在更推薦存儲為二進制或使用UUID_SHORT()) - 國家代碼(如
CHAR(2)用于 'US', 'CN') - 定長的狀態(tài)碼或標志位(如
CHAR(1)用于 'Y'/‘N’)
- 避免使用CHAR的情況:
- 需要精確保留字符串的原始格式(包括尾部空格)
- 使用
VARCHAR的情況:- 存儲的字符串長度變化很大。
一個簡單的例子
CREATE TABLE test_string (
id INT PRIMARY KEY,
fixed_char CHAR(5),
variable_varchar VARCHAR(5)
);
INSERT INTO test_string (id, fixed_char, variable_varchar) VALUES
(1, 'A', 'A'), -- CHAR存儲 'A ', VARCHAR存儲 'A'
(2, 'ABCDE', 'ABCDE'); -- 兩者都存滿
-- 查詢并顯示長度
SELECT
fixed_char,
LENGTH(fixed_char) as char_length,
variable_varchar,
LENGTH(variable_varchar) as varchar_length
FROM test_string;結果可能如下:
| fixed_char | char_length | variable_varchar | varchar_length |
|---|---|---|---|
| A | 1 | A | 1 |
| ABCDE | 5 | ABCDE | 5 |
總結
- 追求空間效率,數(shù)據(jù)長度多變 -> 選擇
VARCHAR。這是絕大多數(shù)場景下的選擇。 - 追求極致性能,數(shù)據(jù)長度固定 -> 選擇
CHAR。 - 深刻理解
CHAR會剔除檢索結果的尾部空格 這一點,可以避免很多意想不到的查詢 Bug。
在現(xiàn)代 MySQL 版本和 InnoDB 存儲引擎下,對于大多數(shù)通用場景,VARCHAR 因其靈活性而更受歡迎。除非你非常確定某個字段的長度是絕對固定的,否則從 VARCHAR 開始通常是一個安全的選擇。
到此這篇關于mysql中 char 和 varchar 的區(qū)別的文章就介紹到這了,更多相關mysql char 和 varchar區(qū)別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
mysql觸發(fā)器實現(xiàn)oracle物化視圖示例代碼
mysql觸發(fā)器實現(xiàn)oracle物化視圖即不是基于基表的虛表,而是根據(jù)表實際存在的實表,需要的朋友可以參考下2014-02-02
MySQL?數(shù)據(jù)庫如何實現(xiàn)存儲時間
這篇文章主要介紹了MySQL?數(shù)據(jù)庫如何實現(xiàn)存儲時間,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03
MySQL 自動備份與數(shù)據(jù)庫被破壞后的恢復方法
當數(shù)據(jù)庫服務器建立好以后,我們首先要做的不是考慮要在這個支持數(shù)據(jù)庫的服務器運行哪些受MySQL提攜的程序,而是當數(shù)據(jù)庫遭到破壞后,怎樣安然恢復到最后一次正常的狀態(tài),使得數(shù)據(jù)的損失達到最小。2010-03-03
MySQL 5.0.96 for Windows x86 32位綠色精簡版安裝教程
這篇文章主要介紹了MySQL 5.0.96 for Windows x86 32位綠色精簡版安裝教程,需要的朋友可以參考下2017-10-10
mysql中插入表數(shù)據(jù)中文亂碼問題的解決方法
mysql是我們項目中非經(jīng)常常使用的數(shù)據(jù)型數(shù)據(jù)庫,下面這篇文章主要給大家介紹了關于mysql中插入表數(shù)據(jù)中文亂碼問題的解決方法,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面隨著小編來一起學習學習吧2018-09-09

