字符串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创建对象的工厂.在做性能测试 ...
随机推荐
- 【2019.10.17】十天Web前端程序员体验(软件工程实践第五次作业)
结对信息.具体分工 Github地址:https://github.com/MokouTyan/131700101-031702425 学号 昵称 主要负责内容 博客地址 131700101 莫多 代 ...
- 2019年领航杯 江苏省网络信息安全竞赛 初赛部分writeup
赛题已上传,下载连接:https://github.com/raddyfiy/2019linghangcup 做出了全部的misc和前三道逆向题,排名第10,暂且贴一下writeup. 关卡一 编码解 ...
- Gated CNN 阅读笔记
之前看过TCN,稍微了解了一下语言模型,这篇论文也是对语言模型建模,但是由于对语言模型了解不深,一些常用数据处理方法,训练损失的计算包括残差都没有系统的看过,只是参考网上代码对论文做了粗浅的复现.开学 ...
- Qt *.pro工程文件 详解
先介绍一下QT中关于项目的相关介绍 app - 建立一个应用程序的makefile.这是默认值,所以如果模板没有被指定,这个将被使用. lib - 建立一个库的makefile. vcapp - 建立 ...
- vue cli 静态资源导入 路径
1.public文件夹 使用绝对路径引入. 2.assets文件夹 使用相对路径引入. https://cli.vuejs.org/zh/guide/html-and-static-assets.ht ...
- esxi上为基于LVM的centos7的根目录扩容
概念:据说默认centos都是基于LVM的 LVM:LVM是逻辑盘卷管理(Logical Volume Manager)的简称,它是Linux环境下对磁盘分区进行管理的一种机制. LVM 更加详细的说 ...
- PostgreSQL中的 时间格式转化常识
下面的SQL文查询结果是 "2018-08-20 10:09:10.815125",并且返回类型可以当String处理.返回json等都方便使用. SQL> SELECT t ...
- ISO/IEC 9899:2011 条款6.5.16——赋值操作符
6.5.16 赋值操作符 语法 1.assignment-expression: conditional-expression unary-expression assignment-opera ...
- 报错:Configured broker.id 68 doesn't match stored broker.id 113 in meta.properties
报错背景: CDH中安装完成kafka的组件后不能成功启动,发现UI界面中的broker.id和服务器中的broker.id不一致, 因此更改了服务器中broker.id 但是更改完成之后还是报错. ...
- 利用Python来远程控制肉鸡自由操作,下一个黑客大佬就是你
利用Python来远程控制肉鸡自由操作,下一个黑客大佬就是你 直接开始主题 Server:控制端 Client:被控端 具体实现 然后当有肉鸡连接的时候我们需要获得肉鸡的socket,并且记录下来,以 ...