MySQL:数据类型

一、先看全貌:类型分几大类

复制代码
数据类型
├── 数值类型
│   ├── 整型   tinyint / smallint / mediumint / int / bigint
│   ├── 位类型 bit
│   └── 小数   float / double / decimal
├── 字符串类型
│   ├── char / varchar
│   ├── text / blob
│   └── enum / set          ← 单选 / 多选
└── 日期时间类型
    ├── date
    ├── datetime
    └── timestamp

为什么非要选类型? 就像买收纳盒:

  • 你说"我要一个格子",店家会问"放戒指还是放被子?"------大小不一样,价格不一样;
  • 数据库里,类型决定了:占多少空间 、能存多大范围 、能不能比较/排序 、会不会偷偷四舍五入。

选错类型的典型后果:

  • 用 tinyint 存手机号 → 存不下,报错;
  • 用 float 存金额 → 0.1 + 0.2 不等于 0.3,账算不平;
  • 用 char(50) 存地址 → 每条记录浪费几十字节,一百万条就是几十 MB 白扔。

二、整型:tinyint 与 unsigned

2.1 先做个实验:越界会怎样

复制代码
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

mysql> select * from tt1;
+------+
| num  |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

发生了什么 :tinyint 的范围是 -128 ~ 127 ,你偏要塞 128,MySQL 直接拒绝(报 Out of range),原来那行 1 还在。

📌 注意是报错不是"截断"。这条数据压根没进去。

2.2 有符号 vs 无符号

课件说明:

在 MySQL 中,整型可以指定是有符号 的和无符号 的,默认是有符号的 。可以通过 UNSIGNED 来说明某个字段是无符号的。

类型 有符号范围(默认) 无符号范围(unsigned)
tinyint -128 ~ 127 0 ~ 255
smallint -32768 ~ 32767 0 ~ 65535
int -21 亿 ~ 21 亿 0 ~ 42 亿
bigint 极大 极大

打个比方:

  • 有符号 = 温度计,能让零下;
  • 无符号 = 年龄、库存、价格,永远不可能是负数,所以把"负数那半边"也拿来做正数,能存的范围翻倍。

2.3 无符号案例

复制代码
mysql> create table tt2(num tinyint unsigned);
Query OK, 0 rows affected (0.02 sec)

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)

mysql> select * from tt2;
+------+
| num  |
+------+
|  255 |
+------+
1 row in set (0.00 sec)
  • 插 -1 → 报错(无符号不收负数);
  • 插 255 → 成功(上限从 127 提到 255)。

2.4 课件的一条重要建议(反直觉)

⚠️ 注意:尽量不使用 unsigned ,对于 int 类型可能存放不下的数据,int unsigned 同样可能存放不下。与其如此,还不如设计时,将 int 类型提升为 bigint 类型。

为什么这么说? 因为 unsigned 会带来两个麻烦:

  1. 范围只翻了一倍 ,治标不治本。真正的风险是"以后数据会超过 int 上限",那就直接用 bigint;
  2. 做减法时会出错 :unsigned 的列减一个更大的数,MySQL 会报错或绕回成一个巨大的正数(0 - 1 变成 42 亿),这是非常隐蔽的 bug。

打个比方 :你的车油箱不够用,unsigned 相当于"把座椅拆了装个副油箱"(只多一点,还影响别的功能);而换 bigint 相当于"直接换个大油箱"(一步解决)。

📌 实战建议:能用 int 就用 int;可能超大(比如日志 ID、时间戳)用 bigint;unsigned 少用。


三、bit:位类型(存开关和布尔值)

3.1 语法

复制代码
bit[(M)]

M 表示每个值的位数,范围从 1 到 64 。如果 M 被忽略,默认为 1。

3.2 一个"诡异"的案例

复制代码
mysql> create table tt4 (id int, a bit(8));
Query OK, 0 rows affected (0.01 sec)

mysql> insert into tt4 values(10, 10);
Query OK, 1 row affected (0.01 sec)

mysql> select * from tt4;      # 发现很怪异的现象,a 的数据 10 没有出现
+------+------+
| id   | a    |
+------+------+
|   10 |      |
+------+------+
1 row in set (0.00 sec)

为什么看不到 10? 因为:

bit 字段在显示时,是按照 ASCII 码对应的值显示。

ASCII 码 10 是"换行符"(不可见字符),所以显示成空白。

再插一个 65:

复制代码
mysql> insert into tt4 values(65, 65);
mysql> select * from tt4;
+------+------+
| id   | a    |
+------+------+
|   10 |      |
|   65 | A    |
+------+------+
2 rows in set (0.00 sec)

ASCII 65 就是大写字母 A,所以显示 A。

📌 结论 :bit 显示的是"这个数字对应的字符",不是数字本身。想看数字得用 a+0 或 bin(a) 之类的转换。

3.3 什么时候用 bit

如果我们有这样的值,只存放 0 或 1 ,这时可以定义 bit(1)。这样可以节省空间。

比如:

  • 性别(0/1)
  • 是否删除(0/1)
  • 是否已读(0/1)

一个 bit(1) 只占 1 位,而 tinyint 要占 1 字节(8 位)。八倍差距,数据量大时很可观。

打个比方 :bit(1) 是一个电灯开关,只有开/关两种状态;tinyint 是一个抽屉,能装 -128~127 但你就放个 0 或 1,浪费。

⚠️ 不过实务中很多人还是用 tinyint(1) 当布尔值,因为 ORM/各种工具对 bit 的支持不一定完美。这一点知道就行。


四、小数类型:float 与 decimal

小数是最容易出错的一块,因为涉及精度。

4.1 float 语法

复制代码
float[(m, d)] [unsigned]

M 指定显示长度 ,d 指定小数位数 ,占用空间 4 个字节。

怎么理解 m 和 d?

float(4,2):

  • d=2 → 小数点后 2 位;
  • m=4 → 总共 4 位(整数部分 + 小数点 + 小数部分里,MySQL 里 m 指的是总位数,不含小数点);
  • 所以范围是 -99.99 ~ 99.99。

4.2 案例:范围和四舍五入

复制代码
mysql> create table tt6(id int, salary float(4,2));
Query OK, 0 rows affected (0.01 sec)

mysql> insert into tt6 values(100, -99.99);
Query OK, 1 row affected (0.00 sec)

mysql> insert into tt6 values(101, -99.991);    # 多的这一点被拿掉了
Query OK, 1 row affected (0.00 sec)

mysql> select * from tt6;
+------+--------+
| id   | salary |
+------+--------+
|  100 | -99.99 |
|  101 | -99.99 |
+------+--------+
2 rows in set (0.00 sec)

两个现象:

  1. -99.991 被存成 -99.99------多的小数位被截掉/四舍五入;
  2. 范围就是 -99.99 ~ 99.99,超出就报错或警告。

课件留了个思考题:float(6,3) 的范围是多少? 答案:整数部分 3 位、小数 3 位 → -999.999 ~ 999.999。

4.3 无符号的 float

复制代码
mysql> create table tt7(id int, salary float(4,2) unsigned);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into tt7 values(100, -0.1);
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> show warnings;
+---------+------+-------------------------------------------------+
| Level   | Code | Message                                         |
+---------+------+-------------------------------------------------+
| Warning | 1264 | Out of range value for column 'salary' at row 1 |
+---------+------+-------------------------------------------------+
1 row in set (0.00 sec)

mysql> insert into tt7 values(100, -0);
Query OK, 1 row affected (0.00 sec)

mysql> insert into tt7 values(100, 99.99);
Query OK, 1 row affected (0.00 sec)

注意这里的细节:插 -0.1 时不是报错而是一条 Warning ,值被存成了 0.00(因为无符号范围是 0~99.99)。

📌 -0 是合法的(它等于 0),但 -0.1 越界。

4.4 decimal:精度更高的定点数

复制代码
decimal(m, d) [unsigned]

decimal(5,2) 表示的范围是 -999.99 ~ 999.99 ; decimal(5,2) unsigned 表示范围 0 ~ 999.99。

看起来和 float 一模一样,但关键区别在精度:

decimal 整数最大位数 m 为 65 ,支持小数最大位数 d 是 30 。 如果 d 被省略,默认为 0;如果 m 被省略,默认是 10。

说明:float 表示的精度大约是 7 位。

4.5 精度对比实验(本篇最值得记住的)

复制代码
mysql> create table tt8 ( id int, salary float(10,8), salary2 decimal(10,8));
Query OK, 0 rows affected (0.01 sec)

mysql> insert into tt8 values(100, 23.12345612, 23.12345612);
Query OK, 1 row affected (0.00 sec)

mysql> select * from tt8;
+------+-------------+-------------+
| id   | salary      | salary2     |
+------+-------------+-------------+
|  100 | 23.12345695 | 23.12345612 |
+------+-------------+-------------+
1 row in set (0.00 sec)

同样的输入 23.12345612:

  • float 存成了 23.12345695(后面几位全乱了);
  • decimal 原封不动 23.12345612。

为什么? 因为 float 是二进制浮点数 ,很多十进制小数在二进制里是"除不尽的无限循环小数",只能近似。而 decimal 是按十进制存的,能精确表示。

📌 课件建议:如果希望小数的精度高,推荐使用 decimal。

4.6 什么时候用哪个

场景 用什么 原因
金额、价格、工资、账目 decimal 一分钱都不能差
科学计算、坐标、图形 float / double 只要近似值,且运算快、省空间
百分比、评分(如 4.5 分) decimal(3,1) 精度够、可读性好

打个比方:

  • float 是一把弹簧秤,读数快、范围大,但"1.000 克"可能显示成"1.002 克";
  • decimal 是一台精密天平,慢一点、占地方,但你说 23.12345612 它就记 23.12345612。

⚠️ 血泪教训 :很多系统用 float 存金额,结果对账差几分钱,查半天查不出来。金额永远用 decimal。


五、字符串类型:char 与 varchar

这两个是新手最容易混的,我们从"它俩到底差在哪"讲起。

5.1 char:定长字符串

复制代码
char(L)

char(L):固定长度字符串,L 是可以存储的长度,单位为字符,最大长度值可以为 255。

关键词:固定长度 、单位是"字符" (不是字节)、最大 255。

案例:

复制代码
mysql> create table tt9(id int, name char(2));
Query OK, 0 rows affected (0.00 sec)

mysql> insert into tt9 values(100, 'ab');
Query OK, 1 row affected (0.00 sec)

mysql> insert into tt9 values(101, '中国');
Query OK, 1 row affected (0.00 sec)

mysql> select * from tt9;
+------+--------+
| id   | name   |
+------+--------+
|  100 | ab     |
|  101 | 中国   |
+------+--------+
2 rows in set (0.00 sec)

char(2) 表示可以存放两个字符 ,可以是字母或汉字,但是不能超过 2 个,最多只能是 255。

注意 :char(2) 写 '中国' 是可以的------因为 L 的单位是"字符"不是"字节",两个汉字就是两个字符。

超过 255 会怎样:

复制代码
mysql> create table tt10(id int ,name char(256));
ERROR 1074 (42000): Column length too big for column 'name' (max = 255); use BLOB or TEXT instead

报错直接告诉你:max = 255,想存更长请用 BLOB / TEXT。

5.2 varchar:变长字符串

复制代码
varchar(L)

varchar(L):可变长度字符串,L 表示字符长度,最大长度 65535 个字节。

注意这里的措辞:最大 65535 个字节------不是字符!这就是要命的地方。

课件专门解释了:

关于 varchar(len),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 字节)。

翻译成一张表:

编码 一个字符占几字节 varchar(n) 的 n 上限
utf8 3 21844
gbk 2 32766

验证实验:

复制代码
mysql> create table tt11(name varchar(21845)) charset=utf8;   -- 验证了 utf8 确实不能超过 21844
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. You have to change some columns to TEXT or BLOBs

mysql> create table tt11(name varchar(21844)) charset=utf8;
Query OK, 0 rows affected (0.01 sec)

21845 报错、21844 通过,刚好卡在 21844。

为什么? 因为 21844 × 3 = 65532(减去记录长度的 1-3 字节),再加上其他开销就超过 65535 的单行上限了。

5.3 案例:varchar 能存多少就看定义

复制代码
mysql> create table tt10(id int ,name varchar(6));   -- 表示这里可以存放 6 个字符
mysql> insert into tt10 values(100, 'hello');
mysql> insert into tt10 values(100, '我爱你,中国');
mysql> select * from tt10;
+------+--------------------+
| id   | name               |
+------+--------------------+
|  100 | hello              |
|  100 | 我爱你,中国       |
+------+--------------------+
2 rows in set (0.00 sec)

varchar(6) 存 '我爱你,中国'------数一下字符:我(1)爱(2)你(3),(4)中(5)国(6),正好 6 个字符,所以能存。

📌 再次强调 :varchar(6) 的 6 是字符数,不是字节数。中文也算 1 个字符。

5.4 char vs varchar:到底差在哪

对比项 char(L) varchar(L)
长度 固定 L 个字符 可变,最多 L 个字符
单位 字符 字符(但底层按字节算上限)
最大 255 个字符 utf8 下 21844 、gbk 下 32766
空间 总是占用 L 个字符的空间(不够会补空格) 按实际长度占用 + 1-2 字节记录长度
效率 高(长度固定,定位快) 稍低(要先读长度)
适合 长度固定的数据 长度不定的数据

课件对选择的总结非常到位:

如何选择定长或变长字符串?

  • 如果数据确定长度都一样 ,就使用定长(char) ,比如:身份证、手机号、md5

  • 如果数据长度有变化 ,就使用变长(varchar) ,比如:名字、地址,但是你要保证最长的能存的进去。

  • 定长的磁盘空间比较浪费,但是效率高。

  • 变长的磁盘空间比较节省,但是效率低。

  • 定长的意义是:直接开辟好对应的空间。

  • 变长的意义是:在不超过自定义范围的情况下,用多少,开辟多少。

打个比方:

  • char(10) 像一排固定 10 个格子的收纳盒。你放 3 个东西,剩下 7 个格子空着,但盒子大小不变;
  • varchar(10) 像一个能撑到 10 格的弹性袋子。放 3 个就只占 3 格,但袋子本身要记一下"我现在装了 3 格"(那 1-2 字节) 。

5.5 实战选择建议

数据 选什么 理由
身份证号 char(18) 固定 18 位
手机号 char(11) 固定 11 位
密码 md5 char(32) 固定 32 位
姓名 varchar(20) 有人 2 字有人 20 字
地址 varchar(200) 长短差别巨大
邮箱 varchar(100) 长度不定
文章正文 text 超过 varchar 上限

六、日期和时间类型

6.1 三个常用类型

类型 格式 范围 占用
date 'yyyy-mm-dd' 日期 3 字节
datetime 'yyyy-mm-dd HH:ii:ss' 1000 ~ 9999 年 8 字节
timestamp 时间戳(从 1970 年开始),格式与 datetime 完全一致 1970 ~ 2038 4 字节

6.2 关键区别:timestamp 会"自动干活"

复制代码
mysql> create table birthday (t1 date, t2 datetime, t3 timestamp);
Query OK, 0 rows affected (0.01 sec)

-- 只插前两列,第三列不填
mysql> insert into birthday(t1,t2) values('1997-7-1','2008-8-8 12:1:1');
Query OK, 1 row affected (0.00 sec)

mysql> select * from birthday;
+------------+---------------------+---------------------+
| t1         | t2                  | t3                  |
+------------+---------------------+---------------------+
| 1997-07-01 | 2008-08-08 12:01:01 | 2017-11-12 18:28:55 |
+------------+---------------------+---------------------+
1 row in set (0.00 sec)

注意 t3(timestamp)那一列:添加数据时,时间戳自动补上当前时间(虽然我们没给它赋值)。

再看更新:

复制代码
mysql> update birthday set t1='2000-1-1';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from birthday;
+------------+---------------------+---------------------+
| t1         | t2                  | t3                  |
+------------+---------------------+---------------------+
| 2000-01-01 | 2008-08-08 12:01:01 | 2017-11-12 18:32:09 |
+------------+---------------------+---------------------+
1 row in set (0.00 sec)

更新数据时,时间戳会更新成当前时间 (对比一下:18:28:55 → 18:32:09,变了)。

而 t2(datetime)纹丝不动。

6.3 三个类型的适用场景

类型 适合 特点
date 生日、入职日期 只要日期,不要时分秒
datetime 订单创建时间、预约时间 需要精确到秒,且不会自己变
timestamp created_at、updated_at 省空间(4字节)、自动维护 ,但2038 年就溢出了

打个比方:

  • datetime 是你手写在纸上的时间,写多少就是多少,不会自己变;
  • timestamp 是一块自动盖章的电子钟,你不填它自己盖当前时间,你每次改这张纸它又盖一次。

6.4 ⚠️ 2038 问题

timestamp 占 4 字节,最大只能表示到 2038-01-19 03:14:07(因为 32 位有符号整数溢出了)。

📌 现在很多新项目直接用 datetime 或 bigint(存毫秒时间戳)来避开这个坑。老系统里这个雷是真实存在的。


七、enum 和 set:单选与多选

这两个很像,区别就一个:能选几个。

7.1 enum:单选

复制代码
enum('选项1','选项2','选项3',...)

enum:枚举,"单选"类型。 该设定只是提供了若干个选项的值,最终一个单元格中,实际只存储了其中一个值 ;而且出于效率考虑,这些值实际存储的是"数字" ------这些选项的每个选项值依次对应如下数字:1,2,3,... ,最多 65535 个。 当我们添加枚举值时,也可以添加对应的数字编号。

打个比方 :这就是一道单选题,A/B/C/D 只能选一个;而且系统内部把 A 记作 1、B 记作 2......

7.2 set:多选

复制代码
set('选项值1','选项值2','选项值3', ...)

set:集合,"多选"类型。 该设定只是提供了若干个选项的值,最终一个单元格中,可以存储其中任意多个值 ;而且出于效率考虑,这些值实际存储的是"数字" ------每个选项值依次对应:1,2,4,8,16,32,...,最多 64 个。

注意数字规律 :enum 是 1,2,3,4(连续),set 是 1,2,4,8,16(2 的幂)!

为什么?因为 set 要用二进制位表示"选了哪几个":

选项 对应位 数字
登山 第 1 位 1
游泳 第 2 位 2
篮球 第 3 位 4
武术 第 4 位 8

选了"登山+武术" → 1 + 8 = 9(二进制 1001)。一个数字就表达了多选组合,非常省空间。

📌 课件提到"想想 Linux 权限"------没错,这和 Linux 的 755 权限(r=4, w=2, x=1 相加)是同一个思路。

7.3 完整案例

复制代码
mysql> create table votes(
    -> username varchar(30),
    -> hobby set('登山','游泳','篮球','武术'),   -- 注意:使用数字标识每个爱好时,想想 Linux 权限,采用比特位位置
    -> gender enum('男','女'));                 -- 注意:使用数字标识的时候,就是正常的数组下标
Query OK, 0 rows affected (0.02 sec)

插入数据:

复制代码
insert into votes values('雷锋', '登山,武术', '男');
insert into votes values('Juse','登山,武术',2);     -- gender 用数字 2 表示"女"

查询:

复制代码
mysql> select * from votes where gender=2;
+----------+---------------+--------+
| username | hobby         | gender |
+----------+---------------+--------+
| Juse     | 登山,武术     |女      |
+----------+---------------+--------+

用数字 2 也能匹配到 enum 的第二个值"女"。

7.4 一个重要建议

说明:不建议在添加枚举值、集合值的时候采用数字的方式,因为不利于阅读。

理由很简单:三个月后你看到 gender=2,得回去数"男是1、女是2",还不如直接看 gender='女' 清楚。

7.5 set 的查询坑(重点)

有一个调查表,数据如下:

复制代码
+-----------+---------------+--------+
| username  | hobby         | gender |
+-----------+---------------+--------+
| 雷锋      | 登山,武术     | 男     |
| Juse      | 登山,武术     | 女     |
| LiLei     | 登山          | 男     |
| LiLei     | 篮球          | 男     |
| HanMeiMei | 游泳          | 女     |
+-----------+---------------+--------+

错误写法:直接等于

复制代码
mysql> select * from votes where hobby='登山';
+----------+--------+--------+
| username | hobby  | gender |
+----------+--------+--------+
| LiLei    | 登山   | 男     |
+----------+--------+--------+

不能查询出所有爱好为登山的人! 因为它只匹配"hobby 的值恰好等于 '登山'"的那一行,而 '登山,武术' 不是 '登山'。

正确写法 :用 find_in_set

复制代码
find_in_set(sub, str_list)

如果 sub 在 str_list 中,则返回下标 ;如果不在,返回 0 ;str_list 是用逗号分隔的字符串。

先验证函数行为:

复制代码
mysql> select find_in_set('a', 'a,b,c');
+---------------------------+
| find_in_set('a', 'a,b,c') |
+---------------------------+
|                         1 |
+---------------------------+

mysql> select find_in_set('d', 'a,b,c');
+---------------------------+
| find_in_set('d', 'a,b,c') |
+---------------------------+
|                         0 |
+---------------------------+

再查:

复制代码
mysql> select * from votes where find_in_set('登山', hobby);
+----------+---------------+--------+
| username | hobby         | gender |
+----------+---------------+--------+
| 雷锋     | 登山,武术     | 男     |
| Juse     | 登山,武术     | 女     |
| LiLei    | 登山          | 男     |
+----------+---------------+--------+

三行全出来了,这才是想要的结果。

打个比方 :hobby='登山' 是"你的购物清单必须只有 登山这一项";find_in_set('登山', hobby) 是"你的购物清单里包含登山"。前者太严格,后者才是你要的。


八、一张表总结所有类型

大类 类型 大小/范围 典型用途 一句话
整型 tinyint -128127 / 0255 年龄、状态码 小数字
int ±21 亿 ID、数量 最常用
bigint 极大 大数据量 ID、时间戳 装不下就用它
位 bit(M) 1~64 位 布尔开关 按 ASCII 显示
小数 float(m,d) 4 字节,精度约 7 位 坐标、评分 快但不准
decimal(m,d) 精度 m≤65、d≤30 金额 准但稍慢
字符串 char(L) ≤255 字符,定长 身份证、手机号、md5 固定格子
varchar(L) utf8 下 ≤21844 字符,变长 姓名、地址、邮箱 弹性袋子
text 更大 文章正文 大文本
时间 date 3 字节 生日 只要日期
datetime 8 字节 订单时间 手写时间
timestamp 4 字节 created_at 自动盖章,2038 溢出
选择 enum 最多 65535 个 性别、状态 单选
set 最多 64 个 爱好、标签 多选(位运算)

九、易错点速记

误解 正确理解
整型默认无符号 默认有符号 ,无符号要写 unsigned
越界会截断 大多直接报错 (Out of range)
bit 会显示数字 显示的是 ASCII 字符 (65 显示成 A)
float(4,2) 表示 4 位整数 表示总共 4 位,范围 -99.99~99.99
float 和 decimal 差不多 精度差很多,金额必须用 decimal
varchar(10) 能存 10 个字节 是 10 个字符,utf8 下要占 30 字节
varchar 上限 65535 utf8 下实际只能 21844,gbk 下 32766
char(2) 存不下"中国" 能存,单位是字符不是字节
timestamp 和 datetime 一样 timestamp 自动补/更新时间,且 2038 溢出
hobby='登山' 能查所有喜欢登山的人 不能,要用 find_in_set('登山', hobby)
enum 的数字是 1,2,4,8 enum 是 1,2,3,4 ;set 才是 1,2,4,8

十、本篇小结

  • 类型决定空间、范围、精度,选错会报错或者算错账。
  • 整型默认有符号;unsigned 只是翻倍,长得用好 bigint,别迷信 unsigned。
  • bit 省空间但显示成 ASCII 字符,适合 0/1 开关。
  • float 不准,decimal 准 ------金额一律 decimal。
  • char 定长(≤255 字符,效率高但浪费空间),varchar 变长(utf8 下 ≤21844 字符,省空间但稍慢);身份证/手机号/md5 用 char,姓名/地址用 varchar。
  • date / datetime / timestamp 按需选;timestamp 会自动维护但有 2038 问题。
  • enum 单选、set 多选;set 的数字是 2 的幂(位运算),查询多选值要用 find_in_set。
相关推荐
酷炫码神2 小时前
Day 10|Pinia 状态管理:把散落在各组件的数据,收进一个全局仓库
android·开发语言·javascript
造火箭3 小时前
安卓不同类型自动化测试介绍
android
汪海游龙6 小时前
流式回复结尾的那一下闪:逐帧定位 Compose 聊天列表的三处布局跳动
android·性能优化·kotlin
2501_915909068 小时前
Ipa Guard 防护上架,混淆、重签名和回归测试怎么做
android·ios·小程序·https·uni-app·iphone·webview
码点9 小时前
Android ANR 全解析 与 traces 分析实战
android
敲代码的瓦龙10 小时前
Jetpack?lifecycle!!!
android·kotlin
苦瓜花10 小时前
Hilt用使用及原理
android
深度学习040711 小时前
MySQL InnoDB Cluster 部署完整文档
android·mysql·adb
邪修king12 小时前
Re:Linux系统篇(三十七):进程间通信Chapter4:System V 共享内存深度解析:为什么它是最快的 IPC?
android·linux·运维