天天看點

MySQL資料類型之字元串(char和varchar)

    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關聯還要慢。

繼續閱讀