原创

MySQL 数据类型核心指南:选型、实战与避坑

MySQL 表设计里有一个很容易被低估的问题:字段类型选错,短期通常不会报错。

VARCHAR 能存数字,BIGINT 能存绝大多数 ID,DOUBLE 也能存金额,时间甚至可以直接塞进字符串。业务照样能跑,所以很多问题会被拖到数据量上来以后才暴露。

真正的代价往往出现在后面:索引变大、比较发生隐式转换、金额出现精度误差、时间范围不够、JOIN 用不上索引,甚至只是因为一个毫无必要的 BIGINT,让整张表的二级索引持续膨胀。

所以选数据类型不能只问一句:

这个类型能不能存下当前的数据?

更应该问:

它是否准确表达业务含义,并且用合理的空间支持未来几年的数据规模和查询方式?

下面按 MySQL 8.x 的常见业务场景来拆。

一、选数据类型时,真正要看这 5 件事

建字段之前,建议按这个顺序考虑:

  1. 数据本身是什么:数字、金额、字符串、时间还是结构化数据;
  2. 最大值和最小值可能到哪里;
  3. 是否要求精确计算;
  4. 这个字段以后会不会建索引、排序、JOIN;
  5. 未来数据量增长以后,当前类型是否还够用。

比如订单金额:

price DOUBLE

看起来完全能存。

但金额需要精确计算,应该优先考虑:

price DECIMAL(12, 2)

再比如手机号:

mobile BIGINT

虽然中国大陆手机号看起来像数字,但手机号实际上不是用来计算的数字,它是一个标识符。

更合理的是:

mobile VARCHAR(20)

以后碰到 +86、海外号码、前导 0,都不需要修改表结构。

这就是数据类型设计里最重要的一条判断标准:

按业务语义选择类型,而不是按数据长得像什么来选择。


二、整数类型:不要看到数字就上 BIGINT

MySQL 常见整数类型如下:

类型 字节数 SIGNED 范围 UNSIGNED 最大值
TINYINT 1 -128 ~ 127 255
SMALLINT 2 -32768 ~ 32767 65535
MEDIUMINT 3 -8388608 ~ 8388607 16777215
INT 4 约 -21.47 亿 ~ 21.47 亿 约 42.94 亿
BIGINT 8 约 ±922 亿亿 约 1844 亿亿

实际开发里最常用的是:

TINYINT
INT
BIGINT

状态字段优先考虑 TINYINT

例如订单状态:

0 待支付
1 已支付
2 已发货
3 已完成
4 已取消

没必要写成:

status INT NOT NULL

更合理的是:

status TINYINT UNSIGNED NOT NULL

整个业务只有几个状态,1 个字节已经绰绰有余。

类似的字段包括:

用户状态
审核状态
支付状态
删除标记
渠道类型
性别编码
业务类型

都可以优先考虑 TINYINTSMALLINT

主键到底用 INT 还是 BIGINT?

很多项目建表时已经形成肌肉记忆:

id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT

这当然省心,但并不是免费的。

INT 占 4 字节,BIGINT 占 8 字节。

单看主键多 4 字节似乎没什么,但 InnoDB 的二级索引叶子节点会保存主键值。

假设一张表有:

1 亿行数据
5 个二级索引

那么主键从 4 字节变成 8 字节,增加的并不只是主键索引本身。

二级索引也会跟着变胖。

这才是 BIGINT 真正的成本。

如果确定一张普通业务表生命周期内只有几百万甚至几千万条记录:

INT UNSIGNED

已经可以支持大约 42.9 亿个正整数。

但订单流水、日志、行为事件、消息记录这类持续高速增长的数据,直接使用:

BIGINT

通常更省后续迁移成本。

不要机械追求“小类型”,也不要无脑全部 BIGINT

先估数据规模。


三、SIGNED 和 UNSIGNED:省范围没问题,乱用才麻烦

比如用户 ID 不可能出现负数,于是很多表设计成:

user_id BIGINT UNSIGNED

从范围利用率来看没问题。

真正容易踩坑的是不同表定义不一致。

用户表:

id BIGINT UNSIGNED

订单表:

user_id BIGINT

一个是 UNSIGNED,一个是 SIGNED。

这种差异会给关联、外键定义、ORM 映射和数据迁移制造额外麻烦。

ID 类型最好从项目一开始就统一。

例如统一规定:

所有用户 ID:BIGINT UNSIGNED
所有订单 ID:BIGINT UNSIGNED
状态码:TINYINT UNSIGNED
普通计数器:INT UNSIGNED

比单独讨论某一个字段应该用不用 UNSIGNED 更重要。


四、BOOLEAN 并不是真正独立的布尔类型

MySQL 里:

BOOLEAN

实际上是:

TINYINT(1)

的同义词。

所以:

is_deleted BOOLEAN NOT NULL DEFAULT FALSE

本质上仍然是整数。

很多项目更愿意明确写:

is_deleted TINYINT UNSIGNED NOT NULL DEFAULT 0

约定:

0 = 否
1 = 是

这样数据库层面的含义反而更加直观。

另外不要把:

TINYINT(1)

里面的 1 理解成“只能保存一位数字”。

它不是范围限制。

TINYINT 能存什么值,由类型本身以及是否 UNSIGNED 决定。


五、金额字段:DECIMAL 和 DOUBLE 根本不是一回事

这是业务系统里最值得单独拿出来讲的类型问题。

FLOAT / DOUBLE 是近似值

浮点数使用二进制表示小数。

某些十进制小数不能被二进制浮点数精确表示,所以在连续计算以后可能出现类似:

99.9999999997
100.0000000003

科学计算、坐标、比例、测量值等允许误差的业务可以使用:

FLOAT
DOUBLE

但金额通常不应该。

例如:

amount DECIMAL(12, 2)

12 表示总有效数字位数,2 表示小数位数。

因此可以保存:

9999999999.99

常见金额字段

例如:

price DECIMAL(12, 2)
amount DECIMAL(12, 2)
balance DECIMAL(14, 2)

金额范围特别大的系统,可以根据实际业务扩大:

DECIMAL(18, 2)

如果涉及汇率、佣金率或者数字资产,可能需要更高的小数精度:

exchange_rate DECIMAL(18, 8)

甚至:

amount DECIMAL(36, 18)

关键不是统一用 DECIMAL(18,2),而是先确定:

整数最多多少位?
小数到底需要几位?

再确定 MD

金额存“分”也是一种方案

还有一种常见设计:

amount BIGINT

数据库里保存单位为“分”的整数。

比如:

¥12.34

保存:

1234

这种方案也可以完全避免浮点误差,而且整数计算非常直接。

但它有一个额外成本:所有调用方必须永远记住单位。

一旦有系统把“分”当成“元”,问题会非常严重。

所以普通电商、支付、财务业务里,使用:

DECIMAL

通常可读性更高。


六、CHAR、VARCHAR、TEXT,到底怎么选?

字符串是 MySQL 建表时最容易被滥用的一类类型。

最经典的设计大概是:

name VARCHAR(255)
mobile VARCHAR(255)
email VARCHAR(255)
order_no VARCHAR(255)
status VARCHAR(255)

能跑。

但这基本等于没有认真设计字段。

CHAR:长度基本固定

适合长度固定或者高度稳定的数据。

例如某些固定编码:

country_code CHAR(2)

如果业务中确实存在固定长度编号,也可以使用 CHAR

但不要因为身份证号“现在是固定长度”,就机械地认为所有证件字段都应该使用 CHAR。如果系统未来需要支持护照、港澳证件或者其他国家证件,业务语义已经变了。

VARCHAR:绝大多数普通字符串字段的主力

例如:

username VARCHAR(64)
nickname VARCHAR(64)
mobile VARCHAR(20)
email VARCHAR(128)
order_no VARCHAR(32)
title VARCHAR(200)

这里尤其容易出现一个误解:

VARCHAR(100)

这里的 100 对非二进制字符串来说主要表示最多保存多少个字符,不是简单理解成 100 个字节。

使用 utf8mb4 时,一个字符最多可能需要多个字节。

因此:

VARCHAR(1000)

理论占用空间和:

VARCHAR(50)

显然不是一个级别。

这会进一步影响:

行长度
索引长度
内存排序
临时表
网络传输

所以不要习惯性全部写 VARCHAR(255)

字段长度本身就是数据约束的一部分。


七、TEXT 不是“大号 VARCHAR”

文本比较长时可以考虑:

TEXT
MEDIUMTEXT
LONGTEXT

常见容量等级大致是:

TEXT        约 64 KB
MEDIUMTEXT  约 16 MB
LONGTEXT    约 4 GB

比如:

文章正文
商品详情
小说章节
Markdown 内容
长备注
富文本 HTML

适合使用 TEXT 系列。

例如:

content MEDIUMTEXT NOT NULL

但不要看到文本就直接 TEXT

如果字段只是:

昵称
标题
订单备注
标签名
地址

长度明显可控,优先使用 VARCHAR

原因不只是存储空间。

很多业务后面还会:

建立索引
排序
去重
分组
进行条件查询

可控长度的 VARCHAR 更容易处理。


八、不要把“数字字符串”设计成数字

下面这些数据看起来都是数字:

手机号
身份证号
银行卡号
邮政编码
商品编码
快递单号
企业编码

但它们并不是数学意义上的数字。

判断方法非常简单:

这个字段以后会不会进行加减乘除?

如果不会,大概率应该把它看成标识符。

例如邮政编码:

00100

如果存成:

INT

最终可能变成:

100

前导 0 丢了。

手机号同理。

所以:

mobile VARCHAR(20)

通常比:

mobile BIGINT

更合理。


九、DATETIME 和 TIMESTAMP,别只看名字

常见时间类型主要有:

DATE
DATETIME
TIMESTAMP
TIME

普通业务最常用的是前三种。

DATE

只需要日期:

2026-08-25

使用:

birthday DATE

不要为了统一方便,把生日写成:

DATETIME

然后永远保存:

2026-08-25 00:00:00

没有必要。

DATETIME

保存完整日期和时间:

2026-08-25 14:30:25

可以:

created_at DATETIME

如果需要毫秒:

created_at DATETIME(3)

例如:

2026-08-25 14:30:25.123

TIMESTAMP 最大的区别是时区转换

TIMESTAMP 与 MySQL 会话的 time_zone 有关系。

写入和读取过程中会进行 UTC 与当前会话时区之间的转换。

DATETIME 更像是把:

2026-08-25 14:30:25

这组日期时间值直接保存下来。

因此对于:

预约时间
会议时间
营业时间
计划执行时间

这类带有明确业务时间语义的数据,使用 DATETIME 往往更容易控制。

如果整个系统明确统一使用 UTC,并理解 MySQL 的时区行为,TIMESTAMP 也很好用。

问题不在于哪个绝对更好。

问题在于很多项目用了 TIMESTAMP,却根本没有统一服务器、数据库连接和应用层的时区配置。

这种情况下,时区 bug 通常比节省几个字节难查得多。

另外,传统 TIMESTAMP 还有著名的 2038 年时间范围问题。如果系统需要存储很远的未来日期,不要默认使用它。


十、时间不要轻易存 VARCHAR

这种设计最好避免:

created_at VARCHAR(32)

然后保存:

2026-08-25 12:30:22

因为接下来所有时间操作都会变麻烦:

WHERE created_at >= ?

时间函数:

DATE(created_at)

日期计算:

DATE_ADD(...)

月份统计:

YEAR(created_at)
MONTH(created_at)

本来数据库原生能处理的问题,现在全部变成字符串处理。

除非原始业务数据就是一个不规则时间字符串,否则数据库中的标准业务时间应该优先使用原生时间类型。


十一、时间戳要不要直接存 BIGINT?

有些系统喜欢保存 Unix Timestamp:

created_at BIGINT

例如:

1787630400000

优点是跨语言传输简单。

但数据库可读性会明显下降。

本来:

SELECT created_at
FROM orders;

直接可以看到:

2026-08-25 12:00:00

现在看到的是:

1787630400000

SQL 查询、运维排查、报表统计也都需要额外转换。

如果没有非常明确的架构理由,普通关系型业务表直接使用:

DATETIME

通常更舒服。


十二、ENUM:看起来优雅,业务变动以后未必优雅

例如:

status ENUM(
    'PENDING',
    'PAID',
    'SHIPPED',
    'FINISHED'
)

代码看起来很直观。

对于长期固定、几乎不发生变化的枚举集合,ENUM 并不是不能用。

但业务状态经常变化时,我更倾向:

status TINYINT UNSIGNED NOT NULL

应用代码维护:

0 = PENDING
1 = PAID
2 = SHIPPED
3 = FINISHED
4 = CANCELLED

原因很简单。

业务增加状态是应用发布里非常常见的一件事,不应该动不动就把它升级成数据库表结构变更。

如果希望数据库层面也具有可读性,可以再使用状态字典表,但不要为了“数据库里看起来舒服”牺牲业务迭代能力。


十三、JSON 很好用,但别拿它逃避表设计

MySQL 的 JSON 类型非常适合存储扩展属性。

例如不同订单来源存在不同的附加参数:

{
  "campaignId": 10086,
  "device": "ios",
  "channel": "douyin"
}

可以定义:

extra JSON

这比建:

extra1
extra2
extra3
extra4

干净得多。

但 JSON 有一个非常明显的边界。

假设后来业务天天查询:

channel = douyin

还需要:

按 channel 分组
按 channel 建索引
按 channel 做 JOIN

那么 channel 已经不是“扩展属性”了。

它已经升级成核心业务字段。

应该考虑直接拆出来:

channel VARCHAR(32)

JSON 最适合:

字段稀疏
结构变化快
很少作为核心过滤条件
不参与主要 JOIN

如果把用户 ID、状态、金额、创建时间全部塞进 JSON,确实少写了几个字段。

代价是把关系型数据库最擅长的部分一起扔掉了。


十四、IP 地址不要再用 VARCHAR(15)

IPv4:

192.168.1.1

最长 15 个字符,所以老系统经常:

ip VARCHAR(15)

然后 IPv6 出现:

2001:0db8:85a3:0000:0000:8a2e:0370:7334

直接存不下。

简单方案可以:

ip VARCHAR(45)

如果 IP 查询、存储量比较大,更推荐:

ip VARBINARY(16)

MySQL 提供了:

INET6_ATON()
INET6_NTOA()

例如:

INSERT INTO access_log(ip)
VALUES (INET6_ATON('192.168.1.1'));

查询:

SELECT INET6_NTOA(ip)
FROM access_log;

IPv4 和 IPv6 都可以统一处理,而且二进制存储更加紧凑。


十五、UUID 用 CHAR(36) 能跑,但代价不小

标准 UUID:

550e8400-e29b-41d4-a716-446655440000

直接存:

CHAR(36)

当然最直观。

但如果一张大表用 UUID 做大量索引,36 字节的字符串并不便宜。

可以转换成:

BINARY(16)

将 128 bit UUID 用 16 字节保存。

但还有一个更重要的问题:

随机 UUID 并不适合直接作为高写入量 InnoDB 表的聚簇主键。

InnoDB 数据按照主键组织。

大量完全随机的主键插入会让写入位置分散,更容易带来页分裂、缓存局部性下降等问题。

所以在高写入业务里,比“UUID 用 CHAR 还是 BINARY”更应该先考虑:

为什么要让随机 UUID 当聚簇主键?

一种常见方案是:

内部主键:BIGINT
外部业务 ID:UUID / 雪花 ID / 其他全局 ID

内部存储效率和外部全局唯一性分开处理。


十六、VARCHAR 长度越大,真的就只是“上限大一点”吗?

不是。

很多人会觉得:

VARCHAR(50)

和:

VARCHAR(5000)

只要实际上都只存 10 个字符,占用空间就差不多,所以干脆都定义得大一点。

这个思路只看到了磁盘实际字符串长度。

没有看到数据库其他执行过程。

过大的字段声明可能影响:

索引设计
排序
内存估算
临时表
行大小限制
ORM 映射
数据质量约束

而且长度限制本身就是一种非常有价值的数据校验。

用户名如果业务最多允许 32 个字符,就应该接近业务限制:

username VARCHAR(32)

而不是:

username VARCHAR(5000)

然后指望永远没有脏数据进来。


十七、字符集和排序规则也属于“类型设计”

下面两个字段虽然都是:

VARCHAR(32)

行为却不一定完全相同:

字符集不同
Collation 不同

会影响:

一个字符最多占多少字节
字符串比较
大小写敏感
排序方式
唯一索引判断

现在新项目通常优先使用:

utf8mb4

而不是老的 MySQL:

utf8

因为 MySQL 传统的 utf8 实际最多使用 3 字节,并不能覆盖完整 Unicode。

例如部分 Emoji 就无法正常保存。

因此如果业务存在:

用户昵称
评论
聊天
文章
社交内容
Emoji

优先:

utf8mb4

基本已经是默认选择。


十八、隐式类型转换,是选错字段类型之后最隐蔽的坑

假设表里:

mobile VARCHAR(20)

并且建立了索引:

KEY idx_mobile (mobile)

正确查询:

SELECT *
FROM user
WHERE mobile = '13800138000';

如果代码错误地把手机号当数字:

SELECT *
FROM user
WHERE mobile = 13800138000;

此时数据库可能需要进行类型转换。

字段本身参与转换后,原本期待的索引访问路径就可能发生变化。

类似问题经常出现在:

VARCHAR 和 BIGINT 比较
SIGNED 和 UNSIGNED 混用
不同字符集字段 JOIN
日期字段与字符串比较

所以字段类型统一并不只是“代码规范”。

它直接关系到 SQL 执行路径。

例如两张表通过:

user_id

关联,就应该尽量保证双方定义完全一致:

BIGINT UNSIGNED

不要一个:

BIGINT

另一个:

VARCHAR(32)

然后期待数据库替应用层收拾残局。


十九、一张订单表应该怎么设计?

把前面的原则放进一个实际表结构里。

下面以 MySQL 8.x 的订单表为例:

CREATE TABLE `orders` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '内部主键',

    `order_no` VARCHAR(32) CHARACTER SET ascii COLLATE ascii_bin
        NOT NULL COMMENT '订单号',

    `user_id` BIGINT UNSIGNED NOT NULL COMMENT '用户ID',

    `product_name` VARCHAR(128)
        NOT NULL COMMENT '商品名称',

    `amount` DECIMAL(12, 2)
        NOT NULL COMMENT '订单金额',

    `status` TINYINT UNSIGNED
        NOT NULL DEFAULT 0
        COMMENT '状态:0待支付 1已支付 2已发货 3已完成 4已取消',

    `source_ip` VARBINARY(16)
        DEFAULT NULL COMMENT '来源IP',

    `remark` VARCHAR(500)
        DEFAULT NULL COMMENT '订单备注',

    `extra` JSON
        DEFAULT NULL COMMENT '扩展信息',

    `paid_at` DATETIME(3)
        DEFAULT NULL COMMENT '支付时间',

    `created_at` DATETIME(3)
        NOT NULL DEFAULT CURRENT_TIMESTAMP(3)
        COMMENT '创建时间',

    `updated_at` DATETIME(3)
        NOT NULL DEFAULT CURRENT_TIMESTAMP(3)
        ON UPDATE CURRENT_TIMESTAMP(3)
        COMMENT '更新时间',

    PRIMARY KEY (`id`),

    UNIQUE KEY `uk_order_no` (`order_no`),

    KEY `idx_user_created_at` (`user_id`, `created_at`),

    KEY `idx_status_created_at` (`status`, `created_at`),

    CONSTRAINT `chk_orders_amount`
        CHECK (`amount` >= 0)
) ENGINE=InnoDB
  DEFAULT CHARSET=utf8mb4
  COMMENT='订单表';

这里每一个类型都有明确理由。

id:BIGINT UNSIGNED

订单属于持续高速增长数据,而且通常会长期保留。

这里使用:

BIGINT UNSIGNED

是用更大的索引成本换取更长的数据生命周期。

如果只是几百万条数据的小型配置表,就没有必要照抄。

order_no:VARCHAR(32) + ASCII

订单号通常只包含:

数字
大小写英文字母
特殊分隔符

不需要 utf8mb4

所以可以单独指定:

CHARACTER SET ascii

并且订单号一般要求精确匹配:

COLLATE ascii_bin

避免某些不必要的大小写比较语义。

amount:DECIMAL

订单金额要求精确:

DECIMAL(12, 2)

不用 DOUBLE

status:TINYINT

只有几个状态:

TINYINT UNSIGNED

已经足够。

source_ip:VARBINARY(16)

同时兼容:

IPv4
IPv6

比直接给一个很长的字符串更紧凑。

extra:JSON

适合保存不同渠道产生的非核心扩展字段。

但如果以后某个 JSON 属性变成高频查询条件,就应该考虑拆成普通列。

created_at:DATETIME(3)

保留毫秒精度:

2026-08-25 15:32:16.328

对订单、支付、日志等系统通常已经足够。


二十、索引越多,类型选择的成本越明显

假设订单表只有一个主键:

BIGINT

你可能觉得比 INT 多 4 字节,没什么。

但订单表通常还有:

KEY idx_user_created_at (user_id, created_at)

KEY idx_status_created_at (status, created_at)

KEY idx_shop_created_at (shop_id, created_at)

KEY idx_pay_created_at (pay_type, created_at)

InnoDB 二级索引叶子节点会保存对应记录的主键。

于是主键宽度会不断复制到二级索引中。

同样的问题也存在于:

VARCHAR 主键
UUID 主键
超长联合索引

所以建索引的时候,不应该只看:

WHERE 后面有没有这个字段

还应该看:

字段到底有多宽?
主键到底有多宽?
整个索引一条记录需要多少字节?

数据达到亿级以后,几个字节的差别就不再是“几个字节”。


二十一、几个很典型的错误设计

错误 1:所有数字都 BIGINT

status BIGINT
age BIGINT
gender BIGINT
type BIGINT

不是不能运行,只是没有意义。

更合理的可能是:

status TINYINT UNSIGNED
age TINYINT UNSIGNED
gender TINYINT UNSIGNED
type SMALLINT UNSIGNED

数据库表越大,这种差距越明显。

错误 2:所有字符串 VARCHAR(255)

mobile VARCHAR(255)
username VARCHAR(255)
status VARCHAR(255)
order_no VARCHAR(255)

这通常不是“预留扩展空间”,而是没有做数据建模。

错误 3:金额使用 DOUBLE

amount DOUBLE

价格、余额、账单、财务金额优先:

DECIMAL

不要拿浮点误差考验对账系统。

错误 4:手机号使用 BIGINT

mobile BIGINT

手机号是标识符:

mobile VARCHAR(20)

错误 5:时间全部 VARCHAR

created_at VARCHAR(32)

会把本来数据库原生支持的:

范围查询
日期计算
排序
时间函数

全部搞复杂。

错误 6:所有扩展字段全部 JSON

一开始确实开发快。

半年以后:

JSON 查询
JSON 聚合
JSON 排序
JSON 条件组合

开始铺满业务 SQL。

到了这个阶段,这些数据往往早就应该变成普通字段了。

错误 7:为了“以后可能用到”,字段无限放大

title VARCHAR(5000)

实际上标题最多:

100 个字符

那就应该根据业务限制设计。

“可能以后用到”是数据库设计里非常危险的一句话。

真到了业务边界发生数量级变化的时候,通常要改的也不会只有这一个字段。


二十二、建表时可以直接套用的选型思路

普通业务系统可以从下面这套规则开始。

业务数据 常见选择
是否、开关、少量状态 TINYINT
普通整数 INT
高增长主键、流水 ID BIGINT
金额 DECIMAL
比例、科学计算 FLOAT / DOUBLE
手机号 VARCHAR
邮箱 VARCHAR
用户名、昵称 VARCHAR
固定长度代码 CHAR
普通标题、备注 VARCHAR
长文章、富文本 TEXT / MEDIUMTEXT
生日 DATE
普通业务时间 DATETIME
需要时区转换的时间 TIMESTAMP
IPv4 + IPv6 VARBINARY(16)
UUID BINARY(16) 或 CHAR(36)
稀疏扩展属性 JSON
高频查询属性 普通独立字段

这张表只能作为起点,不能代替业务分析。

比如:

BIGINT 是否合适
VARCHAR 到底多长
DECIMAL 保留多少位
DATETIME 是否需要毫秒
JSON 是否该拆列

最后都应该由真实的数据规模和查询方式决定。


二十三、真正值得记住的不是类型表,而是判断方式

MySQL 数据类型并不难记。

难的是在建表时愿意多想一步。

看到:

100

不要马上想到 INT,先判断它是不是编号。

看到:

12.99

不要马上想到 DOUBLE,先判断它是不是金额。

看到:

2026-08-25 15:30:00

不要只问 DATETIMETIMESTAMP 哪个更流行,先把时区语义搞清楚。

看到 ID,也不要无条件:

BIGINT

先估一下这张表到底会有多少数据,以及它会有多少个二级索引。

好的字段类型通常有三个特征:

语义准确、范围够用、存储不过度。

如果还要加第四个,就是:

让未来写 SQL 的人少骂两句。

这比背下所有 MySQL 数据类型的最大长度有用得多。

正文到此结束
评论插件初始化中...
Loading...