• 字符串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不用指定字符集。
    其他类型简单介绍
  • 相关阅读:
    进程和线程
    分治算法
    MySQL-IN和Exists区别
    Java-悲观锁和乐观锁
    Spring如何解析Dubbo标签
    Java平台标准版本
    java常用的框架
    状态码
    算法
    java.c++.c#.c的区别
  • 原文地址:https://www.cnblogs.com/strawberry-1/p/11435945.html
Copyright © 2020-2023  润新知