数据类型 1. 常用数据类型一览 分类 数据类型 说明 数值类型 BIT(M) 位类型。M 指定位数,默认值 1,范围 1–64。 TINYINT [UNSIGNED] 很小的整数。带符号范围:-128 ~ 127;无符号范围:0 ~ 255。默认为有符号。 BOOL / BOOLEAN 布尔类型,是 TINYINT(1) 的同义词,0 表示 FALSE,非 0 表示 TRUE。 SMALLINT [UNSIGNED] 小整数。带符号范围:-32,768 ~ 32,767;无符号范围:0 ~ 65,535。 INT / INTEGER [UNSIGNED] 最常用的整数类型 。带符号范围:-2,147,483,648 ~ 2,147,483,647;无符号范围:0 ~ 4,294,967,295。BIGINT [UNSIGNED] 大整数。带符号范围:-9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807;无符号范围:0 ~ 18,446,744,073,709,551,615。 FLOAT(M,D) [UNSIGNED] 单精度浮点数。M 为总位数,D 为小数位数。占用 4 字节。存在精度误差。 DOUBLE(M, D) [UNSIGNED] 双精度浮点数。比 FLOAT 精度更高,占用 8 字节。 DECIMAL(M,D) [UNSIGNED] 定点数(高精度 )。M 为总位数,D 为小数位数。用于 货币、金额计算 ,不会产生精度误差。 字符串与二进制类型 CHAR(size) 定长字符串,最大长度 255 字符。不足部分用空格填充。性能稳定但浪费空间。 VARCHAR(size) 最常用字符串类型 ,可变长度字符串,最大 65,535 字符。节省空间,性能较好。TEXT 长文本对象,最大 65,535 字符。不支持默认值 。 TINYTEXT / MEDIUMTEXT / LONGTEXT 不同大小的文本类型,最大长度分别为 255、16MB、4GB。 BLOB 二进制大对象,用于存储图片、文件、音频等。 TINYBLOB / MEDIUMBLOB / LONGBLOB 不同大小的二进制对象类型。 时间日期类型 DATE 日期类型,格式 YYYY-MM-DD,范围 '1000-01-01' ~ '9999-12-31'。 DATETIME 最常用时间类型 ,格式 YYYY-MM-DD HH:MM:SS,范围 '1000-01-01 00:00:00' ~ '9999-12-31 23:59:59'。不受时区影响。TIMESTAMP 时间戳类型,格式 YYYY-MM-DD HH:MM:SS,范围 '1970-01-01 00:00:01' UTC ~ '2038-01-19 03:14:07' UTC。受时区影响,插入/更新自动设置当前时间。 TIME 时间类型,格式 HH:MM:SS 或 HHH:MM:SS(可表示超过 24 小时的时间)。 YEAR 年份类型,可为 2 位或 4 位数字格式(推荐 4 位)。 字符串枚举类型 ENUM(‘v1’,’v2’,…) 枚举类型,列值必须是预定义列表中的一个值。内部按数字存储。节省空间但灵活性差。 SET(‘v1’,’v2’,…) 集合类型,可同时存储多个预定义值(以逗号分隔)。每个成员值本身不能含逗号。
1. 补充说明 项 说明 [UNSIGNED] 表示无符号数,只能存储正数和零。 M, D 参数 在 FLOAT、DOUBLE 中:M 为显示宽度,D 为小数位数;在 DECIMAL 中:M 为总位数,D 为小数位数。 size 参数 对于 CHAR、VARCHAR,表示 字符数 而非字节数。UTF8 编码下一个字符占 1–3 字节,UTF8MB4 下占 1–4 字节。 TIMESTAMP 特性 默认在插入或更新时自动设为当前时间,受服务器时区影响。 ENUM / SET 内部存储 虽然是字符串类型,但内部以整数映射存储,在性能上优于 VARCHAR,但修改枚举值需要重建表。
2. 实际开发常用推荐表 场景 推荐数据类型 理由 主键、自增 ID BIGINT UNSIGNED 足够大、可自增,不会溢出。 数量、状态码 INT / TINYINT 占用少,查询快。 金额、精确计算 DECIMAL(10,2) 高精度,避免浮点误差。 姓名、标题 VARCHAR(100) 适合变长字符串。 内容、备注 TEXT 存放长文本。 日期时间 DATETIME 直观、不受时区影响。 更新时间 TIMESTAMP 自动更新特性方便日志记录。 性别、状态、类型 ENUM 固定选项值,节省空间。
2. 数值类型 1. tinyint 类型 1. 作用 TINYINT 是 MySQL 中 最小的整数类型 ,常用于存储范围较小的整数值(例如状态标识、布尔值、性别、等级、标志位等)。它只占用 1 个字节(8 位) 存储空间,因此在性能和空间利用上非常高效。
2. 数据范围 类型 取值范围 tinyint(有符号) -128 ~ 127 tinyint unsigned(无符号) 0 ~ 255
UNSIGNED 关键字用于声明“无符号整数”,即不存储负数,范围翻倍。
3. 基本使用 inyint 类型占用 1 字节,有符号 tinyint 的取值范围为 -128~127,插入该范围内的数据时都能成功插入,如果插入的数据不在 -128~127 范围内,那么插入数据时就会产生报错:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 # 创建表 t1,字段 num 类型为 tinyint(默认有符号) create table t1( num tinyint ); # 插入范围内的数据(100 在 -128 ~ 127 之间,成功) insert into t1 values (100 );# 插入有符号 tinyint 的最小值(-128 ,成功) insert into t1 values (-128 );# 插入超出范围的数据(-129 小于最小值 -128 ,报错) insert into t1 values (-129 );ERROR 1264 (22003 ): Out of range value for column 'num' at row 1 # 查询表 t1 中的数据,验证插入结果 select * from t1;+ | num | + | 100 | | -128 | +
由于 tinyint 类型占用 1 字节,因此无符号 tinyint 的取值范围为 0255,插入该范围的数据时都能成功插入。如果插入的数据不在 0255 范围内,那么插入数据时就会产生报错:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 # 创建表 t2,字段 num 类型为 tinyint unsigned(无符号,范围 0 ~ 255 ) create table t2( num tinyint unsigned ); # 插入范围内的数据(100 在 0 ~ 255 之间,成功) insert into t2 values (100 );# 插入负数(-1 小于 0 ,无符号不允许负数,报错) insert into t2 values (-1 );ERROR 1264 (22003 ): Out of range value for column 'num' at row 1 # 插入超出最大值的数据(256 大于 255 ,报错) insert into t2 values (256 );ERROR 1264 (22003 ): Out of range value for column 'num' at row 1 # 插入无符号 tinyint 的最大值(255 ,成功) insert into t2 values (255 );# 查询表 t2 中的数据,验证插入结果 select * from t2;+ | num | + | 100 | | 255 | +
4. 表示布尔值(最常见) 1 2 3 4 5 6 7 # tinyint 的常见用途:表示布尔值(0 代表 false ,1 代表 true ) # 例如创建一个表示"是否启用"的字段,用 tinyint 存储更节省空间 create table status_table( is_enabled tinyint # 0 = 禁用,1 = 启用 ); is_active TINYINT(1 ) DEFAULT 1 COMMENT '是否启用:0=禁用,1=启用' ;
说明一下:MySQL 本身是不支持 bool 类型的,当把一个数据设置成 bool 类型时,数据库会自动将其转换成 tinyint(1) 的数据类型,其实这个就是变相的 bool 类型,因为 tinyint(1) 只有 1 和 0 两种取值,可以分别对应 bool 类型的 true 和 false。
TINYINT(1) 实际上与 BOOL / BOOLEAN 等价;存储时底层仍是整数,0 表示 FALSE,非 0 表示 TRUE; 建议在逻辑字段中统一约定:0 = 否,1 = 是。 5. 表示小范围状态码 适用于枚举值较少的场景(如状态、类型、标志),取值有限时优先用 TINYINT 而不是 INT,节省空间。
1 status TINYINT UNSIGNED DEFAULT 0 COMMENT '状态:0=未开始,1=进行中,2=已完成' ;
6. 作为计数或等级字段 1 level TINYINT UNSIGNED DEFAULT 1 COMMENT '等级:1~10' ;
适合范围小的整数类型,如用户级别、权限等级、重试次数等。
7. 注意事项 项目 说明 (1) TINYINT(1) 中的数字 1 不是长度限制 ,而是“显示宽度”,几乎无效。从 MySQL 8.0.17 起被完全废弃。(2) 若定义为 UNSIGNED,再插入负数会报错或被截断为 0。 (3) TINYINT 与 BOOLEAN 只是语法同义词,底层存储一样。(4) 若需要表示超过 ±128 的范围,建议改用 SMALLINT 或 INT。 (5) 对布尔字段建立索引意义不大(因为区分度太低)。
8. 详细示例 1 2 3 4 5 6 CREATE TABLE user_status ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID' , is_active TINYINT(1 ) DEFAULT 1 COMMENT '是否启用:0=否,1=是' , status TINYINT UNSIGNED DEFAULT 0 COMMENT '状态:0=未激活,1=已激活,2=冻结' , level TINYINT UNSIGNED DEFAULT 1 COMMENT '等级:1~10' ) ENGINE= InnoDB DEFAULT CHARSET= utf8mb4 COMMENT= '用户状态信息表' ;
执行:
输出示例:
1 2 3 4 5 6 7 8 + | Field | Type | Null | Key | Default | Extra | + | id | int (11 ) | NO | PRI | NULL | auto_increment | | is_active | tinyint(1 ) | YES | | 1 | | | status | tinyint unsigned | YES | | 0 | | | level | tinyint unsigned | YES | | 1 | | +
2. bit 类型 一个 TINYINT 存一个状态,而一个 BIT(8) 可以在一个字节中同时存 8 个二进制标志。
1. 作用 BIT 类型用于存储 二进制位数据(bit data) ,常用于表示 标志位、状态开关、权限标识、布尔组合等场景 。它能更高效地存储多个开关量,相当于一组二进制“位标志位数组”。
2. 数据范围 项目 说明 M 表示位数,取值范围为 1–64 。如果省略,默认为 1。 存储空间 每 8 位占用 1 字节(向上取整)。 值范围 可存储从 0 到 2^M - 1 的整数值。
MySQL 类型 位数 存储空间 C 语言类比 取值范围(有符号) BIT(1)1 位 约 1 位(实际存储会按字节对齐,通常占 1 字节) unsigned char(低 1 位)0 ~ 1 BIT(4)4 位 约 4 位(实际存储占 1 字节) unsigned char(低 4 位)0 ~ 15 BIT(8)8 位 1 字节 unsigned char0 ~ 255 BIT(16)16 位 2 字节 unsigned short0 ~ 65,535 BIT(32)32 位 4 字节 unsigned int0 ~ 4,294,967,295 BIT(64)64 位 8 字节 unsigned long long0 ~ 18,446,744,073,709,551,615
3. 基本使用 1 2 3 4 5 6 7 mysql> create table t3 (id int ,num bit(8 )); # 定义 num 为 8 位的 bit 类型 mysql> insert into t3 values (10 ,10 ); # 插入十进制 10 ,自动转为 8 位二进制 00001010 # 也可以用二进制格式插入等价数据: insert into t3 values (11 , b'00001010' ); # 二进制 00001010 等价于十进制 10 insert into t3 values (12 , 0 b00001010); # 0 b 前缀也表示二进制
直接查询 bit 类型字段时,MySQL 会默认以 十六进制字符串 显示,如果想查看十进制或二进制值,需用函数转换:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 # 示例查询结果(默认十六进制) select * from t3;+ | id | num | + | 10 | 0x0A | # 0x0A 是十六进制,对应二进制 00001010 + # 用 hex() 函数显式查看十六进制(和默认一致),语法:select id, hex(num) from 表名; mysql> select id, hex(num) from t3; # 结果:10 | 0 A + | id | hex(num) | + | 10 | A | | 11 | A | | 12 | A | + # 用 bin() 函数查看二进制(补全位数),语法:select id, bin(num) from 表名; mysql> select id, bin(num) from t3; # 结果:10 | 1010 (注意:MySQL 会省略前导 0 ,实际存储是 8 位 00001010 ) + | id | bin(num) | + | 10 | 1010 | | 11 | 1010 | | 12 | 1010 | + # 用 cast () 转换为十进制整数查看,语法:select id, cast (num as unsigned) from 表名; mysql> select id, cast (num as unsigned) from t3; # 结果:10 | 10 (转回十进制) + | id | cast (num as unsigned) | + | 10 | 10 | | 11 | 10 | | 12 | 10 | +
4. 存储布尔值或开关状态(节省空间) bit(1) 可存储 1 位二进制(0 或 1),适合表示布尔值(如 是否有效、开关状态 等),比 tinyint 更节省空间(1 位 vs 1 字节)。比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 mysql> create table t4 ( - > id int , - > gender bit(1 ) # 1 表示男,0 表示女 - > ); # 插入 id= 1 、性别为男(用 1 表示)的记录 mysql> insert into t4 values (1 , 1 ); # 插入 id= 2 、性别为女(用 0 表示)的记录 mysql> insert into t4 values (2 , 0 ); # 若插入非 0 / 1 的值(如 2 ),会报错(bit(1 ) 只能存 1 位二进制,范围 0 ~ 1 ) mysql> insert into t4 values (3 , 2 ); ERROR 1406 (22001 ): Data too long for column 'gender' at row 1 mysql> select * from t4; + | id | gender | + | 1 | 0x01 | | 2 | 0x00 | + # 用 cast (gender as unsigned) 转为十进制,再给列起别名 (如 gender_desc),结果更易理解 mysql> select - > id, - > cast (gender as unsigned) as gender_code, # 转十进制 后显示 0 / 1 (性别编码) - > case cast (gender as unsigned) # 用 case 语句将 0 / 1 转为具体文字(可选,更友好) - > when 1 then '男' - > when 0 then '女' - > end as gender_desc - > from t4; + | id | gender_code | gender_desc | + | 1 | 1 | 男 | | 2 | 0 | 女 | +
3. 小数类型 1. float 类型 1. 作用 float 是用于存储单精度浮点数的数值类型,主要用于表示带小数部分的数值(如身高、体重、温度等),其核心特点是 占用空间小、计算效率高 ,但精度有限(适用于对精度要求不高的场景)。
2. 数据范围 存储空间 :4 字节(32 位)。取值范围: 绝对值最大能达到接近 10^38^ 数量级。精度限制 :约 6~7 位有效数字(超过后可能产生精度丢失,这是浮点数的固有特性)。M:总位数 (整数部分 + 小数部分的总长度,范围 1~255)。D:小数位数 (小数点后的位数,范围 0~30,且 D 必须小于 M)。例如 float(5, 2) 表示:总长度 5 位,其中小数部分占 2 位,整数部分最多 3 位(可存储范围:-999.99 ~ 999.99)。如果省略 M 和 D(直接写 float),MySQL 会根据插入的数据自动分配存储空间(默认单精度,占用 4 字节)。
3. 基本使用 以 float(5, 2) 为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 # float (M,D) 中:M= 5 表示总位数(整数+ 小数共5 位),D= 2 表示小数部分占2 位 # 因此整数部分最多 3 位(5 -2 = 3 ),取值范围为 -999.99 ~ 999.99 create table t5(height float (5 ,2 ));# 插入 99.99 :整数部分2 位 + 小数2 位,总4 位(未超过5 位),符合范围 → 成功 insert into t5 values (99.99 );# 插入 -99.99 :负数同样遵循范围约束(-99.99 在 -999.99 ~ 999.99 之间)→ 成功 insert into t5 values (-99.99 );# 插入 1000.1 :整数部分4 位(1000 )+ 小数1 位,总位数超过5 位 → 超出范围,报错 insert into t5 values (1000.1 );ERROR 1264 (22003 ): Out of range value for column 'height' at row 1 # 插入 999.99 :整数部分3 位(999 )+ 小数2 位,总5 位(刚好达到上限)→ 成功 insert into t5 values (999.99 );# 插入 999.994 :小数部分实际3 位(994 ),定义为2 位 → 四舍五入后为999.99 (未超上限)→ 成功 insert into t5 values (999.994 );# 插入 999.995 :四舍五入后为1000.00 ,整数部分变为4 位(1000 ),总位数超过5 位 → 超出范围,报错 insert into t5 values (999.995 );ERROR 1264 (22003 ): Out of range value for column 'height' at row 1 # -999.995 需四舍五入到2 位小数:小数点后第3 位是5 ,向前进1 → 结果为 -1000.00 超过5 位限制 → 报错 insert into t5 values (-999.995 );ERROR 1264 (22003 ): Out of range value for column 'height' at row 1 # -999.994 四舍五入到2 位小数:小数点后第3 位是4 ,舍去 → 结果为 -999.99 符合 float (5 ,2 ) 约束 → 成功 insert into t5 values (-999.994 );
创建表 t6,定义 height 为 float(4,2) unsigned 进行演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 # float (4 ,2 ) 表示总位数≤4 ,小数部分固定2 位 → 整数部分最多2 位(4 -2 = 2 ) # unsigned 表示无符号 → 只能存储非负数(≥0 ) create table t6(height float (4 ,2 ) unsigned);# 插入 -0.1 :负数,违反 unsigned 无符号约束(只能存≥0 的值)→ 报错 insert into t6 values (-0.1 );ERROR 1264 (22003 ): Out of range value for column 'height' at row 1 # 插入 0 :0 是非负数,且总位数(0.00 ,整数0 位+ 小数2 位)符合 float (4 ,2 ) → 成功 insert into t6 values (0 );# 插入 -0.01 :负数,违反 unsigned 约束 → 报错 insert into t6 values (-0.01 );ERROR 1264 (22003 ): Out of range value for column 'height' at row 1 # 插入 99.94 :整数部分2 位(99 )+ 小数2 位 → 总位数4 ,且非负数 → 符合约束 → 成功 insert into t6 values (99.94 );# 插入 99.95 :整数部分2 位 + 小数2 位 → 总位数4 ,非负数 → 成功 insert into t6 values (99.95 );# 插入 99.99 :整数部分2 位 + 小数2 位 → 总位数4 ,非负数 → 成功(达到理论最大值) insert into t6 values (99.99 );# 插入 99.994 :需四舍五入到2 位小数 → 99.99 (整数2 位+ 小数2 位,总4 位)→ 成功 insert into t6 values (99.994 );# 插入 99.995 :四舍五入到2 位小数 → 100.00 (整数部分变为3 位,总位数= 3 + 2 = 5 >4 )→ 超出范围 → 报错 insert into t6 values (99.995 );ERROR 1264 (22003 ): Out of range value for column 'height' at row 1
2. decimal 类型 decimal 和 float 类型的使用方式 一模一样 ,但 decimal 的精度比 float 更高 。这里就不详细讲解,类比使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # 创建表 t7,定义两个字段: # n1 为 float (10 ,8 ):单精度浮点数,总位数10 位,小数部分8 位(整数部分最多2 位) # n2 为 decimal (10 ,8 ):高精度小数(定点数),总位数10 位,小数部分8 位(整数部分最多2 位) # 对比两者在存储精度上的差异 create table t7(n1 float (10 ,8 ),n2 decimal (10 ,8 ));# 插入相同的数值 3.1415926 (小数部分7 位)到两个字段 insert into t7 values (3.1415926 ,3.1415926 );Query OK, 1 row affected (0.00 sec) # 查询结果,观察精度差异: # n1(float 类型):存储结果为 3.14159250 ,与原始值有细微偏差(精度丢失) # 原因:float 是浮点数,用二进制近似存储,无法精确表示某些十进制小数,超过6 -7 位有效数字后会失真 # n2(decimal 类型):存储结果为 3.14159260 ,完全精确(补全8 位小数为9260 ) # 原因:decimal 是定点数,按十进制存储,能精确表示小数,适合对精度要求高的场景(如金额) select * from t7;+ | n1 | n2 | + | 3.14159250 | 3.14159260 | + 1 row in set (0.00 sec)
3. 字符串类型 1. char 类型 1. 作用 char 是一种 固定长度 的字符串类型,适用于存储长度固定或变化很小的字符串(如手机号、身份证号、性别标识等)。其核心特点是 存储空间固定,无论实际存储的字符串长度如何,都会占用预设的固定字节数。
2. 数据范围 L 表示字符串的长度(即最多能存储的字符数),范围是 0~255(单位:字符,不是字节)。例如 char(10) 表示该字段最多存储 10 个字符,无论实际插入的字符串是 1 个还是 10 个字符,都会占用 10 个字符对应的存储空间(具体字节数取决于字符集,如 UTF8 中一个字符可能占 1~3 字节)。 3. 基本使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 # 创建表 t8,定义 str 字段为 char (6 )(固定存储6 个字符) create table t8(str char (6 ));# 插入值时未用引号包裹"minbit",MySQL会误认为是列名,导致"未知列"错误,注意:字符串值必须用单引号('' )或双引号("")包裹 insert into t8 values (minbit);ERROR 1054 (42 S22): Unknown column 'minbit' in 'field list' # 用单引号包裹字符串"minbit"(长度6 个字符,刚好符合char (6 )的长度)→ 插入成功 insert into t8 values ('minbit' );# 用双引号包裹字符串"minbit"(效果同单引号,MySQL支持单/ 双引号表示字符串)→ 插入成功 insert into t8 values ("minbit");# 插入字符串"minbit1"(长度7 个字符,超过char (6 )定义的最大长度6 )→ 超长报错 insert into t8 values ("minbit1");ERROR 1406 (22001 ): Data too long for column 'str' at row 1 # 插入中文字符串"小米里的大麦"(长度6 个汉字,每个汉字按1 个字符计数,符合char (6 ))→ 成功 # 说明:char (L)中的L是"字符数",不是字节数,中文也按1 个字符算(具体字节数取决于字符集) insert into t8 values ("小米里的大麦");# 插入"小米里的大麦1"(6 个汉字+ 1 个字母,共7 个字符,超过6 )→ 超长报错 insert into t8 values ("小米里的大麦1");ERROR 1406 (22001 ): Data too long for column 'str' at row 1 # 插入字符串"1"(长度1 个字符,短于6 )→ 成功(MySQL会自动补5 个空格至6 个字符长度) insert into t8 values ("1");# 插入空字符串""(长度0 ,符合char (6 )允许的范围)→ 成功(存储6 个空格) insert into t8 values ("");# 查询表中数据,注意: # 1. 短于6 个字符的字符串(如"1"),查询时自动去除末尾填充的空格,显示原始长度 # 2. 空字符串显示为空白(实际存储6 个空格,查询时去除后为空) # 3. 刚好6 个字符的字符串(如"minbit"、"小米里的大麦")原样显示 select * from t8;+ | str | + | minbit | | minbit | | 小米里的大麦 | | 1 | | | +
2. varchar 类型 1. 作用 varchar 是一种 可变长度的字符串类型 ,适用于存储长度不固定或变化较大的字符串(如用户名、地址、备注等)。其核心特点是 存储空间随实际字符串长度变化 ,避免了固定长度类型(如 char)的空间浪费。
2. 数据范围 L 表示字符串的最大长度(最多能存储的字符数),范围根据 MySQL 版本和存储引擎有所不同(通常为 065535,实际受表中其他字段总长度限制),**注意:其中有 12 字节用来表示实际数据长度,还有 1 字节来存储其他控制信息,因此 varchar 类型的有效字节数最多是 65532 字节。**例如 varchar(50) 表示该字段最多存储 50 个字符,实际存储时会根据插入的字符串长度动态分配空间(不会像 char 那样固定占用 50 个字符的空间)。 注意: 在 MySQL 中,VARCHAR 类型的最大长度不是以“字符数”为上限,而是受 存储字节数 限制。理论上,单行数据总字节上限为 65535 字节 (含记录开销),因此 VARCHAR(L) 的最大值要根据字符集计算:例如在 utf8 编码下,一个字符最多占 3 字节,理论上 65532 ÷ 3 ≈ 21844,而在 gbk 编码下为 65532 ÷ 2 ≈ 32766。但在实际中,InnoDB 存储引擎 (尤其是默认 COMPACT 或 REDUNDANT 行格式)会对单个 VARCHAR 字段额外限制其最大存储字节数为 16383 字节 ,超出即报错:ERROR 1074 (42000): Column length too big for column 'str' (max = 16383); use BLOB or TEXT instead。比如下面是我的配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 # 查看指定表(如t9)的状态信息,\G表示按行垂直显示结果(更易读) mysql> SHOW TABLE STATUS LIKE 't9' \G * * * * * * * * * * * * * * * * * * * * * * * * * * * 1. row * * * * * * * * * * * * * * * * * * * * * * * * * * * Name: t9 # 表名 Engine: InnoDB # 存储引擎为InnoDB(MySQL默认的事务型引擎) Version: 10 # 表结构版本 Row_format: Dynamic # 行格式为Dynamic (InnoDB动态行格式,支持变长字段高效存储) Rows : 4 # 估算的行数(非精确值,InnoDB通过统计信息计算) Avg_row_length: 4096 # 平均每行占用的字节数(总数据长度/ 行数) Data_length: 16384 # 表数据占用的字节数(16384 字节= 16 KB,InnoDB最小分配单位) Max_data_length: 0 # 表可存储的最大数据量(InnoDB不限制,故为0 ) Index_length: 0 # 索引占用的字节数(该表无索引,故为0 ) Data_free: 0 # 已分配但未使用的空间(该表数据紧凑,故为0 ) Auto_increment: NULL # 自增字段的下一个值(该表无自增字段,故为NULL ) Create_time: 2025 -10 -10 15 :00 :57 # 表的创建时间 Update_time: 2025 -10 -10 15 :02 :17 # 表数据最后更新时间 Check_time: NULL # 最后一次检查表的时间(未检查过,故为NULL ) Collation : utf8mb4_general_ci # 表的默认字符集排序规则(utf8mb4编码对应的通用排序) Checksum: NULL # 表的校验和(未启用,故为NULL ) Create_options: # 创建表时的额外选项(无特殊选项,故为空) Comment: # 表的注释(无注释,故为空) # 查看数据库默认字符集(当前为utf8mb4,支持emoji和所有Unicode字符) mysql> SHOW VARIABLES LIKE 'character_set_database' ; + | Variable_name | Value | + | character_set_database | utf8mb4 | + # 查看数据库默认排序规则(utf8mb4_general_ci为utf8mb4的通用不区分大小写排序) mysql> SHOW VARIABLES LIKE 'collation_database' ; + | Variable_name | Value | + | collation_database | utf8mb4_general_ci | + # 查看InnoDB文件格式(MySQL 8.0 已移除该参数,默认使用Barracuda格式,故为空) mysql> SHOW VARIABLES LIKE 'innodb_file_format' ; Empty set (0.00 sec)# 查看InnoDB默认行格式(Dynamic 为动态行格式,适合存储变长字段,节省空间) mysql> SHOW VARIABLES LIKE 'innodb_default_row_format' ; + | Variable_name | Value | + | innodb_default_row_format | dynamic | + # 查看是否启用独立表空间(ON 表示每张表单独存储为.ibd文件,便于管理) mysql> SHOW VARIABLES LIKE 'innodb_file_per_table' ; + | Variable_name | Value | + | innodb_file_per_table | ON | + # 查看MySQL服务器版本(当前为8.0 .43 ,基于Ubuntu 22.04 系统) mysql> SELECT VERSION(); + | VERSION() | + | 8.0 .43 -0 ubuntu0.22 .04 .2 | + # 查看服务器默认字符集(与数据库一致,均为utf8mb4) mysql> SHOW VARIABLES LIKE 'character_set_server' ; + | Variable_name | Value | + | character_set_server | utf8mb4 | + # 查看服务器默认排序规则(与数据库一致,确保字符处理规则统一) mysql> SHOW VARIABLES LIKE 'collation_server' ; + | Variable_name | Value | + | collation_server | utf8mb4_general_ci | +
配置一览 当前配置 说明 MySQL 版本 8.0.43 新版 InnoDB,默认行格式已为 Dynamic 存储引擎 InnoDB 支持大字段分离存储 行格式 Dynamic 允许单行超出 8KB,字段可溢出页外存储 字符集 utf8mb4 每字符最多 4 字节 校验规则 utf8mb4_general_ci 默认排序规则 每表独立文件 ON 每张表独立存储,支持更大数据量
我的配置只能配置 varchar(16383)。
3. 基本使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 # 创建表 t9,定义 str 字段为 varchar (6 )(可变长度字符串,最大6 个字符) create table t9(str varchar (6 ));# 插入数值1 (未加引号,MySQL会自动转为字符串"1",长度1 ≤ 6 )→ 成功,说明:varchar 是字符串类型,插入数值时会隐式转换为字符串存储 insert into t9 values (1 );# 插入单引号包裹的字符串"minbit"(长度6 个字符,刚好达到 varchar (6 ) 的最大限制)→ 成功 insert into t9 values ('minbit' );# 插入双引号包裹的中文字符串"小米里的大麦"(长度6 个汉字,每个汉字按1 个字符计数,符合最大长度6 )→ 成功 # 注意:varchar (L) 中的 L 是字符数,中文、字母、数字均按1 个字符计算 insert into t9 values ("小米里的大麦");# 插入"小米里的大麦1"(6 个汉字+ 1 个数字,共7 个字符,超过 varchar (6 ) 的最大长度)→ 超长报错 insert into t9 values ("小米里的大麦1");ERROR 1406 (22001 ): Data too long for column 'str' at row 1 # 插入空值(未指定具体值,等价于插入 NULL 或空字符串,符合长度要求)→ 成功 # varchar 允许存储空值,此时不占用额外空间(仅存储长度标识) insert into t9 values ();# 查询 t9 表中的所有数据,观察 varchar (6 ) 字段的存储结果 select * from t9;+ | str | + | 1 | # 对应插入的数值1 ,自动转为字符串"1"(长度1 ,按实际长度存储)| minbit | # 插入的6 字符字符串,刚好达到varchar (6 )的最大长度,完整存储| 小米里的大麦 | # 插入的6 个汉字(6 字符),符合长度限制,完整存储(varchar 对中文按字符计数)| NULL | # 对应插入的空值(values ()),varchar 允许存储NULL ,显示为NULL (区别于空字符串"")+
3. char VS varchar 1. 功能与定义差异 特性 CHAR(L) VARCHAR(L) 存储方式 定长(固定长度) 变长(按实际长度存储) 最大存储上限 255 个字符 与字符集和表结构相关(utf8mb4 下约 16383 字符) 空间分配 无论实际存储多少字符,都占 L 个字符空间 仅占实际字符所需空间 + 1~3 字节长度信息 超出定义长度 报错 报错 是否需要额外字节 否 是(1~3 字节记录长度)
2. 性能与效率差异 对比项 CHAR VARCHAR 空间利用率 较低(浪费空间) 较高(按需分配) 访问效率 高(定长数据定位快) 稍低(需先解析长度字节) 更新效率 高(不易产生碎片) 低(长度变化可能导致页分裂) 适用场景 数据长度固定 数据长度不固定
4. 日期和时间类型 1. 常用的三种时间日期类型 类型 格式 占用空间 说明 DATE YYYY-MM-DD3 字节 只保存日期,不含时间。适合存储生日、入职日期等。 DATETIME YYYY-MM-DD HH:MM:SS8 字节 保存完整的日期与时间。与时区无关,适合通用业务时间记录。 TIMESTAMP YYYY-MM-DD HH:MM:SS4 字节 自动记录插入或更新时间,会受时区影响。常用于“创建时间”、“修改时间”等字段。
2. 基本使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 # 创建表 t10,包含三种日期时间类型: # t1: date (仅存储日期,格式YYYY- MM- DD) # t2: datetime(存储日期+ 时间,格式YYYY- MM- DD HH:MM:SS) # t3: timestamp (存储日期+ 时间,受时区影响,默认可自动更新) create table t10( t1 date , t2 datetime, t3 timestamp );Query OK, 0 rows affected (0.03 sec) # 查看表结构: # t3 字段类型为 timestamp ,但 Extra 列无特殊标识(默认不自动更新,需显式配置) desc t10;+ | Field | Type | Null | Key | Default | Extra | + | t1 | date | YES | | NULL | | | t2 | datetime | YES | | NULL | | | t3 | timestamp | YES | | NULL | | # 无 ON UPDATE CURRENT_TIMESTAMP ,故不自动更新+ # 插入时未用引号包裹日期时间值,MySQL 会解析为表达式(2025 -01 -01 被当作数学计算),导致语法错误 insert into t10 (t1,t2) values (2025 -01 -01 ,2025 -01 -01 00 :00 :00 );ERROR 1064 (42000 ): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '00:00:00)' at line 1 # 插入数据时,为 t1、t2 赋值(t3 未指定,默认为 NULL ) # 日期时间字符串需用单引号包裹,格式符合要求('YYYY-MM-DD' 或 'YYYY-MM-DD HH:MM:SS' ) mysql> insert into t10 (t1,t2) values ('2025-01-01' ,'2025-01-01 00:00:00' ); # 完整语句补全后 # 用双引号包裹日期时间字符串(效果同单引号),符合语法规则,插入成功 insert into t10 (t1,t2) values ("2025-01-01","2025-01-01 00:00:00");# 查询结果:t3 均为 NULL (因插入时未赋值,且未配置自动更新) select * from t10;+ | t1 | t2 | t3 | + | 2025 -01 -01 | 2025 -01 -01 00 :00 :00 | NULL | # t3 未赋值,保持 NULL | 2025 -01 -01 | 2025 -01 -01 00 :00 :00 | NULL | # t3 未赋值,保持 NULL +
注意:default current_timestamp on update current_timestamp 这类规则只能在 创建表时定义字段 或 修改表结构时 配置,不能在 insert 语句中直接使用!必须在 create table 或 alter table 时声明,属于表结构的一部分!创建表时配置规则 (推荐):
1 2 3 4 5 6 7 create table t11( t1 date , t2 datetime, t3 timestamp default current_timestamp on update current_timestamp # 定义时配置规则 ); insert into t11 (t3) values (default ); # 使用 t3 字段定义的默认值(当前时间)
对于已存在的表,用 alter table 补充规则:
1 2 3 alter table t11modify column t3 timestamp default current_timestamp on update current_timestamp ;
5. enum 和 set 1. enum 类型(枚举) enum 用于存储 “多选一” 的值,即字段值只能是预定义选项中的 一个 。
1. 数据范围 1 enum('值1' , '值2' , ..., '值n' )
选项列表最多支持 65535 个值(实际使用中通常远少于此),选项区分大小写(取决于表的字符集排序规则,如 utf8mb4_general_ci 不区分大小写,utf8mb4_bin 区分)。
2. 基本使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 # 创建表 t12,定义 gender 为 enum 类型(枚举,只能从预定义选项中选一个) # enum('男' ,"女",'未知' ) 表示可选值为 '男' 、'女' 、'未知' (单/ 双引号均可) create table t12( id int , gender enum('男' ,"女",'未知' ) ); # 插入符合 enum 选项的值(单/ 双引号包裹均可),均成功 insert into t12 values (1 ,'男' ), # 选 '男' (2 ,"女"), # 选 '女' (双引号) (3 ,'未知' ); # 选 '未知 # 插入未在 enum 选项中的值 ' 保密' → 不符合预定义范围,报错,错误提示:字段值被截断(实际因值不在选项中,无法存储) insert into t12 values (4,"保密"); ERROR 1265 (01000): Data truncated for column ' gender' at row 1 # 插入数字 1 → enum 支持用数字索引(从1开始)表示选项,1 对应第一个选项 ' 男' → 成功 insert into t12 values (4,1); # 插入数字 3 → 3 对应第三个选项 ' 未知' → 成功 insert into t12 values (4,3); # 插入数字 4 → enum 选项只有3个(索引1~3),4 超出范围 → 报错 insert into t12 values (4,4); ERROR 1265 (01000): Data truncated for column ' gender' at row 1 # 查询结果: # 数字索引会自动转换为对应的选项值(1→' 男',3→' 未知') select * from t12; +------+--------+ | id | gender | +------+--------+ | 1 | 男 | # 直接插入 ' 男' | 2 | 女 | # 直接插入 ' 女' | 3 | 未知 | # 直接插入 ' 未知' | 4 | 男 | # 插入 1 → 对应 ' 男' | 4 | 未知 | # 插入 3 → 对应 ' 未知' +------+--------+
2. set 类型(集合) set 用于存储 “多选多” 的值,即字段值可以是预定义选项中的 多个(0 个或多个) ,值之间用逗号分隔。
1. 数据范围 1 set ('值1' , '值2' , ..., '值n' )
选项列表最多支持 64 个值(因存储方式限制),选项同样区分大小写(规则同 enum)。
2. 基本使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 # 创建表 t13,定义 s 为 set 类型(集合,可从预定义选项中选多个值) # set ('吃饭' ,"睡觉",'打豆豆' ,"编码") 表示可选值为这4 个,支持多选(用逗号分隔) create table t13 ( id int , s set ('吃饭' ,"睡觉",'打豆豆' ,"编码") ); # 插入符合 set 规则的值(单/ 双引号均可): # 1. 选1 个值;2. 空值(选0 个);3. 选多个值(用逗号分隔);4. 选1 个值 insert into t13 values (1 ,'吃饭' ), (2 ,""), # 空字符串表示不选任何值 (3 ,"吃饭,睡觉,编码"), # 多选值用逗号分隔 (4 ,'编码' ); # 插入重复值 '吃饭,吃饭' → set 会自动去重,存储为 '吃饭' → 成功 insert into t13 values (5 ,'吃饭,吃饭' );# 插入未在 set 选项中的 '打游戏' → 不在预定义范围,报错 insert into t13 values (5 ,"打游戏");ERROR 1265 (01000 ): Data truncated for column 's' at row 1 # 插入数字 11 → set 支持用二进制位对应的数字表示选项(每个选项对应一个位,从左到右为 1 ,2 ,4 ,8. ..) # 选项对应关系:'吃饭' = 1 (2 ^ 0 )、'睡觉' = 2 (2 ^ 1 )、'打豆豆' = 4 (2 ^ 2 )、'编码' = 8 (2 ^ 3 ) # 11 = 8 + 2 + 1 → 对应 '吃饭,睡觉,编码' → 成功 insert into t13 values (5 ,11 );# 插入数字 10 → 10 = 8 + 2 → 对应 '睡觉,编码' → 成功 insert into t13 values (5 ,10 );# 插入数字 000 (即 0 )→ 0 表示不选任何值(等价于空字符串)→ 成功 insert into t13 values (5 ,000 );# 插入数字 0001 (即 1 )→ 1 对应 '吃饭' → 成功 insert into t13 values (5 ,0001 );# 插入数字 1111 → 该 set 只有4 个选项(最大对应数字 1 + 2 + 4 + 8 = 15 ),1111 超出范围(1111 是十进制4369 )→ 报错 insert into t13 values (5 ,1111 );ERROR 1265 (01000 ): Data truncated for column 's' at row 1 # 查询结果: mysql> select * from t13; + | id | s | + | 1 | 吃饭 | | 2 | | | 3 | 吃饭,睡觉,编码 | | 4 | 编码 | | 5 | 吃饭 | | 5 | 吃饭,睡觉,编码 | | 5 | 睡觉,编码 | | 5 | | | 5 | 吃饭 | +