varchar和char是兩種最主要的字元串類型。
這些值在磁盤和記憶體中如何存儲,要根據存儲引擎的具體實作。
存儲引擎存儲char或者varchar值的方式在記憶體中和磁盤上可能不一樣。
varchar用于存儲可變長字元串。它比定長類型更節省空間。有一種例外,如果是用了row_format=fixed建立,那麼每一行都會使用定長存儲。
varchar需要使用1或2個額外位元組記錄字元串長度,如果列的最大長度小于或等于255位元組,使用1個位元組表示,否則使用2個位元組表示。
因為行是變長的,在update時可能使行變得比原來更長,這就導緻需要額外的工作。
如果一行占用的空間增長,并且在頁内沒有更多的空間可以存儲,在這種情況下,不同存儲引擎的處理方式是不一樣的。
MyISAM會将行拆成不同的片段處理,InnoDB則需要分裂頁來使行可以放進頁内。
varchar大緻适合下列的情況:
a.字元串的列最大長度比平均長度大很多
b.列更新的很少(是以碎片不是問題)
c.使用了複雜的字元集(例如UTF-8),每個字元都使用不同的位元組數進行存儲
MySQL 5.0或更高版本,存儲和檢索時會保留末尾空格。早期版本會剔除末尾空格。InnoDB則更靈活,它可以把過長的varchar存儲為BLOB。
char類型是定長的。
當存儲char值時,MySQL會剔除所有的末尾空格。char值會根據需要采用空格進行填充以友善比較。
char适合存儲很短的字元串,或者所有值都接近同一個長度。例如char非常适合存儲密碼的md5值。
對于經常變更的資料,char也比varchar更好,定長的char類型不容易産生碎片。
對于非常短的列,char比varchar在存儲空間上也更有效率。比如char(1)隻需要1個位元組,而varchar(1)則需要2個位元組。
與char和varchar類似的還有binary和varbinary,他們存儲的是二進制字元串。隻不過二進制字元串存儲的是位元組碼而不是字元。填充也不一樣:MySQL填充binary采用的是\0(零位元組)而不是空格,檢索時也不會去掉填充
當希望使用位元組碼而不是字元進行比較時,這些類型非常有用。比較binary字元串時,每次按一個位元組,并且根據位元組的數值進行比較。
二進制比較字元比較簡單,更快。
blob和text都是為存儲很大的資料而設計的字元串資料類型,分别采用二進制和字元方式存儲。
他們分别屬于兩組不同的資料類型家族:
字元類型包括tinytext,smalltext,text,mediumtext,longtext
二進制類型包括tinyblob,smallblob,blob,mediumblob,longblob
MySQL把每一個blob和text值當做一個獨立的對象處理。當值太大時,innoDB會使用專門的外部存儲區域存儲實際的值。
blob和text家族之間僅有的不同是blob類型處處的是 二進制資料,沒有排序規則或字元集,而text類型有字元集和排序規則。
MySQL對blob和text列進行排序與其他類型不同:它隻對每列的最前max_sort_length位元組而不是整個字元串做排序。如果隻需要排序前面一小部分,則可以縮減max_sort_length的配置活着使用order by substring(column,lenth)。
枚舉(enum)
有時候可以使用枚舉列代替常用的字元串。
枚舉列可以把一些不重複的字元串存儲成一個預定義的集合。枚舉在存儲時非常緊湊,會根絕清單值得數量壓縮到1個或者2個位元組中。MySQL在内部将每個值在清單中的位置儲存為整數,并在表的.frm檔案中儲存“數字-字元串”映射關系的查找表。
如果一個表中的字段e是枚舉類型(有三個值,a,b,c),表内插入該字段值分别是a,b,c三條記錄
查詢如下:select e+0 from test;
查詢結果:
+---------+
| e + 0 |
| 1 |
| 3 |
| 2 |
+---------+
如果使用數字作為enum枚舉常量,這種雙重性很容易導緻混亂,例如enum('1','2','3'),建議避免。
查詢如下:select e from test;
查詢結果:
+---------+
| e |
| a |
| b |
| c |
+---------+
一種繞過這種現實的方式是按照需要的順序來定義枚舉列。也可以在查詢中使用field()函數現實的指定排序順序,但這回導緻無法利用索引消除排序。
select e from text order by field(e,'a','b','c')
枚舉最不好的地方是,字元串清單是固定的,添加或者删除字元串必須使用alter table。
對于一些列未來可能會改變的字元串,使用枚舉不太好,除非能接受在清單末尾添加元素,這樣就可以不用重建整個表來完成修改。
因為枚舉值儲存為整數,并且必須進行查找才能轉換為字元串,是以枚舉列有一些開銷。通常枚舉列都比較小,是以開銷還可以控制。
特殊情況,char和varchar與枚舉列關聯可能比直接跟char或varchar關聯還要慢。