当前位置:网站首页>【mysql进阶】10种数据类型的区别以及如何优化表结构(三)
【mysql进阶】10种数据类型的区别以及如何优化表结构(三)
2022-06-11 19:28:00 【wu_55555】
文章目录
0.引言
一个优秀的开发者在于性能的提升和资源的节约上是会不断追求,不断打磨的,我们在使用mysql时创建表结构时,更是需要我们理解每一种数据类型的区别,并且在不同的业务场景中选择适合的数据类型。
那么我们今天就来谈谈如何来优化表结构
1. 数据类型的优化
字段是组成表结构的基础,而针对数据类型做好优化,更是表结构优化的第一步。所以我们先来看如何对数据类型做好选型与优化。
1.1 mysql的数据类型
首先我们要知道mysql支持哪些数据类型,这些数据类型之间的区别是是什么,然后我们才能针对不同的场景选择不同的类型。
mysql中一共支持10种数据类型
1.1.1 整数类型
整数类型分为以下5种
| 数据类型 | 大小 | 范围 |
|---|---|---|
| tinyint | 1字节 | -128~127 |
| smallint | 2字节 | -32768~32767 |
| mediumint | 3字节 | -8388608~8388607 |
| int | 4字节 | -2147483648~2147483647 |
| bigint | 8字节 | -9.22*10^18~9.22*10^18 |
通过上述我们知道tinyint是在所有整型中占用空间最小的,我们常常看到会用int(n)等形式来表示数据类型,其中的n的含义是该数据类型能够展现的最大宽度,比如10的宽度就是2,100的宽度就是3,n与数据的存储大小不相关,也就是说int(1)与int(11)所占用的空间都是4字节
1.1.2 浮点数类型
mysql中浮点类型有以下3种
| 数据类型 | 大小 |
|---|---|
| float | 4字节 |
| double | 8字节 |
| decimal (m,n) | 取决于m,n |
decimal的大小取决于m,n的值,m表示整个数值的数字长度,n表示小数部分的数字长度,默认4个字节可以存储9个数字,小数点占1个字节,不满9个数字时占用大小如下所示
| 数字个数 | 大小 |
|---|---|
| 1,2 | 1字节 |
| 3,4 | 2字节 |
| 5,6 | 3字节 |
| 7,8 | 4字节 |
举个例子:decimal(19,4),19/9=2…1,2*4=8字节,1个数字占1字节,再加上小数点1字节,所以总共占8+1+1=10字节
需要注意的是:mysql规定m<65,n<30
1.1.3 位类型
bit数据类型用于存储位字段值,支持1-64个长度,我们可以用bit(1)来表示布尔类型的数据
尽管从空间占用上来说,bit更小,但实际开发中我们更常用的是tinyint(1)来表示,而很少使用bit,主要是因为bit是在mysql5.x版本后的支持才逐渐完善,而历史开发的习惯和继承使得我们更喜欢使用tinyint
1.1.4 日期类型*
日期类型主要包含以下5种
| 数据类型 | 大小 | 范围 | 用途 |
|---|---|---|---|
| date | 3字节 | 1000-01-01~9999-12-31 | 存储日期 |
| time | 3字节 | ‘-838:59:59’~‘838:59:59’ | 存储时间值(不存储日月年) |
| year | 1字节 | 1901~2155 | 存储年份值 |
| datetime | 8字节 | 1000-01-01 00:00:00~9999-12-31 23:59:59 | 存储时间值(包括日月年) |
| timestamp | 4字节 | 1970-01-01 00:00:00~2038-1-19 11:14:07 | 存储时间戳,注意只能存储到2038年 |
1.1.5 字符类型*
字符类型包括如下几种:
| 数据类型 | 大小 | 用途 |
|---|---|---|
| char | 0~255字节 | 存储定长字符串 |
| varchar | 0-65535字节 | 存储变长字符串 |
| text | 0-65535字节 | 存储长文本 |
| tinytext | 0-255字节 | 存储短文本 |
| mediumtext | 0-16M | 存储中等文本 |
| longtext | 0-4G | 存储极大文本 |
需要注意的是,在mysql中已经很少使用4种text类型了,一般这类长文本数据会以文件形式存储到OSS,或者存储到es中间件中。
1.1.6 二进制字符串类型
与上述的文本类型对应,mysql中提供了4中二进制文本类型,实际开发中使用较少,这里罗列出来供大家参考
| 数据类型 | 大小 | 用途 |
|---|---|---|
| blob | 0-65535字节 | 存储二进制形式的长文本 |
| tinyblob | 0-255字节 | 存储二进制形式的短文本 |
| mediumblob | 0-16M | 存储二进制形式的中等文本 |
| longblob | 0-4G | 存储二进制形式的极大文本 |
blob类型与text类型的区别在于:
1、blob是以二进制存储数据,text是以文本存储数据
2、blob存储的数据只能整体读出
3、因为blob是二进制的,所以不用指定字符集,而text需要
1.1.7 枚举类型*
enum,与java一样,mysql中也有枚举类型,我们可以用枚举类型来表示状态、类型等枚举值
1.1.8 集合类型
set,不常用,一般用子表存储集合数据
1.1.9 JSON类型
json,用于存储json型对象、数组,比如存储bpmn工作流模版json型数据。但实际工作中很少使用mysql存储json数据,这是由mysql本身关系型数据库的本质决定的,更常使用天然支持json的mongodb,如果数据量大的还可以采用es存储
1.1.10 空间数据类型
geometry,point等,mysql中也很少存储空间坐标数据,同样更常使用mongodb、es来存储
1.2 数据类型优化原则
我们在了解了mysql支持的数据类型以及它们占用的空间大小和用途后,就可以接着进入我们今天的正题,如何优化表字段。我们从以下3个原则出发来进行讲解
1.2.1 越小越好
我们应当尽量使用最小的数据类型,所谓最小就是占用空间最小。能用smallint就不用int,能用tinyint就不用smallint
1、整型
比如‘是否删除’这样的标识字段,我们就可以用tinyint(1)来表示,而不要用int(1)来表示。上面已经解释了,这里面的1并不是其占用的空间大小,不要觉得tinyint(1)的大小和int(1)大小是一致的
整型的空间大小按从小到大是:tinyint<smallint<mediumint<int<bigint,能用小则用小
** 2、字符串**
字符串中我们最常用的是varchar和char,如电话号码、邮编这样的定长的字符我们就尽量使用char。并且其长度在满足业务的情况下,能小则小,比如邮编为6位,就不要定义为char(10),不要白白浪费这4个空间。
同时对于不确定长度的字符串,我们虽然使用varchar,但也不要盲目地定义为varchar(255),而是要根据实际的业务情况来定义最大长度,如果你不知道他的最大长度,那就去问产品经理、问业务,确定一个最大长度。
这里还要给大家补充几个知识点:
(1)varchar(n),当n<=255时,需要使用额外的1个字节保存长度,n>255时需要额外使用2个字节保存长度。
(2)为了提高查询效率,及时长度不满255,mysql也会给varchar预留255的空间位置,也就是说varchar(1)预留的空间位置也是255,这里要注意预留位置不代表实际占用的大小,所谓预留是指将磁盘中连续的这一段空间位置留出来,这样这些数据是连续的,获取的时候效率就高。想想你们一家人,你哥住村头,你住村尾,你说村长过来通知你家去开会,你们是住在一起的时候通知的快还是没住在一起的时候通知的快?
(3)varchar在mysql5.6版本之前,变更长度到255以下改到255以上时,会导致锁表。所以我们都尽量建议将长度定到255以下
(4)char的查询效率比varchar更高,所以能用char就用char。结合上面说的村头村尾的例子,想想为什么?
3、长文本数据
如上述所示,这类数据一般是文章或者其他文档文件,我们一般将其以文件形式存储到OSS服务器,然后在数据库中以varchar形式存储一个OSS上该文件的地址
4、时间类型
按照占用大小来看:date<timestamp<datetime。按照上述的原理,在满足业务的情况下尽量使用小的,但是时间类型比较特殊,我们考虑业务需要具有一定的前瞻性:
比如存储的日期需不需要到秒,业务上可能没有这个需求,但是未来做数据统计的时候需不需要。
或者项目运行的日期会不会超过2038年,因为timestamp最大只能表示2038年。这时就要使用datetime
5、枚举类型
使用enum类型或者数值类型来代替一些枚举型的字符串
6、ip地址
一般我们存储ip地址直接想到的是字符串,实际上可以通过inet_aton函数将字符串型的ip数据转换为数值存储到数据库,这样占用的空间就会大大缩小,查询时再通过inet_ntoa函数来转换
select inet_aton('1.1.1.1')
select inet_ntoa(16843009)
1.2.2 越简单越好
能够使用更加简单的类型就使用更简单的类型,因为简单的数据类型消耗的CPU资源更少。那么哪些类型更加简单呢?
1、整型比字符串更简单,比如ip地址转换为整型来存储
2、日期类型比字符串更简单,比如避免使用字符串来存储日期
3、char比varchar更简单
1.2.3 避免为空
我们知道在对null值判断时,直接=null、!=null是不生效的,而得通过is null、is not null来判断。并且null值会让索引无法统计,因此我们在创建表字段时,能给默认值就尽量给默认值,特别是索引字段。
2. 表结构优化原则
2.1 适当的数据冗余
适用场景:频繁查询且需要join两张或两张以上表才能获取的少量字段
设计表结构时,如果某些字段需要join另一个表来查询,并且查询还比较频繁,那么我们就应该考虑在主表中冗余该字段,这样通过一张表查询所有数据,提高查询效率
案例1:
比如商品名称,商品ID等数据维护在商品表里,订单表中有商品ID。我们查询订单中必然要显示商品名称,如果每次都从商品表中关联获取名称,其效率肯定不如我们直接在订单表中冗余一个商品名称来得高
当然这样的冗余要考虑业务需要,比如我们某些业务要求数据要实时显示,名称这类的信息可能会被更改,一旦更改了之前业务表中查询出来的名称也要是最新的,这种情况下,就需要我们得通过关联查询了,就不再是冗余数据能够解决的了
有的同学可能会说了,我更新的时候把冗余字段一起更新了不就行了吗?嗯这倒是个好主意,但是得分情况,如果业务表中的数据特别的,那你要更新的冗余数据就会特别多,可能就会导致这个更新操作得不偿失。
案例2:
比如我们有一个运单表,每个运单下记录了多个运输的货物信息,那么同时也有了一个运输货物表,那么当我们要统计某段时间内的运输总量时,就需要通过运单表关联货物表,然后对货物表中的重量字段求和
但实际上我们可以通过在运单中冗余一个总重量字段,甚至可能还有一个总金额字段,在插入货物的时候就求和并且记录到运单中了,这样统计时直接在运单中获取即可
2.2 适当的拆分
使用场景:表中存在占用空间较大但不常查询的字段,同时存在其他频繁查询的字段时
当我们的表中存在某个或某几个占用空间大,比如text类型的,或者varchar(200+)类型的,我们需要经常查询这张表的某几个字段,但是这几个大字段却不需要时,我们就可以考虑把这几个大字段拆分到另一张表中,通过外键关联
这样做的好处是,让这些经常查询的数据存放在相邻的数据块中,这样查询时可以提高效率(还是上述提高的村头村尾的例子),减少IO次数
2.3 选择合适的字符集
可能我们很多的开发中并没有在意字符集的选择,很多都是闭着眼给数据库设置utf8mb4,然后完事了。
但是实际上,针对不同的业务场景,选择适当的字符集可以大大提高我们的查询效率
1、如果业务数据只有英文和数字,那么可以设置为latin1,也就是拉丁字符集,这可以节约大量的存储空间。如果可以确定不需求存放多种语言的数据,就没有必要非得用utf8或utf8mb4
2、针对不同的业务表的不同数据情况,选择不同的字符集,以减少存储空间,从而提高查询效率
3、有中文,就使用utf8mb4,而不要用utf8。因为utf8最多支持3字节,而像一些生僻中文字和emojj表情是需要4字节的,就会导致存储错误bug,mysql官方在2010年发布utf8mb4也是为了解决这些bug。
2.4 主键选择
主键选择一般有两种方案:一是选择业务数据中的具有唯一性的自然主键,比如用户表中的身份证号,订单表中的订单号;二是通过主键生成算法生成一个与业务无关的主键,比如UUID
我们更加推荐使用第二种方案,即通过主键生成算法来生成一个随机的主键,这样做有两种好处:
1 与业务无关,更加容易维护
想象一下,如果是在多租户系统中,很多情况下为了满足用户公司的管理需求,我们允许用户输入自定义编号,比如租户A的用户输入了编号111,如果我们将这个唯一编号作为主键,因为是多租户系统,数据是隔离的,租户B的用户是看不到编号111的数据的,但是如果他刚好也创建了一个编号111时,就会发现数据库报错了,因为主键不允许重复,但是他却会纳闷了:我也没看到111被输入过呀,页面里没有显示呀。所以这样的情况下, 与业务无关的主键成为必要。2 一般主键生成算法是通用的,通用的处理方案对整体开发而言是能够高效节约时间的
总结
好了,本期关于表结构优化的几种原则就到此结束了,更多细节上的实现还要大家结合具体的业务需求来把控。如果你觉得本文对你有帮助的话,不妨点个关注给个赞!
我们下期再见~
边栏推荐
- Web3游戏:游戏体验的探寻与重塑
- Anaconda安装、Jupyter Notebook默认启动路径修改及Nbextensions插件安装
- Introduction to go language (V) -- branch statement
- 【求助】請問如何讓微信公眾號文章在外部瀏覽器中打開後還能顯示下方的精選留言?
- [C language questions -- 10 simple questions for leetcode]
- CMU 15-445 數據庫課程第五課文字版 - 緩沖池
- Yolov3 pytoch code and principle analysis (II): network structure and loss calculation
- Record the phpstudy configuration php8.0 and php8.1 extension redis
- Given a project, how will you conduct performance testing?
- 使用canvas给页面添加文字水印
猜你喜欢

【C语言刷题——Leetcode10道简单题】
![[image denoising] image denoising based on Markov random field with matlab code](/img/ef/d28b89a47723b43705fca07261c958.png)
[image denoising] image denoising based on Markov random field with matlab code

谷歌提出超强预训练模型CoCa,在ImageNet上微调Top-1准确率达91%!在多个下游任务上SOTA!...
![[signal denoising] speech adaptive denoising based on nonlinear filter with matlab code](/img/fd/07cee3c51ac44ca40f730dd487aa20.png)
[signal denoising] speech adaptive denoising based on nonlinear filter with matlab code
![leetcode:926. Flip the string to monotonically increasing [prefix and + analog analysis]](/img/e8/a43b397155c6957b142dd0feb59885.png)
leetcode:926. Flip the string to monotonically increasing [prefix and + analog analysis]
![[image denoising] impulse noise image denoising based on absolute difference median filter, weighted median filter and improved weighted median filter with matlab code attached](/img/dc/6348cb17ca91afe39381a9b3eb54e6.png)
[image denoising] impulse noise image denoising based on absolute difference median filter, weighted median filter and improved weighted median filter with matlab code attached

On the translation of rich text storage database format

Find the maximum 3 same digits in the string

CMU 15-445 數據庫課程第五課文字版 - 緩沖池

Tensorflow---TFRecord文件的创建与读取
随机推荐
Gmail: how do I recall an outgoing message?
ASEMI的MOS管25N120在不同应用场景的表现
Today's sleep quality record is 60 points
Pyramid test principle: 8 tips for writing unit tests
[C language questions -- 10 simple questions for leetcode]
LDPC 7 - simple example of decoding
[laravel series 7.5] event system
Introduction to typescript
collect.stream().collect()方法的使用
[solution] codeforces round 798 (Div. 2)
Go语言入门(六)——循环语句
[signal denoising] speech adaptive denoising based on nonlinear filter with matlab code
【Multisim仿真】利用运算放大器产生锯齿波
Performance of MOS transistor 25n120 of asemi in different application scenarios
构建Web应用程序
使用贝叶斯优化进行深度神经网络超参数优化
Detailed explanation of iSCSI (IV) -- actual configuration of iSCSI server
[image denoising] impulse noise image denoising based on absolute difference median filter, weighted median filter and improved weighted median filter with matlab code attached
leetcode:66.加一
YOLOv3 Pytorch代码及原理分析(二):网络结构和 Loss 计算