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)加密在存放。不只效率高,还很保证了数据的安全性。

相关文章
相关标签/搜索