【目录】
1.掌握数据类型分类
2.掌握使用常用数据类型
1.常用数据类型分类
在面向对象软件开发的过程中,通常会先进行需求分析,从而得到类和属性。类是面向对象中的概念,对应到数据库中的概念就是实体,类中的属性则对应实体中的属性。实体通常以表的形式存在,每个实体对应一张表,表中的每条记录(数据行)就是实体的一个实例,每条记录又包含若干字段(或称为列),每个字段代表实体的一个属性。如下图,每一行是实体的一个实例,而每一列又代表了实体的属性。
如果要定义实体的属性,就需要为属性命名并指定合适的数据类型。与其他编程语言类似,SQL 中也规定了用于描述属性的数据类型。常用的数据类型有以下几类:
- 数值类型
- 字符串类型
- 二进制类型
- 日期类型。
建议:数据类型不用死记细节,抓住“整数用 INT/BIGINT、金额用 DECIMAL、短字符串用 VARCHAR、长文本用 TEXT、时间用 DATETIME”这五个主力,就能覆盖绝大多数场景,剩下的知道有、用到再查即可——真正要记的是选型原则,而不是每个类型的字节数。
2.数值类型
2.1常用类型举例
1.整数类型
| 类型 | 大小 | 说明 |
|---|---|---|
| BIT[(M)] | 默认 1 bit | 位值类型。M 表示每个值的位数,取值范围为 1 ~ 64。如果省略 M,默认为 1。 |
| TINYINT[(M)] | 1 byte | 取值范围 -2^7 ~ 2^7-1,无符号取值范围 0 ~ 2^8-1。 |
| SMALLINT[(M)] | 2 byte | 取值范围 -2^15 ~ 2^15-1,无符号取值范围 0 ~ 2^16-1。 |
| MEDIUMINT[(M)] | 3 byte | 取值范围 -2^23 ~ 2^23-1,无符号取值范围 0 ~ 2^24-1。 |
| INT[(M)] | 4 byte | 取值范围 -2^31 ~ 2^31-1,无符号取值范围 0 ~ 2^32-1。 |
| INTEGER[(M)] | 4 byte | INT[(M)] 的同义词。 |
| BIGINT[(M)] | 8 byte | 取值范围 -2^63 ~ 2^63-1,无符号取值范围 0 ~ 2^64-1。 |
| BOOL | 1 byte | TINYINT(1) 的同义词。值为零被认为是false,非零值被认为是 true。 |
对于整数类型,我们不建议用M规定每个值的位数,原因是:M的作用是配合ZEROFILL,规定显示时最少几位,纯粹是个显示格式,对数据和存储毫无影响,而且已经被官方废弃。接下来进行讲解,了解即可。
比如:INT(4) 和 INT(6)都是四字节的存储的单位,只是在配合ZEROFILL时,进行打印会有差别。假设存储5,
- 如果配合ZEROFILL,那么INT(4)打印出来是0005,而INT(6)打印出来是000005
- 如果不配合ZEROFILL,那么打印出来仍是INT(4)和INT(6)打印出来都是5
- 而如果存储数据位数大于指定位数,比如INT(4)存储123456,那么无论有没有ZEROFILL,都会打印出123456
另外,对于无符号整数,我们可以指定为unsigned,但是不建议这么做。比如int存不下,那么unsigned int 也不一定存的下,与其这样,还不如升级为bigint。
2.浮点数类型
| FLOAT[(M,D)] | 4 byte | 单精度浮点型,M 是总位数,D 是小数点后面的位数,大约可以精确到小数点后 7 位。 |
| DOUBLE[(M,D)] | 8 byte | 双精度浮点型,M 是总位数,D 是小数点后面的位数,大约可以精确到小数点后 15 位。 |
浮点数类型与整数类型相似,它的(M,D)也是可以省略的,并且建议省略。其中M表示他可以存储浮点数的位数(这个位数指的是整数部分和小数部分相加和),而D则表示的是小数部分的位数,比如:
float(5,2)最大存储就是999.99,一旦超过这个数,那么就会报错。这与float最大能存多少无关,而是以M和D为主在日常开发中,凡
| 类型 | 大小 | 有符号最小值 | 有符号最大值 | 无符号最小值 | 无符号最大值 |
|---|---|---|---|---|---|
| TINYINT | 1 Byte | -128 | 127 | 0 | 255 |
| SMALLINT | 2 Byte | -32768 | 32767 | 0 | 65535 |
| MEDIUMINT | 3 Byte | -8388608 | 8388607 | 0 | 16777215 |
| INT | 4 Byte | -2147483648 | 2147483647 | 0 | 4294967295 |
| BIGINT | 8 Byte | -2^63 | 2^63-1 | 0 | 2^64-1 |
是涉及到精确数据,都不建议用float和double,而是用decimal:
| DECIMAL[(M,D)] | 动态 | 不存在精度损失,M 是总位数,D 是小数点后的位数。 DECIMAL 的最大位数(M)为 65,最大小数位数(D)为 30。如果省略 M,则默认为 10;如果省略 D,则默认为 0。 M 中不计算小数点和负数的负号,如果 D 为 0,则值没有小数点和小数部分。 |
对于decimal,它的(M,D)是强烈建议写的,原因如下:它同float和double并不一样,如果说它存储了一个12.45,默认的(10,0)意味着小数部分是0,会导致存储的时候存储成12,小数部分直接丢失,这是非常危险的。
另外,decimal是精确的,这得益于它的特殊存储机制:它并不把数据转换成二进制,而是以十进制的方式进行存储,这样就避免了因为转二进制而造成的精度丢失问题。
3.总结(M,D)
在常用的这些数值类型中,无论是整数的(M),亦或是浮点数的(M,D),都是不建议指定的,因为指定了可能会出问题,并且不指定的情况下,其用法就同java/c的编程语言一样用法,会根据真正的最大/最小数值进行判断存储。而decimal除外,强烈建议decimal进行指定。
2.2 常用数值类型的范围
3.字符串类型
3.1 char(n) 和 varchar(n)
这里的n表示的是可容纳字符个数的上限,例如char(10),表示最多能容纳长度为10的字符串,至于具体细节见下表
一、对比
| 对比项 | CHAR(n) | VARCHAR(n) |
|---|---|---|
| 长度性质 | 固定长度 | 可变长度 |
| 声明含义 | 固定 n 个字符 | 最多 n 个字符 |
| 实际字符数 | 永远 = n | 按输入,≤ n |
| 不够 n 时 | 自动补空格凑满 n | 不补 |
| 没用的空间 | 被空格占掉 | 不分配,不浪费 |
| 内容字节数 | 按补满后的 n 个字符算 | 按实际内容算 |
| 长度前缀(详解见后) | 无 | 1~2 字节(n≤255 用 1 字节,n>255 用 2 字节) |
| 总字节数 | n × 每字符字节数 | 实际内容字节 + 1~2 字节 |
| 超长时 | 报错或截断 | 报错或截断 |
| 存取性能 | 稍快(定长好定位) | 稍慢(变长需计算) |
| 最大长度 | 0~255 字符 | 0~65535 字节(受行上限限制) |
| n 是字符还是字节 | 字符数 | 字符数 |
| 适用场景 | 长度固定的短数据 | 长度不固定的数据 |
| 一句话 | 占满 n 个字符位,不够自动补空格 | 最多 n 个字符,用多少占多少,不预留 |
举例(utf8mb4 字符集)
| 存入内容 | CHAR(10) 实际占用 | VARCHAR(10) 实际占用 |
|---|---|---|
'abc' | 'abc '(10 字符,10 字节) | 'abc'(3 字符 + 1 字节前缀 = 4 字节) |
'中' | '中 '(10 字符,3+9 = 12 字节) | '中'(1 字符 + 1 字节前缀 = 4 字节) |
'abcdefghij' | 10 字符,10 字节 | 10 字符 + 1 字节前缀 = 11 字节 |
二、长度前缀总结
| 对比项 | 说明 |
|---|---|
| 是什么 | VARCHAR 每条记录里额外占的 1~2 字节,用来记录“这列实际占多少字节” |
| 为什么需要 | VARCHAR 是变长的,没有它 MySQL 就不知道每列读到哪算完,无法正确读取下一列 |
| 占几字节 | n ≤ 255 → 1 字节;n > 255 → 2 字节 |
| 存的是什么 | 实际内容的字节长度(注意:不是字符数,不计入字符个数) |
| CHAR 有吗 | 没有。CHAR 定长,读完 n 个字符就知道下一列在哪 |
| 是浪费吗 | 不是,是“可变长度”必须付出的代价 |
| 比喻 | CHAR 像固定大小的快递柜,不用贴标签;VARCHAR 像大小不一的包裹,必须贴标签写明多大 |
3.2 text系列
一、TEXT系列 与 VARCHAR 对比(以 TEXT 为典型)
| 对比项 | VARCHAR(n) | TEXT |
|---|---|---|
| 长度性质 | 可变,有上限 | 可变,有上限 |
| 上限 | 最多 n 个字符 | 最大 65,535 字节 |
| 能不能写 n | 必须写,如VARCHAR(100) | 不能写,写TEXT(100)无效 |
| 长度前缀 | 1~2 字节 | 1~4 字节 |
| 实际占用 | 实际内容 + 1~2 字节 | 实际内容 + 1~4 字节 |
| 默认值 | 可以有 | 不能有 |
短文本用 VARCHAR,长文本才用 TEXT 系列。
二、TEXT 系列总结
| 类型 | 最大长度(字节) | 换算 | 长度前缀 | 约存汉字数(utf8mb4) | 典型用途 |
|---|---|---|---|---|---|
| TINYTEXT | 255 | 2⁸ - 1 | 1 字节 | 约 85 个 | 极短文本、摘要 |
| TEXT | 65,535 | 2¹⁶ - 1 | 2 字节 | 约 21,845 个 | 文章、评论、日志 |
| MEDIUMTEXT | 16,777,215 | 2²⁴ - 1 | 3 字节 | 约 559 万个 | 长文章、大段 JSON |
| LONGTEXT | 4,294,967,295 | 2³² - 1 | 4 字节 | 约 14 亿个 | 书籍、原始数据 |
3.3 blob系列
一、BLOB 系列与 TEXT 系列对比(以 BLOB 和 TEXT 为典型)
| 对比项 | TEXT | BLOB |
|---|---|---|
| 存什么 | 文本(字符) | 二进制(字节) |
| 字符集 | 有 | 无 |
| 最大长度 | 65,535 字节 | 65,535 字节 |
| 长度前缀 | 2 字节 | 2 字节 |
| 实际字节数 | 按真实内容算 | 按真实内容算 |
| 数据库怎么理解 | 按字符集翻译成文字 | 当原始字节 |
| 校验 | 校验字节是否符合字符集 | 不校验,任意字节都能存 |
| 比较/排序 | 按字符集规则 | 按字节值 |
| 大小写转换 | 支持 | 不支持 |
| 算字符数 | CHAR_LENGTH()有效 | 只能算字节数 |
对应关系:
| TEXT 系列 | BLOB 系列 | 最大长度(字节) |
|---|---|---|
| TINYTEXT | TINYBLOB | 255 |
| TEXT | BLOB | 65,535 |
| MEDIUMTEXT | MEDIUMBLOB | 16,777,215 |
| LONGTEXT | LONGBLOB | 4,294,967,295 |
二、BLOB 系列总结
| 类型 | 最大长度(字节) | 换算 | 长度前缀 | 存什么 |
|---|---|---|---|---|
| TINYBLOB | 255 | 2⁸ - 1 | 1 字节 | 二进制数据 |
| BLOB | 65,535 | 2¹⁶ - 1 | 2 字节 | 二进制数据 |
| MEDIUMBLOB | 16,777,215 | 2²⁴ - 1 | 3 字节 | 二进制数据 |
| LONGBLOB | 4,294,967,295 | 2³² - 1 | 4 字节 | 二进制数据 |
三、差异的意义(具体例子了解即可)
核心意义一句话:让数据库知道“这堆字节到底是不是文字”,从而决定怎么处理它。
| 差异 | 意义 |
|---|---|
| 有字符集 vs 无字符集 | TEXT 能翻译成文字,BLOB 只当原始字节 |
| 按字符规则比较 vs 按字节值比较 | TEXT 能正确排序文字,BLOB 只能按字节排 |
| 支持大小写转换 vs 不支持 | TEXT 能UPPER(),BLOB 不能 |
| 能算字符数 vs 只能算字节数 | TEXT 的CHAR_LENGTH()有效,BLOB 不行 |
| 校验字节合法性 vs 不校验 | TEXT 会拒绝非法字节,BLOB 任意字节都能存 |
如果混用会出问题:
用 TEXT 存图片 → 字节可能不符合字符集,插入报错或图片损坏
用 BLOB 存文章 → 能存,但没法按字符处理,显示可能乱码
打个比方:
TEXT= 贴了“文字”标签的箱子,管理员会按文字方式整理
BLOB= 贴了“二进制”标签的箱子,管理员只按大小堆放,不解读内容
箱子本身一样大,但标签决定了管理员怎么处理它。
四、一句话总结
BLOB 系列和 TEXT 系列一一对应,最大长度完全相同(255、65535、16777215、4GB),区别只在于 TEXT 有字符集、按文字处理,BLOB 无字符集、按原始字节处理。这个区别的意义是让数据库知道数据是“文字”还是“二进制”,从而用正确的方式存储、比较和读取。
4.日期类型
一、五种类型分别什么时候用
| 类型 | 什么时候用 | 例子 |
|---|---|---|
| DATE | 只需要日期,不需要时间 | 生日、入职日期、发布日期 |
| TIME | 只需要时间,不需要日期 | 营业时间、课程时长、闹钟 |
| DATETIME | 需要日期 + 时间,日常场景 | 创建时间、订单时间、评论时间 |
| TIMESTAMP | 需要日期 + 时间,且跨时区或自动更新 | 跨时区系统、最后修改时间 |
| YEAR | 只需要年份 | 毕业年份、车型年份 |
三、DATETIME 和 TIMESTAMP 到底怎么选
| 场景 | 选哪个 | 原因 |
|---|---|---|
| 日常记录时间 | DATETIME | 范围大(1000~9999),不受时区影响 |
| 跨时区系统 | TIMESTAMP | 自动按时区转换 |
| 需要自动更新 | TIMESTAMP | 原生支持ON UPDATE CURRENT_TIMESTAMP |
| 需要范围超过 2038 年 | DATETIME | TIMESTAMP 只到 2038 年 |
| 需要存生日、很久以前 | DATETIME | TIMESTAMP 不支持 1970 以前 |
一句话:日常用 DATETIME,跨时区或自动更新用 TIMESTAMP。
四、记法口诀
| 需求 | 用哪个 |
|---|---|
| 只要日期 | DATE |
| 只要时间 | TIME |
| 日期 + 时间 | DATETIME |
| 跨时区、自动更新 | TIMESTAMP |
| 只要年份 |
|
五、一句话总结
只关心“哪一天”用 DATE,只关心“几点”用 TIME,关心“哪一天几点”用 DATETIME,跨时区或自动更新用 TIMESTAMP,只要年份用 YEAR。日常场景用 DATETIME,跨时区用 TIMESTAMP。
5.一句话总结常用类型
再次建议:数据类型不用死记细节,抓住“整数用 INT/BIGINT、金额用 DECIMAL、短字符串用 VARCHAR、长文本用 TEXT、时间用 DATETIME”这五个主力,就能覆盖绝大多数场景,剩下的知道有、用到再查即可——真正要记的是选型原则,而不是每个类型的字节数。