八股:MySQL 中 varchar 和 char 有什么区别?
对话解析
char和 varchar的区别
大佬: 我今天遇到个新问题,Mysql建表的时候,那个char类型和varchar类型有啥区别的,不都是字符串吗?
凯歌: 这俩啊,说的确实没问题,都是存字符串的,不过确实有点区别,我给你列个表,你直观感受下。
| 不同点 | CHAR | VARCAHR |
|---|---|---|
| 存储方式不同 | 定长字符串(长度不足,空格补齐) | 变长字符串 |
| 占用空间不同 | 始终占用固定长度 | 需要多少,占用多少 |
| 性能不同 | 长度固定,可能会浪费空间 | 需要多少,存多少,可以节省一些空间,但是某些情况下,可能会影响性能 |
| 适用场景不同 | 适合存储固定且短的字符串 | 适合存储变化或较长的字符串 |
大佬: 哦哦,看这个表格,我大概知道啥区别了,就是一个直尺,一个是卷尺呗?能变不能变的。
凯歌: 对对对,就是这意思
varcahr的影响
大佬: 那我看,你上面说,某些情况下,varchar会有影响,是啥情况,啥影响啊?
凯歌: 哦哦哦,这个啊,这个是在排序或者分组的时候,产生的现象,我下面详细说说。
凯歌: 还是拿我们的user表举例子啊,比如,我们要查询user表中id在190万之后的用户的id,姓名,年龄,并且结果要按照年龄排序。SQL语句如下。
▼sql复制代码select id,name,age from user where id>1900001 order by age;
凯歌: 下面我画个图,我们这个SQL的执行流程,大概是什么样子啊。
凯歌: 下面我我照着这个图挑重点讲讲
凯歌: 第一步:InnoDB执行我们的SQL语句,获取到未排序或分组的结果集。
凯歌: 第二步:判断sort_buffer(排序内存缓冲区)的大小,能不能放下我们的结果集
凯歌: 到这里,我们就需要暂停下,分析:怎么判断能不能放下
凯歌: 很简单,一个是看下sort_buffer的大小,一个就是统计每个字段的长度,这时候,因为char存的都是固定且短的字符,而varchar存的是变化且长的字符,如果我们的varchar很长,就放不进sort_buffer
凯歌: 当我们不能把数据都放进内存里的时候,就需要把数据拆开
凯歌: 比如多路并归排序,这时候,我们原本可以一次在内存中操作完的,就需要多次IO操作,增加了成本,降低了性能。
多路并归排序:
将数据拆分成一块块可以放进sort_buffer中的大小,然后一块一块的进去排序,将排好序的数据,再存到磁盘中,等所有的小块,都排好了,再把每一个小块中,最小的主键取出来,然后再根据这些取出来的主键,把整个数据在内存排好,返回给客户端
大佬: 哦哦哦,那我大概明白了。这里的排序、分组啥的还能再展开讲讲不,感觉好多还可以展开再说说。
凯歌: 当然,不可以了! 时间来不及了,马上12点了,这块不是这里的重点,后期我在别的地方单独讲给你听。
大佬: 行吧,你个老六。
单个varchar的最大长度是多少?
大佬: 那不能展开讲那个,你说说一个varchar最多能存多少东西吧,你老说它可变,到底能变多长啊?无限长?
凯歌: 这没问题。
凯歌: 根据mysql的官方文档,我们可以知道一个varcahr的最大长度是65535个字节。如下图:
大佬: 这是它的整体大小,那我们存数据也能存这么多吗?
凯歌: 不不,我们存数据的时候,会略微小一点。
大佬: 那为啥为小啊?存别的东西了?出轨了?
凯歌: 对的,就是存别的东西了,不过没出轨啊,都是存的跟你相关的东西。
凯歌: 这额外存的东西,包含两部分,如下
第一部分:是否null值,占用1字节
第二部分:字符串长度,占用1-2字节,以255为分界线,大于255字节,需要两个字节
凯歌: 也就是说,按照最小可用来说,我们可以存储:65535-1-2=65532字节
大佬: 哦哦哦,65532个字符嘛。
凯歌: 停!不是字符!是字节!
特别提示:字符和字节不同,不同的编码规则,一个字符对应的字节数不一致,例如:UTF-8编码规则,一个字符最大可以占用三个字节
凯歌:以上,就是我们本次关于MySQL 中 varchar 和 char 有什么区别?的讲解了,若有错误,请帮忙指出,一定修改。
