Re:Mysql数据库基础篇(四):一文吃透MySQL数据类型:精度陷阱、长度限制与存储机制


◆ 博主名称: 小此方-CSDN博客 大家好,欢迎来到小此方的博客。
⭐️Linux系列个人专栏: 【主题曲】Mysql
⭐️此方的GitHub: github_此方
⭐️ Re系列专栏:我们思考 (Rethink) · 我们重建 (Rebuild) · 我们记录 (Record)


文章目录


概要&序論

  Hello大家好,我是此方,在几个月前更新过Mysql后来因为Linux网络专栏而停更了一段时间。从本文开始我们将继续更新内容。本文延续上一篇文章。讲解Mysql中常见的数据类型。

一、MySQL数据类型概览与分类

  在MySQL中,选择合适的数据类型对于数据库的性能和存储空间至关重要。不同的数据类型有着不同的存储范围和应用场景。

1.1 数据类型分类总览

  MySQL的数据类型主要分为四大类:数值类型、文本与二进制类型、时间日期类型以及String类型。具体的分类与说明如下表所示。

分类 数据类型 说明
数值类型 BIT(M) 位类型,M指定位数,默认1,范围1-64
数值类型 TINYINT UNSIGNED 带符号范围-128~127,无符号范围0~255,默认有符号
数值类型 BOOL 使用0和1表示真和假
数值类型 SMALLINT UNSIGNED 带符号是-2^15次方到2^15-1,无符号是2^16-1
数值类型 INT UNSIGNED 带符号是-2^31次方到2^31-1,无符号是2^32-1
数值类型 BIGINT UNSIGNED 带符号是-2^63次方到2^63-1,无符号是2^64-1
数值类型 FLOAT(M,D) UNSIGNED M指定显示长度,D指定小数位数,占用4字节
数值类型 DOUBLE(M,D) UNSIGNED 比float精度更大的小数,占用8字节
数值类型 DECIMAL(M,D) UNSIGNED 定点数,M指定长度,D表示小数点的位数
文本、二进制类型 CHAR(size) 固定长度字符串,最大255
文本、二进制类型 VARCHAR(size) 可变长度字符串,最大长度65535
文本、二进制类型 BLOB 二进制数据
文本、二进制类型 TEXT 大文本,不支持全文索引,不支持默认值
时间日期 DATE/DATETIME/TIMESTAMP 日期、日期时间、时间戳格式
String类型 ENUM类型 枚举字符串对象,值来自创建时指定的允许值
String类型 SET类型 集合字符串对象,可包含多个值,以逗号隔开

1.2 数值类型的详细范围

  对于整数类型,带符号(有符号)和无符号(UNSIGNED)的存储范围有显著差异,具体字节数和极值如下表。

类型 字节 最小值(带符号) 最大值(带符号) 最小值(无符号) 最大值(无符号)
TINYINT 1 -128 127 0 255
SMALLINT 2 -32768 32767 0 65535
MEDIUMINT 3 -8388608 8388607 0 16777215
INT 4 -2147483648 2147483647 0 4294967295
BIGINT 8 -9223372036854775808 9223372036854775807 0 18446744073709551615

二、数值类型详解

  在了解了大致分类后,我们详细来看看常用的数值类型。对于整数类型,在MySQL中,整型可以指定是有符号的和无符号的,默认是有符号的,可以通过UNSIGNED来说明某个字段是无符号的。

2.1 tinyint类型

  我们以tinyint为例进行数值越界测试,创建一个带有tinyint字段的表并尝试插入数据。

sql 复制代码
mysql> create table tt1(num tinyint);
Query OK, 0 rows affected (0.02 sec)
mysql> insert into tt1 values(1);
Query OK, 1 row affected (0.00 sec)
mysql> insert into tt1 values(128); -- 越界插入,报错
ERROR 1264 (22003): Out of range value for column 'num' at row 1

  如果是无符号的情况,范围则变成了0到255。

sql 复制代码
mysql> create table tt2(num tinyint unsigned);
mysql> insert into tt2 values(-1); -- 无符号,范围是:0 - 255
ERROR 1264 (22003): Out of range value for column 'num' at row 1
mysql> insert into tt2 values(255);
Query OK, 1 row affected (0.02 sec)

  这里有一个建议,尽量不使用unsigned。对于int类型可能存放不下的数据,int unsigned同样可能存放不下,与其如此,还不如设计时,直接将int类型提升为bigint类型。

2.2 bit类型

  bit(M)是位字段类型,M表示每个值的位数,范围从1到64。如果M被忽略,默认为1。但需要注意的是,bit字段在显示时,是按照ASCII码对应的值显示。

sql 复制代码
mysql> create table tt4 (id int, a bit(8));
Query OK, 0 rows affected (0.01 sec)
mysql> insert into tt4 values(10, 10);
mysql> select * from tt4; # 发现很怪异的现象,a的数据10没有出现,因为10对应ASCII码的换行符,通常不可见
+------+------+
| id   | a    |
+------+------+
|   10 |      |
+------+------+

  如果我们插入65,就会显示为大写字母A。如果我们有这样的值,只存放0或1,这时可以定义bit(1)。这样可以节省空间。比如定义 gender bit(1),插入2则会报错越界。

2.3 小数类型

  小数类型主要分为float和decimal,它们在使用和精度上有显著区别。

2.3.1 float

  语法为 float[(m, d)] [unsigned],其中M指定显示长度,d指定小数位数,占用空间4个字节。小数 float(4,2) 表示的范围是 -99.99 ~ 99.99,MySQL在保存值时会进行四舍五入。

sql 复制代码
mysql> create table tt6(id int, salary float(4,2));
mysql> insert into tt6 values(100, -99.99);
mysql> insert into tt6 values(101, -99.991); # 多的这一点被拿掉了,四舍五入成了-99.99

  如果定义的是 float(4,2) unsigned,这时,因为把它指定为无符号的数,范围是 0 ~ 99.99。如果插入负数如-0.1,会产生警告并截断为0。

2.3.2 decimal

  语法为 decimal(m, d) [unsigned],定点数m指定长度,d表示小数点的位数。decimal(5,2) 表示的范围是 -999.99 ~ 999.99。它和float很像,但最大的区别在于精度。

sql 复制代码
mysql> create table tt8 (id int, salary float(10,8), salary2 decimal(10,8));
mysql> insert into tt8 values(100,23.12345612,23.12345612);
mysql> select * from tt8;
+------+-------------+-------------+
| id   | salary      | salary2     |
+------+-------------+-------------+
|  100 | 23.12345695 | 23.12345612 |
+------+-------------+-------------+

  通过对比发现,decimal的精度更准确,因此如果我们希望某个数据表示高精度,选择decimal。float表示的精度大约是7位。decimal整数最大位数m为65,支持小数最大位数d是30。如果d被省略,默认为0;如果m被省略,默认是10。

三、字符串类型

  字符串类型中最常用的就是char和varchar,我们需要理解它们底层的存储差异。

3.1 char

  语法为 char(L),是固定长度字符串,L是可以存储的长度,单位为字符,最大长度值可以为255。char(2)表示可以存放两个字符,可以是字母或汉字,但是不能超过2个,最多只能是255,如果定义 char(256) 则直接报错。

3.2 varchar

  语法为 varchar(L),是可变长度字符串,L表示字符长度,最大长度65535个字节。关于varchar(len)中len到底能设置多大,和表的编码密切相关。

  varchar长度可以指定为0到65535之间的值,但是有1-3个字节用于记录数据大小,所以说有效字节数是65532。当我们的表的编码是utf8时,varchar(n)的参数n最大值是 65532/3=21844(因为utf8中一个字符占用3个字节);如果编码是gbk,varchar(n)的参数n最大是 65532/2=32766(因为gbk中一个字符占用2字节)。

3.3 char和varchar比较

  如何选择定长或变长字符串?主要依据以下几点。

  1. 如果数据确定长度都一样,就使用定长char,比如身份证、手机号、md5。
  2. 如果数据长度有变化,就使用变长varchar,比如名字、地址,但是你要保证最长的能存的进去。
  3. 定长的磁盘空间比较浪费,但是效率高,它的意义是直接开辟好对应的空间。
  4. 变长的磁盘空间比较节省,但是效率低,它的意义是在不超过自定义范围的情况下,用多少开辟多少。

四、日期和时间类型

  常用的日期类型有三个:date表示日期,格式为 yyyy-mm-dd,占用三字节;datetime表示时间日期,格式为 yyyy-mm-dd HH:ii:ss,表示范围从1000到9999,占用八字节;timestamp表示时间戳,从1970年开始的 yyyy-mm-dd HH:ii:ss 格式和datetime完全一致,占用四字节。

  timestamp有一个特殊属性,在添加或更新数据时,时间戳会自动补上或更新成当前时间。

sql 复制代码
mysql> create table birthday (t1 date, t2 datetime, t3 timestamp);
mysql> insert into birthday(t1,t2) values('1997-7-1','2008-8-8 12:1:1'); 
-- 此时t3时间戳会自动补上当前时间
mysql> update birthday set t1='2000-1-1';
-- 更新数据,t3时间戳会自动更新成当前时间

五、enum和set

  enum是枚举类型,属于"单选"类型,语法为 enum(选项1,选项2,选项3...)。该设定只是提供了若干个选项的值,最终一个单元格中,实际只存储了其中一个值;出于效率考虑,这些值实际存储的是"数字",依次对应 1, 2, 3... 最多65535个。

  set是集合类型,属于"多选"类型,语法为 set(选项值1,选项值2,选项值3...)。一个单元格中可以设计存储其中任意多个值;同样出于效率考虑,这些值实际存储的也是"数字",依次对应 1, 2, 4, 8, 16, 32... 最多64个。不建议在添加枚举值、集合值的时候采用数字的方式,因为不利于阅读。

5.1 案例演示

  我们创建一个调查表votes,需要调查人的喜好(可以多选),以及性别(单选)。

sql 复制代码
mysql> create table votes(
    -> username varchar(30),
    -> hobby set('登山','游泳','篮球','武术'), 
    -> gender enum('男','女')
    -> );
Query OK, 0 rows affected (0.02 sec)

  插入数据时,可以直接用字符串,也可以使用数字下标。

sql 复制代码
insert into votes values('雷锋','登山,武术','男'); 
insert into votes values('Juse','登山,武术',2); 
select * from votes where gender=2;

5.2 集合查询

  假设有数据 Juse 爱好 登山,武术,LiLei 爱好 登山,HanMeiMei 爱好 游泳。我们想查找所有喜欢登山的人,如果使用 select * from votes where hobby='登山';,是不能查询出所有爱好为登山的人的,只能查出行完全匹配 '登山' 的记录。

  集合查询需要使用 find_in_set 函数。find_in_set(sub,str_list) 的含义是:如果sub在str_list中,则返回下标;如果不在,返回0;str_list是用逗号分隔的字符串。正确的查询语句如下。

sql 复制代码
mysql> select * from votes where find_in_set('登山', hobby);

好的本文内容到此结束,我是此方,我们下期再见。

相关推荐
lazy H1 小时前
【计算机网络】第 5 篇:TCP 和 UDP 有什么区别?从 Java 后端场景理解两种传输协议
经验分享·后端·网络协议·tcp/ip·计算机网络·1024程序员节
*小海豚*1 小时前
C盘占用大,windows系统清理C盘各软件 MSI 安装/修复缓存
1024程序员节
域智盾-终端安全管理1 小时前
终端安全管理系统:从“边界信任”到“终端零信任”的工程化落地
1024程序员节·终端安全管理系统
xiaogai_gai1 小时前
旺店通采购订单查询接口字段手册:queryWithDetail 实战权威教程
1024程序员节
黑旋风小威1 小时前
新手做网文漫改怎么提速 知漫剧自动拆分剧情分镜
人工智能·1024程序员节
爱读书的小胖1 小时前
LeetCode 274 H 指数 C 语言解题分析
c语言·算法·leetcode·1024程序员节
B2_Proxy1 小时前
Scrapy 代理 IP 调度进阶:基于 Redis 与中间件的高可用架构实战
python·scrapy·1024程序员节
文慧的科技江湖1 小时前
2026年10月24日智慧农业行业早报:模型数到175个,棚里的账还按年算
开源·智慧农业·农业物联网·数字乡村·1024程序员节·农业机器人·农业数字化
tryCbest1 小时前
文字转语音Edge-TTS知识学习使用
1024程序员节·文字转语音·edge-tts