MySQL CHAR和VARCHAR那些事

咱們知道CHAR(M)VARCHAR(M)的區別就是VARCHAR(M)是變長的字符串,而CHAR(M)是定長的字符串。咱們暫時先不考慮變長和定長的問題,咱們先來看一看CHAR(M)VARCHAR(M)中的M表明的是什麼意思。sql

oracleCHAR(M)VARCHAR(M)中的M表明的是字節數就是這個列佔用的最大字節數。而在MySQLCHAR(M)VARCHAR(M)中的M表明的是這個列佔用的最大字符數。這是什麼意思呢?下面咱們在MySQL中建立一張表來測試一下就明白了。安全

DROP TABLE IF EXISTS `char_test`;
CREATE TABLE `char_test` (
  `ch` char(4) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

char_test表很是簡單,只有一個字段ch,他的類型是CAHR(4),用的是utf-8編碼,接下來在char_test表中插入三行數據。oracle

1:正常插入數據函數

咱們用MySQL提供給咱們的函數length(str),char_length(str),來查看錶char_test中的ch字段的字節數和字符數以下:性能

2:字節數和字符數學習

由於是用utf-8編碼,utf-8編碼中一個英文字符佔用1個字節,一個漢字佔用3個字節。因此咱們看到hi佔用的是2個字節,2個字符。很是高興佔用了12個字節,4給字符。因此咱們能夠知道CHAR(M)中的M是表示最大佔用的字符數。以下圖3面咱們來試一試插入多一點字符的狀況。測試

3:非正常插入編碼

您好tim總共有5個字符,插入就出錯了,這是在STRICT_TRANS_TABLES模式下,直接報錯了。加密

VARCHAR(M)CHAR(M)的狀況同樣,M也是表示最大的字符數。只是和不少資料上的狀況不同的是VARCHAR(M)中的M取值範圍並非固定的0~65535,而是根據編碼不一樣有所不一樣。spa

4:使用ascii編碼

5:使用默認的utf-8編碼

如上圖45所示,當使用ascii編碼的時候,M的取值是0~65535,當使用utf-8編碼是時候M的取值範圍是0~21845

6VARCHAR(M)官方文檔

由於MySQL的官方文檔對於VARCHAR的介紹是最大是65535給字節,而utf-8佔用的是1~6個字節。而21845*3 = 65535,因此咱們也只能猜想在中文環境中MySQL只支持佔用3個字節的漢字,由於漢字大多數佔3個字節。這樣就算是21845個字符所有是漢子都恰好佔用65535個字節。

接下來的事情就是,考慮定長和變長的事了。這其實和功能沒有太大的關係了,主要是存儲和使用效率有關了。

CHAR(M)是定長的,顧名思義就是長度是固定的,這裏的長度是指底層存儲空間的字節數。例如CHAR(4),根據編碼不一樣MySQLCHAR(4)分配的就是固定的字節數的存儲空間,無論你放‘hi’仍是‘很是高興’,底層都是佔用4個字符所佔用的字節。不夠怎麼辦?不要緊,填充空格。至於查詢的時候只要不是PAD_CHAR_TO_FULL_LENGTH模式下,就會把CHAR(M)類型末尾的空格去掉。

VARCHAR(M)是變長的,顧名思義就是長度是可變的,例如:VARCHAR(4),雖然最大的字符數是4可是我若是隻存放一個hi,底層就只佔用2個字符所佔用的字節。

那麼問題來了,咱們該怎樣選擇CHAR(M)VARCHAR(M)呢?這實際上是一個比較複雜的問題,考慮到不一樣的場景和不一樣的存儲引擎,選擇是不一樣的。

若是您對性能沒有什麼要求,而且也不太想花時間去分析思考這些數據的應用場景,數據的查詢和索引效率等的關係,那麼直接用VARCHAR(M)吧。

若是您對性能有要求,那麼您就能夠考慮一下是否對數據進行一些約束,限制一下數據的長度,作一下合理的轉換,特別是對一些常常索引和查詢的數據。例如:有一張用戶表,包含nameaddressphonepassword等屬性。也許就能夠把name設置成CHAR類型的由於name顯然是常常查詢的字段,而且長度比較固定。姓名嘛,通常就是2-4個字符嘛,就算設置大一點,也算是用空間換時間,address看具體的狀況,phone沒什麼說的固定的CHAR(11)一點都不浪費,不要爲了怕出錯弄一個CHAR(20)這樣的類型,由於手機號碼有很是明顯的數據約束,就算是錯誤,也是客戶端的錯誤。至於password徹底能夠考慮學習一下MySQL的作法,直接弄一個CHAR(40),而後用sha1(password)加密在存放。不只效率高,還很保證了數據的安全性。

相關文章
相關標籤/搜索