字符串char vchar性能对比补充
Value | CHAR(4) |
Storage Required | VARCHAR(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 |
- #官网:https://dev.mysql.com/doc/refman/5.7/en/char.html
- #注意:char和varchar括号内的参数指的都是字符的长度
- #char类型:定长,简单粗暴,浪费空间,存取速度快
- 字符长度范围:-(一个中文是一个字符,是utf8编码的3个字节)
- 存储:
- 存储char类型的值时,会往右填充空格来满足长度
- 例如:指定长度为10,存>10个字符则报错(严格模式下),存<10个字符则用空格填充直到凑够10个字符存储
- 检索:
- 在检索或者说查询时,查出的结果会自动删除尾部的空格,如果你想看到它补全空格之后的内容,除非我们打开pad_char_to_full_length SQL模式(SET sql_mode = 'strict_trans_tables,PAD_CHAR_TO_FULL_LENGTH';)
- #varchar类型:变长,精准,节省空间,存取速度慢
- 字符长度范围:-(如果大于21845会提示用其他类型 。mysql行最大限制为65535字节,字符编码为utf-:https://dev.mysql.com/doc/refman/5.7/en/column-count-limit.html)
- 存储:
- varchar类型存储数据的真实内容,不会用空格填充,如果'ab ',尾部的空格也会被存起来
- 强调:varchar类型会在真实数据前加1-2Bytes的前缀,该前缀用来表示真实数据的bytes字节数(-2Bytes最大表示65535个数字,正好符合mysql对row的最大字节限制,即已经足够使用)
- 如果真实的数据<255bytes则需要1Bytes的前缀(1Bytes=8bit **8最大表示的数字为255)
- 如果真实的数据>255bytes则需要2Bytes的前缀(2Bytes=16bit **16最大表示的数字为65535)
- 检索:
- 尾部有空格会保存下来,在检索或者说查询时,也会正常显示包含空格在内的内容
- char和varchar的介绍
char和varchar详细介绍
创建一个t1表,包含一个char类型的字段
- 创建一个t1表,包含一个char类型的字段
- create table t1(id int,name char());
- 超过长度:
- 严格模式下(报错):
- mysql> insert into t1 values('xiaoshabi');
- ERROR (): Data too long for column 'name' at row
- 非严格模式下(警告):
- mysql> set sql_mode='NO_ENGINE_SUBSTITUTION';
- Query OK, rows affected (0.00 sec)
- mysql> create table t1(id int,name char());
- Query OK, rows affected (0.40 sec)
- mysql> insert into t2 values('xiaoshabi');
- Query OK, row affected, warning (0.11 sec)
- 查看一下结果:
- mysql> select * from t1;
- +------+------+
- | id | name |
- +------+------+
- | | xiao | #只有一个xiao
- +------+------+
- row in set (0.00 sec)
- varchar类型和上面的效果是一样的,严格模式下也会报错。
- 如果没有超过长度,那么char类型时mysql会使用空格来补全自己规定的char()的4个字符,varchar不会,我们来做个对比
- 例如:
- #再创建一个含有varchar类型的表t2
- 然后插入几条和t1里面相同的数据
- mysql>insert into t1 values(,'a'),(,'bb'),(,'ccc'),(,'d');
- mysql>create table t2(id int,name varchar());
- mysql> insert into t2 values(,'xiao'),(,'a'),(,'bb'),(,'ccc'),(,'d');
- 查看一下t1表和t2表的内容
- mysql> select * from t1;
- +------+------+
- | id | name |
- +------+------+
- | | xiao |
- | | a |
- | | bb |
- | | ccc |
- | | d |
- +------+------+
- rows in set (0.00 sec)
- mysql> select * from t2;
- +------+------+
- | id | name |
- +------+------+
- | | xiao |
- | | a |
- | | bb |
- | | ccc |
- | | d |
- +------+------+
- rows in set (0.00 sec)
- 好,两个表里面数据是一样的,每一项的数据长度也是一样的,那么我们来验证一下char的自动空格在后面补全的存储方式和varchar的不同
- 通过mysql提供的一个char_length()方法来查看一下所有数据的长度
- mysql> select char_length(name) from t1;
- +-------------------+
- | char_length(name) |
- +-------------------+
- | |
- | |
- | |
- | |
- | |
- +-------------------+
- rows in set (0.00 sec)
- mysql> select char_length(name) from t2;
- +-------------------+
- | char_length(name) |
- +-------------------+
- | |
- | |
- | |
- | |
- | |
- +-------------------+
- rows in set (0.00 sec)
- 通过查看结果可以看到,两者显示的数据长度是一样的,不是说好的char会补全吗,我设置的字段是char(),那么长度应该都是4才对啊?这是因为mysql在你查询的时候自动帮你把结果里面的空格去掉了,如果我们想看到它存储数据的真实长度,需要设置mysql的模式,通过一个叫做PAD_CHAR_TO_FULL_LENGTH的模式,就可以看到了,所以我们把这个模式加到sql_mode里面:
- mysql> set sql_mode='PAD_CHAR_TO_FULL_LENGTH';
- Query OK, rows affected (0.00 sec)
- 然后我们在查看一下t1和t2数据的长度:
- mysql> select char_length(name) from t1;
- +-------------------+
- | char_length(name) |
- +-------------------+
- | |
- | |
- | |
- | |
- | |
- +-------------------+
- rows in set (0.00 sec)
- mysql> select char_length(name) from t2;
- +-------------------+
- | char_length(name) |
- +-------------------+
- | |
- | |
- | |
- | |
- | |
- +-------------------+
- rows in set (0.00 sec)
- 通过结果可以看到,char类型的数据长度都是4,这下看到了两者的不同了吧,至于为什么mysql会这样搞,我们后面有解释的,先看现象就可以啦。
- 现在我们再来看一个问题,就是当你设置的类型为char的时候,我们通过where条件来查询的时候会有一个什么现象:
- mysql> select * from t1 where name='a';
- +------+------+
- | id | name |
- +------+------+
- | | a |
- +------+------+
- row in set (0.00 sec)
- ok,结果没问题,我们在where后面的a后面加一下空格再来试试:
- mysql> select * from t1 where name='a ';
- +------+------+
- | id | name |
- +------+------+
- | | a |
- +------+------+
- row in set (0.00 sec)
- ok,能查到,再多加一些空格试试,加6个空格,超过了设置的char()的4:
- mysql> select * from t1 where name='a ';
- +------+------+
- | id | name |
- +------+------+
- | | 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 |
- +------+------+
- | | 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 |
- +------+------+
- | | 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 的范围 为 ~
- VARCHAR(N)用来保存变长字符类型,对于 VARCHAR 类型,N 的范围为 ~
- 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());
- Query OK, rows affected (0.03 sec)
- mysql> INSERT INTO t SELECT 'abc';
- Query OK, row affected (0.03 sec)
- Records: Duplicates: Warnings:
- mysql> SELECT a,HEX(a),LENGTH(a) FROM t\G;
- *************************** . row ***************************
- a: abc
- HEX(a):
- LENGTH (a):
- row in set (0.00 sec)
- mysql> SET SQL_MODE='PAD_CHAR_TO_FULL_LENGTH';
- Query OK, rows affected (0.00 sec)
- mysql> SELECT a,HEX(a),LENGTH(a) FROM t\G;
- *************************** . row ***************************
- a: abc
- HEX(a):
- LENGTH (a):
- row in set (0.00 sec)
- 在上述这个例子中,先创建了一张表 t,a 列的类型为 CHAR()。然后通过 INSERT语句插入值“abc”,因为 a 列的类型为 CHAR 型,所以会自动在后面填充空字符串,使其长 度为 。接下来在通过 SELECT 语句取出数据时会将 a 列右填充的空字符移除,从而得到 值“abc”。通过 LENGTH 函数看到 a 列的字符长度为 而非 。
- 接着我们将 SQL_MODE 显式地设置为 PAD_CHAR_TO_FULL_LENGTH。这时再通过 SELECT 语句进行查询时,得到的结果是“abc ”,abc 右边有 个填充字符 0x20,并通 过 HEX 函数得到了验证。这次 LENGTH 函数返回的长度为 。需要注意的是,LENGTH 函数返回的是字节长度,而不是字符长度。对于多字节字符集,CHAR(N)长度的列最多 可占用的字节数为该字符集单字符最大占用字节数 *N。例如,对于 utf8 下,CHAR()最 多可能占用 个字节。通过对多字节字符串使用 CHAR_LENGTH 函数和 LENGTH 函数, 可以发现两者的不同,示例如下:
- mysql> SET NAMES gbk;
- Query OK, rows affected (0.03 sec)
- mysql> SELECT @a:='MySQL 技术内幕 '; Query OK, rows affected (0.03 sec)
- mysql> SELECT @a,HEX(@a),LENGTH(@a),CHAR_LENGTH(@a)\G; ***************************** . row **************************** a: MySQL 技术内幕
- HEX(a): 4D7953514CBCBCCAF5C4DAC4BB
- LENGTH (a):
- CHAR_LENGTH(a):
- row in set (0.00 sec)
- 变 量 @ a 是 g b k 字 符 集 的 字 符 串 类 型 , 值 为 “ M y S Q L 技 术 内 幕 ”, 十 六 进 制 为 0x4D7953514CBCBCCAF5C4DAC4BB,LENGTH 函数返回 ,即该字符串占用 字节, 因为 gbk 字符集中的中文字符占用两个字节,因此一共占用 字节。CHAR_LENGTH 函数 返回 ,很显然该字符长度为 。
- #VARCHAR类型
- VARCHAR 类型存储变长字段的字符类型,与 CHAR 类型不同的是,其存储时需要在 前缀长度列表加上实际存储的字符,该字符占用 ~ 字节的空间。当存储的字符串长度小 于 字节时,其需要 字节的空间,当大于 字节时,需要 字节的空间。所以,对 于单字节的 latin1 来说,CHAR()和 VARCHAR()最大占用的存储空间是不同的, CHAR()占用 个字节这是毫无疑问的,而 VARCHAR()的最大占用空间数是 字节,因为其需要 字节来存放字符长度。
- -------------------------------------------------
- 注意 对于有些多字节的字符集类型,其 CHAR 和 VARCHAR 在存储方法上是一样的,同样 需要为长度列表加上字符串的值。对于 GBK 和 UTF- 这些字符类型,其有些字符是以 字节 存放的,有些字符是按 或 字节存放的,因此同样需要 ~ 字节的空间来存储字符的长 度。
- -------------------------------------------------
- 虽然 CHAR 和 VARCHAR 的存储方式不太相同,但是对于两个字符串的比较,都只比 较其值,忽略 CHAR 值存在的右填充,即使将 SQL _MODE 设置为 PAD_CHAR_TO_FULL_ LENGTH 也一样,例如:
- mysql> CREATE TABLE t ( a CHAR(), b VARCHAR());
- Query OK, rows affected (0.01 sec)
- mysql> INSERT INTO t SELECT 'a','a';
- Query OK, row affected (0.00 sec)
- Records: Duplicates: Warnings:
- mysql> SELECT a=b FROM t\G;
- *************************** . row ***************************
- a=b:
- row in set (0.00 sec)
- mysql> SET SQL_MODE='PAD_CHAR_TO_FULL_LENGTH';
- Query OK, rows affected (0.00 sec)
- mysql> SELECT a=b FROM t\G;
- *************************** . row ***************************
- a=b:
- row in set (0.00 sec)
- 官网详解
官网详解
其他的字符串类型:BINARY、VARBINARY、BLOB、TEXT
- BINARY 和 VARBINARY 类似于 CHAR 和 VARCHAR,不同的是它们包含二进制字符串而不要非二进制字符串。也就是说,它们包含字节字符串而不是字符字符串。这说明它们没有字符集,并且排序和比较基于列值字节的数值值。
- BLOB 是一个二进制大对象,可以容纳可变数量的数据。有 种 BLOB 类型:TINYBLOB、BLOB、MEDIUMBLOB 和 LONGBLOB。它们区别在于可容纳存储范围不同。
- 有 种 TEXT 类型:TINYTEXT、TEXT、MEDIUMTEXT 和 LONGTEXT。对应的这 种 BLOB 类型,可存储的最大长度不同,可根据实际情况选择。
- BLOB:
- ._BLOB和_text存储方式不同,_TEXT以文本方式存储,英文存储区分大小写,而_Blob是以二进制方式存储,不分大小写。
- ._BLOB存储的数据只能整体读出。
- ._TEXT可以指定字符集,_BLO不用指定字符集。
其他类型简单介绍
字符串char vchar性能对比补充的更多相关文章
- golang字符串拼接性能对比
对比 +(运算符).strings.Join.sprintf.bytes.Buffer对字符串拼接的性能 package main import ( "bytes" "f ...
- 浅谈C++之冒泡排序、希尔排序、快速排序、插入排序、堆排序、基数排序性能对比分析之后续补充说明(有图有真相)
如果你觉得我的有些话有点唐突,你不理解可以想看看前一篇<C++之冒泡排序.希尔排序.快速排序.插入排序.堆排序.基数排序性能对比分析>. 这几天闲着没事就写了一篇<C++之冒泡排序. ...
- Storm VS Flink ——性能对比
1.背景 Apache Flink 和 Apache Storm 是当前业界广泛使用的两个分布式实时计算框架.其中 Apache Storm(以下简称"Storm")在美团点评实时 ...
- C正则库做DNS域名验证时的性能对比
C正则库做DNS域名验证时的性能对比 本文对C的正则库regex和pcre在做域名验证的场景下做评测. 验证DNS域名的正则表达式为: "^[0-9a-zA-Z_-]+(\\.[0-9a ...
- 不同Framework下StringBuilder和String的性能对比,及不同Framework性能比(附Demo)
本文版权归mephisto和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作. 文章是哥(mephisto)写的,SourceLink 阅读目录 介绍 环境搭建 测试用例 MSDN说明 ...
- PHP生成随机密码的4种方法及性能对比
PHP生成随机密码的4种方法及性能对比 http://www.php100.com/html/it/biancheng/2015/0422/8926.html 来源:露兜博客 时间:2015-04 ...
- StringBuilder和string.Format性能对比
本文由博主(YinaPan)原创,转载请注明出处:http://www.cnblogs.com/YinaPan/p/sbformat.html StringBuilder的性能优于string.For ...
- Net Core下多种ORM框架特性及性能对比
在.NET Framework下有许多ORM框架,最著名的无外乎是Entity Framework,它拥有悠久的历史以及便捷的语法,在占有率上一路领先.但随着Dapper的出现,它的地位受到了威胁,本 ...
- 再看ExpressionTree,Emit,反射创建对象性能对比
[前言] 前几日心血来潮想研究着做一个Spring框架,自然地就涉及到了Ioc容器对象创建的问题,研究怎么高性能地创建一个对象.第一联想到了Emit,兴致冲冲写了个Emit创建对象的工厂.在做性能测试 ...
随机推荐
- pymongo helper
import pymongo import click # 数据库基本信息 db_configs = { 'type': 'mongo', 'host': '127.0.0.1', 'port': ' ...
- git clone速度太慢的解决办法
最近发现使用git clone的速度比较慢,于是找到了办法分享给大家: 思路: git clone特别慢是因为github.global.ssl.fastly.net域名被限制了. 只要找到这个域名对 ...
- Java ArrayList,LinkedList使用
1.ArrayList底层采用数组实现,当使用不带参数的构造方法生成ArrayList对象时,实际上回在底层生成一个长度为10的Object类型数组. 2.如果增加的元素个数超过10个,那么Array ...
- ln bug
/home/hdp/testcpy sudo ln -s . /usr/lib/cpy390sourcecode cpy390sourcecode -> . sudo ln -s pwd /us ...
- 深入理解JS中&&和||
写了这么多JS,才发现JS的语法既是属于C语系的,又与一般C语系的编程语言某些地方有很大区别,其中&&和||就是其中一例. C语系中的&&和|| C语系的&&a ...
- hdfs 通过命令坏块监测和删除或者地址获取参数做监控
[root@nodecm.oldboy.org.cn /data/dfs/nn/current]# hdfs fsck -list-corruptfileblocksConnecting to nam ...
- php递归注意事项
/* 循环去除字符串左边的0 */ function removeLeftZero($str){ if($str['0'] == '0'){ $str = substr($str, '1'); rem ...
- pytorch对模型参数初始化
1.使用apply() 举例说明: Encoder :设计的编码其模型 weights_init(): 用来初始化模型 model.apply():实现初始化 # coding:utf- from t ...
- svn使用步骤
这里只是记录大概使用过程,操作步骤只供参考,不要按部就班. 1.安装SVN 服务端Setup-Subversion-1.6.5.msi和客户端TortoiseSVN-1.6.5.16974-win32 ...
- spring Securicty入门(一)
在一次项目中启动测试一个借口,结果提示要登录,如下图.原因是无意中引用了spring Securicty的依赖,别的啥都没干就弹出来这个,懵逼了半天最后注释掉.shiro你引个jar包别的不配置,也不 ...