字符串char vchar性能对比补充

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

 

 1 #官网:https://dev.mysql.com/doc/refman/5.7/en/char.html
 2 #注意:char和varchar括号内的参数指的都是字符的长度
 3 
 4 #char类型:定长,简单粗暴,浪费空间,存取速度快
 5     字符长度范围:0-255(一个中文是一个字符,是utf8编码的3个字节)
 6     存储:
 7         存储char类型的值时,会往右填充空格来满足长度
 8         例如:指定长度为10,存>10个字符则报错(严格模式下),存<10个字符则用空格填充直到凑够10个字符存储
 9 
10     检索:
11         在检索或者说查询时,查出的结果会自动删除尾部的空格,如果你想看到它补全空格之后的内容,除非我们打开pad_char_to_full_length SQL模式(SET sql_mode = 'strict_trans_tables,PAD_CHAR_TO_FULL_LENGTH';)
12 
13 #varchar类型:变长,精准,节省空间,存取速度慢
14     字符长度范围:0-65535(如果大于21845会提示用其他类型 。mysql行最大限制为65535字节,字符编码为utf-8:https://dev.mysql.com/doc/refman/5.7/en/column-count-limit.html)
15     存储:
16         varchar类型存储数据的真实内容,不会用空格填充,如果'ab  ',尾部的空格也会被存起来
17         强调:varchar类型会在真实数据前加1-2Bytes的前缀,该前缀用来表示真实数据的bytes字节数(1-2Bytes最大表示65535个数字,正好符合mysql对row的最大字节限制,即已经足够使用)
18         如果真实的数据<255bytes则需要1Bytes的前缀(1Bytes=8bit 2**8最大表示的数字为255)
19         如果真实的数据>255bytes则需要2Bytes的前缀(2Bytes=16bit 2**16最大表示的数字为65535)
20     
21     检索:
22         尾部有空格会保存下来,在检索或者说查询时,也会正常显示包含空格在内的内容
23 
24 char和varchar的介绍
char和varchar详细介绍

 

创建一个t1表,包含一个char类型的字段 

创建一个t1表,包含一个char类型的字段
create table t1(id int,name char(4));
            超过长度:
                严格模式下(报错):
                    mysql> insert into t1 values('xiaoshabi');
                    ERROR 1406 (22001): Data too long for column 'name' at row 1
                非严格模式下(警告):
                    mysql> set sql_mode='NO_ENGINE_SUBSTITUTION';
                    Query OK, 0 rows affected (0.00 sec)

                    mysql> create table t1(id int,name char(4));
                    Query OK, 0 rows affected (0.40 sec)

                    mysql> insert into t2 values('xiaoshabi');
                    Query OK, 1 row affected, 1 warning (0.11 sec)
                    查看一下结果:
                    mysql> select * from t1;
                    +------+------+
                    | id   | name |
                    +------+------+
                    |    1 | xiao | #只有一个xiao
                    +------+------+
row in set (0.00 sec)
                varchar类型和上面的效果是一样的,严格模式下也会报错。
            
            如果没有超过长度,那么char类型时mysql会使用空格来补全自己规定的char(4)的4个字符,varchar不会,我们来做个对比
            例如:
                #再创建一个含有varchar类型的表t2
                然后插入几条和t1里面相同的数据
                mysql>insert into t1 values(2,'a'),(3,'bb'),(4,'ccc'),(5,'d');
                
                mysql>create table t2(id int,name varchar(4));
                
                mysql> insert into t2 values(1,'xiao'),(2,'a'),(3,'bb'),(4,'ccc'),(5,'d');
                查看一下t1表和t2表的内容
                mysql> select * from t1;
                +------+------+
                | id   | name |
                +------+------+
                |    1 | xiao |
                |    2 | a    |
                |    3 | bb   |
                |    4 | ccc  |
                |    5 | d    |
                +------+------+
rows in set (0.00 sec)

                mysql> select * from t2;
                +------+------+
                | id   | name |
                +------+------+
                |    1 | xiao |
                |    2 | a    |
                |    3 | bb   |
                |    4 | ccc  |
                |    5 | d    |
                +------+------+
rows in set (0.00 sec)
                
            好,两个表里面数据是一样的,每一项的数据长度也是一样的,那么我们来验证一下char的自动空格在后面补全的存储方式和varchar的不同
            
            通过mysql提供的一个char_length()方法来查看一下所有数据的长度
            mysql> select char_length(name) from t1;
            +-------------------+
            | char_length(name) |
            +-------------------+
            |                 4 |
            |                 1 |
            |                 2 |
            |                 3 |
            |                 1 |
            +-------------------+
rows in set (0.00 sec)
            
            mysql> select char_length(name) from t2;
            +-------------------+
            | char_length(name) |
            +-------------------+
            |                 4 |
            |                 1 |
            |                 2 |
            |                 3 |
            |                 1 |
            +-------------------+
rows in set (0.00 sec)
            通过查看结果可以看到,两者显示的数据长度是一样的,不是说好的char会补全吗,我设置的字段是char(4),那么长度应该都是4才对啊?这是因为mysql在你查询的时候自动帮你把结果里面的空格去掉了,如果我们想看到它存储数据的真实长度,需要设置mysql的模式,通过一个叫做PAD_CHAR_TO_FULL_LENGTH的模式,就可以看到了,所以我们把这个模式加到sql_mode里面:
                mysql> set sql_mode='PAD_CHAR_TO_FULL_LENGTH';
                Query OK, 0 rows affected (0.00 sec)
                
                然后我们在查看一下t1和t2数据的长度:
                mysql> select char_length(name) from t1;
                +-------------------+
                | char_length(name) |
                +-------------------+
                |                 4 |
                |                 4 |
                |                 4 |
                |                 4 |
                |                 4 |
                +-------------------+
rows in set (0.00 sec)
                
                mysql> select char_length(name) from t2;
                +-------------------+
                | char_length(name) |
                +-------------------+
                |                 4 |
                |                 1 |
                |                 2 |
                |                 3 |
                |                 1 |
                +-------------------+
rows in set (0.00 sec)
                通过结果可以看到,char类型的数据长度都是4,这下看到了两者的不同了吧,至于为什么mysql会这样搞,我们后面有解释的,先看现象就可以啦。
                
            现在我们再来看一个问题,就是当你设置的类型为char的时候,我们通过where条件来查询的时候会有一个什么现象:
                mysql> select * from t1 where name='a';
                +------+------+
                | id   | name |
                +------+------+
                |    2 | a    |
                +------+------+
row in set (0.00 sec)
            ok,结果没问题,我们在where后面的a后面加一下空格再来试试:
                mysql> select * from t1 where name='a ';
                +------+------+
                | id   | name |
                +------+------+
                |    2 | a    |
                +------+------+
row in set (0.00 sec)
            ok,能查到,再多加一些空格试试,加6个空格,超过了设置的char(4)的4:
                mysql> select * from t1 where name='a      ';
                +------+------+
                | id   | name |
                +------+------+
                |    2 | a    |
                +------+------+
row in set (0.00 sec)
            ok,也是没问题的
            总结:通过>,=,>=,<,<=作为where的查询条件的时候,char类型字段的查询是没问题的。
            但是,当我们将where后面的比较符号改为like的时候,(like是模糊匹配的意思,我们前面见过,show variables like '%char%';来查看mysql字符集的时候用过)
                其中%的意思是匹配任意字符(0到多个字符都可以匹配到),还有一个符号是_(匹配1个字符),这两个字符其实就像我们学的正则匹配里面的通配符,那么我们通过这些符号进行一下模糊查询,看一下,char类型进行模糊匹配的时候,是否还能行,看例子:
                mysql> select * from t1 where name like 'a';
                Empty set (0.00 sec)
                发现啥也没查到,因为char存储的数据是4个字符长度的,不满4个是以空格来补全的,你在like后面就只写了一个'a',是无法查到的。
                我们试一下上面的通配符来查询:
                mysql> select * from t1 where name like 'a%';
                +------+------+
                | id   | name |
                +------+------+
                |    2 | a    |
                +------+------+
row in set (0.00 sec)
                这样就能看到查询结果了
                
                试一下_是不是匹配1个字符:
                mysql> select * from t1 where name like 'a_';
                Empty set (0.00 sec)
                发现一个_果然不行,我们试试三个_。
                mysql> select * from t1 where name like 'a___';
                +------+------+
                | id   | name |
                +------+------+
                |    2 | a    |
                +------+------+
row in set (0.00 sec)
                发现果然能行,一个_最多匹配1个任意字符。
                如果多写了几个_呢?
                mysql> select * from t1 where name like 'a_____';
                Empty set (0.00 sec)
                查不到结果,说明_匹配的是1个字符,但不是0-1个字符。

char和varchar测试
char和varchar测试

测试

测试结果总结:
  针对char类型,mysql在存储的时候会将不足规定长度的数据使用后面(右边补全)补充空格的形式进行补全,然后存放到硬盘中,但是在读取或者使用的时候会自动去掉它给你补全的空格内容,因为这些空格并不是我们自己存储的数据,所以对我们使用者来说是无用的。

  char和varchar性能对比:
    以char(5)和varchar(5)来比较,加入我要存三个人名:sb,ssb1,ssbb2
    char:
      优点:简单粗暴,不管你是多长的数据,我就按照规定的长度来存,5个5个的存,三个人名就会类似这种存储:sb ssb1 ssbb2,中间是空格补全,取数据的时候5个5个的取,简单粗暴速度快
      缺点:貌似浪费空间,并且我们将来存储的数据的长度可能会参差不齐

    varchar:
      varchar类型不定长存储数据,更为精简和节省空间
      例如存上面三个人名的时候类似于是这样的:sbssb1ssbb2,连着的,如果这样存,请问这三个人名你还怎么取出来,你知道取多长能取出第一个吗?(超哥,我能看出来啊,那我只想说:滚犊子!)
      不知道从哪开始从哪结束,遇到这样的问题,你会想到怎么解决呢?还记的吗?想想?socket?tcp?struct?把数据长度作为消息头。

      
      所以,varchar在存数据的时候,会在每个数据前面加上一个头,这个头是1-2个bytes的数据,这个数据指的是后面跟着的这个数据的长度,1bytes能表示2**8=256,两个bytes表示2**16=65536,能表示0-65535的数字,所以varchar在存储的时候是这样的:1bytes+sb+1bytes+ssb1+1bytes+ssbb2,所以存的时候会比较麻烦,导致效率比char慢,取的时候也慢,先拿长度,再取数据。
      优点:节省了一些硬盘空间,一个acsii码的字符用一个bytes长度就能表示,但是也并不一定比char省,看一下官网给出的一个表格对比数据,当你存的数据正好是你规定的字段长度的时候,varchar反而占用的空间比char要多。

官方解释


#官网:https://dev.mysql.com/doc/refman/5.7/en/char.html
CHAR 和 VARCHAR 是最常使用的两种字符串类型。
一般来说
CHAR(N)用来保存固定长度的字符串,对于 CHAR 类型,N 的范围 为 0 ~ 255
VARCHAR(N)用来保存变长字符类型,对于 VARCHAR 类型,N 的范围为 0 ~ 65 535
CHAR(N)和 VARCHAR(N) 中的 N 都代表字符长度,而非字节长度。
ps:对于 MySQL 4.1 之前的版本,如 MySQL 3.23 和 MySQL 4.0,CHAR(N)和 VARCHAR (N)中的 N 代表字节长度。
#CHAR类型
对于 CHAR 类型的字符串,MySQL 数据库会自动对存储列的右边进行填充(Right Padded)操作,直到字符串达到指定的长度 N。而在读取该列时,MySQL 数据库会自动将 填充的字符删除。有一种情况例外,那就是显式地将 SQL_MODE 设置为 PAD_CHAR_TO_ FULL_LENGTH,例如:
mysql> CREATE TABLE t ( a CHAR(10));
      Query OK, 0 rows affected (0.03 sec)
mysql> INSERT INTO t SELECT 'abc';
      Query OK, 1 row affected (0.03 sec)
      Records: 1  Duplicates: 0  Warnings: 0
mysql> SELECT a,HEX(a),LENGTH(a) FROM tG;
      *************************** 1. row ***************************
              a: abc
         HEX(a): 616263
      LENGTH (a): 3
row in set (0.00 sec)
      mysql> SET SQL_MODE='PAD_CHAR_TO_FULL_LENGTH';
      Query OK, 0 rows affected (0.00 sec)
mysql> SELECT a,HEX(a),LENGTH(a) FROM tG;
      *************************** 1. row ***************************
              a: abc
         HEX(a): 61626320202020202020
      LENGTH (a): 10
row in set (0.00 sec)
在上述这个例子中,先创建了一张表 t,a 列的类型为 CHAR(10)。然后通过 INSERT语句插入值“abc”,因为 a 列的类型为 CHAR 型,所以会自动在后面填充空字符串,使其长 度为 10。接下来在通过 SELECT 语句取出数据时会将 a 列右填充的空字符移除,从而得到 值“abc”。通过 LENGTH 函数看到 a 列的字符长度为 3 而非 10。
接着我们将 SQL_MODE 显式地设置为 PAD_CHAR_TO_FULL_LENGTH。这时再通过 SELECT 语句进行查询时,得到的结果是“abc ”,abc 右边有 7 个填充字符 0x20,并通 过 HEX 函数得到了验证。这次 LENGTH 函数返回的长度为 10。需要注意的是,LENGTH 函数返回的是字节长度,而不是字符长度。对于多字节字符集,CHAR(N)长度的列最多 可占用的字节数为该字符集单字符最大占用字节数 *N。例如,对于 utf8 下,CHAR(10)最 多可能占用 30 个字节。通过对多字节字符串使用 CHAR_LENGTH 函数和 LENGTH 函数, 可以发现两者的不同,示例如下:
mysql> SET NAMES gbk;
     Query OK, 0 rows affected (0.03 sec)
mysql> SELECT @a:='MySQL 技术内幕 '; Query OK, 0 rows affected (0.03 sec)
mysql> SELECT @a,HEX(@a),LENGTH(@a),CHAR_LENGTH(@a)G; ***************************** 1. row **************************** a: MySQL 技术内幕
HEX(a): 4D7953514CBCBCCAF5C4DAC4BB
LENGTH (a): 13
CHAR_LENGTH(a): 9
row in set (0.00 sec)
变 量 @ a 是 g b k 字 符 集 的 字 符 串 类 型 , 值 为 “ M y S Q L 技 术 内 幕 ”, 十 六 进 制 为 0x4D7953514CBCBCCAF5C4DAC4BB,LENGTH 函数返回 13,即该字符串占用 13 字节, 因为 gbk 字符集中的中文字符占用两个字节,因此一共占用 13 字节。CHAR_LENGTH 函数 返回 9,很显然该字符长度为 9#VARCHAR类型
VARCHAR 类型存储变长字段的字符类型,与 CHAR 类型不同的是,其存储时需要在 前缀长度列表加上实际存储的字符,该字符占用 1 ~ 2 字节的空间。当存储的字符串长度小 于 255 字节时,其需要 1 字节的空间,当大于 255 字节时,需要 2 字节的空间。所以,对 于单字节的 latin1 来说,CHAR(10)和 VARCHAR(10)最大占用的存储空间是不同的, CHAR(10)占用 10 个字节这是毫无疑问的,而 VARCHAR(10)的最大占用空间数是 11 字节,因为其需要 1 字节来存放字符长度。
-------------------------------------------------
注意 对于有些多字节的字符集类型,其 CHAR 和 VARCHAR 在存储方法上是一样的,同样 需要为长度列表加上字符串的值。对于 GBK 和 UTF-8 这些字符类型,其有些字符是以 1 字节 存放的,有些字符是按 23 字节存放的,因此同样需要 1 ~ 2 字节的空间来存储字符的长 度。
-------------------------------------------------
虽然 CHAR 和 VARCHAR 的存储方式不太相同,但是对于两个字符串的比较,都只比 较其值,忽略 CHAR 值存在的右填充,即使将 SQL _MODE 设置为 PAD_CHAR_TO_FULL_ LENGTH 也一样,例如:
mysql> CREATE TABLE t ( a CHAR(10), b VARCHAR(10));
    Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO t SELECT 'a','a';
    Query OK, 1 row affected (0.00 sec)
    Records: 1  Duplicates: 0  Warnings: 0
mysql> SELECT a=b FROM tG;
    *************************** 1. row ***************************
    a=b: 1
row in set (0.00 sec)
    mysql> SET SQL_MODE='PAD_CHAR_TO_FULL_LENGTH';
    Query OK, 0 rows affected (0.00 sec)
mysql> SELECT a=b FROM tG;
    *************************** 1. row ***************************
    a=b: 1
row in set (0.00 sec)
官网详解
官网详解

其他的字符串类型:BINARY、VARBINARY、BLOB、TEXT

  

1 BINARY 和 VARBINARY 类似于 CHAR 和 VARCHAR,不同的是它们包含二进制字符串而不要非二进制字符串。也就是说,它们包含字节字符串而不是字符字符串。这说明它们没有字符集,并且排序和比较基于列值字节的数值值。
2 BLOB 是一个二进制大对象,可以容纳可变数量的数据。有 4 种 BLOB 类型:TINYBLOB、BLOB、MEDIUMBLOB 和 LONGBLOB。它们区别在于可容纳存储范围不同。
34 种 TEXT 类型:TINYTEXT、TEXT、MEDIUMTEXT 和 LONGTEXT。对应的这 4 种 BLOB 类型,可存储的最大长度不同,可根据实际情况选择。
4 
5 BLOB:
6      1._BLOB和_text存储方式不同,_TEXT以文本方式存储,英文存储区分大小写,而_Blob是以二进制方式存储,不分大小写。
7      2._BLOB存储的数据只能整体读出。
8      3._TEXT可以指定字符集,_BLO不用指定字符集。
其他类型简单介绍
原文地址:https://www.cnblogs.com/strawberry-1/p/11435945.html