1. 程式人生 > >MYSQL中 char 和 varchar

MYSQL中 char 和 varchar

CHAR和VARCHAR型別相似,差別主要在儲存,尾隨空格和檢索方式上。

CHAR和VARCHAR相同的是:CHAR和VARCHAR都指定了字元長度,注意是字元長度。例如char(30) 和 varchar(30)表示都可以存30個字元。有一點要注意的是在utf8mb4編碼中,每個字元佔4個節點。在utf8中,每個字元佔3個位元組。當要儲存的字元超過CHAR/VARCHAR指定的最大長度。在sql mode 沒開啟的時候是截斷要儲存的字串,只儲存前30位

CHAR列中的值是定長的字串。長度可以指定為0到255個字元(例如utf8mb4: 0-255*4個位元組)之間的值當使用CHAR儲存字元時,以CHAR(30)為例,不夠30個字元的以空格向右填充。當檢索CHAR值時,除非啟用sqlmode:PAD_CHAR_TO_FULL-LENGTH SQL模式,否則將刪除尾部空格。

VARCHAR列中的值是可變長度的字串。長度可以指定為0到65535位元組之間的值。VARCHAR的有效最大長度取決於最大行大小(65535位元組,在所有列之間共享)和使用的字符集

與CHAR不同的是,VARCHAR在儲存資料的時候,會額外儲存儲存1-2個位元組(例如varchar(4),這1-2個位元組長度不會算在這4個字元長度裡面,不用擔心被截斷),這1-2個位元組用來記錄資料字元的長度。假如資料字元長度小於等於255,則使用1個位元組記錄資料長度。大於則用兩個位元組。CHAR只儲存資料本身。如下圖所示。

(誤區:varchar在查詢時比char慢是因為會計算varchar的位元組長度(X))

在latin1編碼中,Latin1不能存中文。英文字母為1個位元組。

ValueCHAR(4)Storage RequiredVARCHAR(4)Storage Required
'' '    ' 4 bytes '' 1 byte
'ab' 'ab  ' 4 bytes 'ab' 3 bytes
'abcd' 'abcd' 4 bytes 'abcd' 5 bytes
'abcdefgh' 'abcd' 4 bytes 'abcd' 5 bytes

 

 

 

 

 

 

需要注意的是VARCHAR值在儲存時不填充空格。在儲存和檢索值時,尾部空格將被保留,這與標準SQL一致。而CHAR則相反,CHAR在儲存時會填充空格,在檢索時尾部空格會去掉,無論這個尾部空格是自動填充的還是資料本身的。舉個例子:

mysql> CREATE TABLE vc (v VARCHAR(4), c CHAR(4));
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO vc VALUES ('ab  ', 'ab  ');
Query OK, 1 row affected (0.00 sec)

mysql> SELECT CONCAT('(', v, ')'), CONCAT('(', c, ')') FROM vc;
+---------------------+---------------------+
| CONCAT('(', v, ')') | CONCAT('(', c, ')') |
+---------------------+---------------------+
| (ab  )              | (ab)                |
+---------------------+---------------------+
1 row in set (0.06 sec)


 

 

做三個實驗。

mysql> show create table vc;
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                         |
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------+
| vc    | CREATE TABLE `vc` (
  `v` varchar(4) DEFAULT NULL,
  `c` char(4) DEFAULT NULL,
  UNIQUE KEY `v_UNIQUE` (`v`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 |
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

  

1.查詢語句 where 欄位='       ab';

mysql> SELECT concat('(',v, ')'),concat('(',c, ')') FROM vc where v='               ab';
Empty set (0.00 sec)

mysql> SELECT concat('(',v, ')'),concat('(',c, ')') FROM vc where c='                 ab';
Empty set (0.00 sec)

 

2.查詢語句 where 欄位='ab                 ';

mysql> SELECT concat('(',v, ')'),concat('(',c, ')') FROM vc where v='ab               ';
+--------------------+--------------------+
| concat('(',v, ')') | concat('(',c, ')') |
+--------------------+--------------------+
| (ab )              | (ab)               |
+--------------------+--------------------+
1 row in set (0.00 sec)

mysql> SELECT concat('(',v, ')'),concat('(',c, ')') FROM vc where c='ab               ';
+--------------------+--------------------+
| concat('(',v, ')') | concat('(',c, ')') |
+--------------------+--------------------+
| (ab )              | (ab)               |
+--------------------+--------------------+
1 row in set (0.00 sec)


在所有字串的比較中,不論是varchar,text,char 都會忽略去掉尾部空格,除了like子句,like子句不會去掉尾部空格如下所示

mysql> SELECT concat('(',v, ')'),concat('(',c, ')') FROM vipshop_dba.vc where c like 'ab'; (無尾部空格)
+--------------------+--------------------+
| concat('(',v, ')') | concat('(',c, ')') |
+--------------------+--------------------+
| (ab ) | (ab) |
| ( ab ) | (ab) |
+--------------------+--------------------+
2 rows in set (0.00 sec)

mysql> SELECT concat('(',v, ')'),concat('(',c, ')') FROM vipshop_dba.vc where c like 'ab '; (有尾部空格)
Empty set (0.00 sec)

 

CHAR在儲存時會填充空格,在檢索時尾部空格會去掉,無論這個尾部空格是自動填充的還是資料本身的。這個去掉尾部空格的動作在比較之前會發生

 

mysql> SELECT concat('(',v, ')'),concat('(',c, ')') FROM vipshop_dba.vc where v like 'ab ';   (有尾部空格)
+--------------------+--------------------+
| concat('(',v, ')') | concat('(',c, ')') |
+--------------------+--------------------+
| (ab ) | (ab) |
+--------------------+--------------------+
1 row in set (0.01 sec)

mysql> SELECT concat('(',v, ')'),concat('(',c, ')') FROM vipshop_dba.vc where v like 'ab';   (無尾部空格)
Empty set (0.00 sec)

  

3.varchar 設定unique 索引 觀察  'ab' 和 'ab      '是否同時能存在

mysql> insert into vc (v,c)values('ab     ', 'ab        ')
    -> ;
ERROR 1062 (23000): Duplicate entry 'ab  ' for key 'v_UNIQUE'
mysql> insert into vc (v,c)values(' ab     ', 'ab        ')
    -> ;
Query OK, 1 row affected, 1 warning (0.00 sec)
說明雖然varchar 尾部空格可以保留,但是索引上似乎額外做了限制。如果varchar是唯一索引,插入的值區別只在於尾部空格的數量的話則會報 Duplicate key

  

說到位元組限制這個問題,也想提醒一下。索引長度也是有限制的噢:

innodb引擎的每個索引列長度限制為767位元組(bytes),所有組成索引列的長度和不能大於3072位元組。注意是位元組,varchar(256)在不同的編碼位元組計算不同。例如在utf8mb4中,一個字元佔4個位元組,256個字元=1024個位元組。就達不到索引覆蓋的效果噢。相當於只做了一個字首索引(非常重要,字首索引是需要回(主鍵)表的,二次查詢)

innodb引擎可以通過配置innodb_large_prefix=on(全域性引數,動態生效)來讓單個索引列長度限制上升到3072位元組

  • 在MySQL5.7裡預設 innodb_large_prefix=1 解除了767bytes長度限制,但是單列索引長度最大還是不能超過3072bytes
  • 在MySQL5.6裡預設 innodb_large_prefix=0 限制單列索引長度不能超過767bytes。需要設定innodb_large_prefix=ON、innodb_file_format=barracuda、innodb_file_per_table=ON ,且Innodb表的儲存格式為 DYNAMIC 或 COMPRESSED,則字首索引最多可包含3072個位元組