MySQL 建表时,INT、VARCHAR、DATETIME、DECIMAL 到底怎么选?

发布时间:2026/9/28 21:23:50

MySQL 建表时,INT、VARCHAR、DATETIME、DECIMAL 到底怎么选? 0.1 0.2 ≠ 0.3。你在 MySQL 里用 FLOAT 存金额对账永远差这一分钱。这篇把建表时最常纠结的四种类型——整数 INT、文本 VARCHAR、时间 DATETIME、金额 DECIMAL——一次讲清看完直接照着建表。先把选型原则钉死所有类型选择背后就四条原则后面每一节都是它们的展开最小存储能放下业务范围的最小类型。年龄不用 BIGINT状态不用 INT。精准匹配是什么类型就用什么类型。数值用数值、文本用字符串、日期用日期别全塞 VARCHAR。精度优先金额、汇率必须定点数浮点绝对不行。兼容拓展自增主键预见到后期数据量直接 BIGINT别等溢出再改表。知道了这四条我们从一张订单表的第一个字段开始选。记住选型不是背类型表是对着业务字段一个个问这一列存什么。主键 IDINT 还是 BIGINTINT(11) 又是什么订单表第一个字段必然是order_id。选 INT 还是 BIGINTINT 是 32 位有符号整数固定 4 字节有符号范围 -21 亿 ~ 21 亿加UNSIGNED翻一倍到 0 ~ 42 亿。中小体量业务 42 亿够你写到公司倒闭但分布式、雪花 ID、海量流水直接上 BIGINT8 字节上限 9.2×10^18。业务里 99% 的整数字段都是非负的——用户 ID、订单数量、浏览量、年龄、排序号这种字段统一加UNSIGNED。一举两得容量翻倍负数脏数据根本写不进去。只有真会出现负数的场景差值、温度、盈亏统计才保留有符号。整数查询快不是玄学——固定 4 字节长度数据库比较、排序、走索引都是按定长算不用像 VARCHAR 那样先读长度前缀再定位。这也是能整型就别字符串的底层原因。这里有个几乎人人踩过的坑INT 后面的括号数字不是存储位数。要点INT(11)、INT(5)、INT(20)占用空间和取值范围完全一样——都是 4 字节。括号里的数字叫显示宽度Display Width只在配ZEROFILL时才生效用于左侧补零。前端本来就会管展示格式数据库这层零填充现在没人用。CREATETABLEt(aINT(5)ZEROFILL,bINT(11));INSERTINTOtVALUES(12,12);SELECTa,bFROMt;-- 预期输出: a00012, b12看到区别没a被补成 5 位b没有。但两个字段占的空间一模一样。⚠️坑我见过有人为了省空间把主键从 INT(11) 改成 INT(5)上线后发现查询结果多了前导零前端把00012当字符串拼了。这事改起来简单但暴露了他根本不知道显示宽度是干嘛的。整型家族怎么挑对照下表类型字节有符号范围无符号范围典型场景TINYINT1-128 ~ 1270 ~ 255状态、性别、评分SMALLINT2-3.2 万 ~ 3.2 万0 ~ 6.5 万年份、小计数INT4±21 亿0 ~ 42 亿用户 ID、订单 IDBIGINT8±9.2×10^180 ~ 1.8×10^19雪花 ID、海量主键主键选完状态字段别再用 INT。订单状态就 0/1/2 三个值用TINYINT UNSIGNED只占 1 字节比 INT 省 3 倍。大表上这个差距肉眼可见。顺便把状态字段的默认值也定了别用INT DEFAULT NULL。两个问题——INT 浪费空间NULL 会让WHERE status ! 1这种查询直接漏掉 NULL 行。统一TINYINT UNSIGNED NOT NULL DEFAULT 0业务里没有未赋值这一说。记住主键预见数据量状态用 TINYINTINT(M) 的 M 别当回事。手机号字段INT 能存为什么不能用下一个字段是phone。11 位数字看着像整数很多人第一反应是 INT。这是个生产事故级别的错误。手机号看着像数字用 INT 存会有三个问题前导 0 直接丢——手机号本身没有前导 0但卡号、身份证、工号有。0012345存进 INT 变成12345对不上。超范围溢出——身份证 18 位早就爆 INT 的 42 亿上限存进去就是错的。失去字符串语义——手机号不做加减乘除你要的是它长什么样不是值多大。⚠️坑我刚工作时见过一张用户表用 BIGINT 存身份证号数据迁移才发现有几个人的号开头是 0导出来全少一位。这种脏数据事后根本查不回来。所以短文本、编号、手机号、邮箱统一用VARCHAR。VARCHAR(M) 的 M 是字符数不是字节数——这是第二个新手坑。一个汉字在 utf8mb4 下最多占 4 字节但VARCHAR(50)就是按 50 个字符算不管你存的是汉字还是字母。长度按够用且最小挑昵称、用户名、手机号VARCHAR(32)或VARCHAR(50)地址、简介、标题VARCHAR(128)或VARCHAR(255)文章正文、商品详情别用 VARCHAR换 TEXT为什么因为 MySQL 单行有 65535 字节的硬上限所有列共享。你把一堆 VARCHAR(2000) 堆进去建表直接报错。长文本交给 TEXT别硬塞。还有个细节VARCHAR 的长度前缀占 1 字节还是 2 字节分界正好在 255。定义 ≤255 时长度前缀 1 字节255 时 2 字节——这也是为什么很多人习惯把 VARCHAR 卡到 255不是迷信是有底层原因的。但别为了这 1 字节硬把短文本设成 255按需选就好。另外密码字段也是 VARCHAR——存的是加密后的哈希串比如 bcrypt 输出 60 位VARCHAR(60)就够别去存明文。要点CHAR和VARCHAR的区别——CHAR 固定长度、尾补空格适合长度完全固定的字段比如定长编码VARCHAR 按需存储90% 场景用它。手机号虽然长度固定 11 位但前导 0 不参与运算这两点还是选 VARCHAR。VARCHAR 还有两个硬规矩字符集统一utf8mb4不然 emoji 存不进去字段默认NOT NULL DEFAULT 别让字符串字段为 NULL——NULL 会让索引效率下降WHERE name ! a这种条件还会漏行。新手最省事的写法是所有字段都用 VARCHAR——图省事其实是灾难。一旦金额列是 VARCHARORDER BY amount DESC就变成字典序排9排在10前面SUM(amount)直接报错或按字符串拼WHERE age 18也走不了数值比较。类型混用索引和计算全部失效。VARCHAR 建索引还有个细节字段太长时别整列建索引指定前缀长度。比如标题列VARCHAR(255)索引只取前 50 个字符INDEX title(title(50))。整列建索引会让索引文件暴涨B 树层级变深查询反而慢。记住编号类字段哪怕全是数字只要带前导 0、不运算、长度超 INT就用 VARCHAR。时间字段DATETIME 还是 TIMESTAMP订单表第三个关键字段是create_time。教科书里教过两个DATETIME 和 TIMESTAMP选哪个直接给结论新项目一律 DATETIME别碰 TIMESTAMP。先说版本前提MySQL 5.6 及以上把 DATETIME 改成了二进制压缩存储固定 5 字节更早版本是字符串存又慢又占地方。现在没人用 5.6 以前的版本了这条可以直接跳过但你要是接手老项目先SELECT version()看一眼。对比项DATETIMETIMESTAMP空间5 字节4 字节范围1000 ~ 9999 年1970 ~ 2038 年时区无关存绝对值依赖时区改时区就乱自动更新可控默认强制那省下来的 1 字节换一个 2038 年就溢出的炸弹值不值⚠️坑2038 问题不是吓唬人。TIMESTAMP 底层是 32 位时间戳到 2038-01-19 03:14:07 UTC 就翻转。现在写的代码几年后可能就在这个坑上炸。而且 TIMESTAMP 会随数据库时区自动转换——服务器从东八区迁到新加坡老数据看起来全变了。DATETIME 存的是绝对值不管服务器时区怎么改2026-09-27 22:30:00就是这个数。实际建表时create_time和update_time是标配create_timeDATETIMENOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT创建时间,update_timeDATETIMENOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMPCOMMENT更新时间create_time插入时自动填当前时间以后不改update_time在行被 UPDATE 时自动刷新。不用业务代码操心。精度上普通业务DATETIME(0)精确到秒就够秒杀、日志、高频排序场景上DATETIME(3)精确到毫秒。两个延伸只存日期不存时间比如生日用DATE只存时长比如视频时长用TIME别全用 DATETIME 浪费。❌错误用VARCHAR存时间字符串或者用INT存时间戳。前者没法用DATEDIFF、DATE_FORMAT这些函数范围索引也走不了后者人眼看不出是几点排查问题全靠转。还有一条容易被忽略的服务器时区、MySQL 时区、应用时区三层必须统一设成Asia/Shanghai。不然你在本地看到的时间和线上差 8 小时排查问题时先怀疑数据错了绕一大圈才发现是时区没对齐。记住新项目时间字段用 DATETIMETIMESTAMP 的 2038 炸弹和时区坑别去接。字段为什么 FLOAT 永远对不平账回到开头那个反常识——0.1 0.2 到底等多少在 MySQL 里实测一下SELECT0.10.2;-- 预期输出: 0.30000000000000004SELECTCAST(0.1ASDECIMAL(10,2))CAST(0.2ASDECIMAL(10,2));-- 预期输出: 0.30FLOAT 和 DOUBLE 是二进制浮点数底层用二进制近似存小数0.1 在二进制里是无限循环存进去就已经不是 0.1 了。这不是 bug是 IEEE 754 的设计。FLOAT 大约 6-7 位有效数字DOUBLE 大约 15-16 位——别被DOUBLE 更准骗了它只是误差更小累加十笔百笔之后照样飘。✅验证你把 0.1 存 FLOAT、0.2 存 FLOAT、加起来再 SUM十笔交易下来对账差几分钱是常态。财务找过来的时候你跟他解释这是二进制浮点——没用。DECIMAL 是十进制定点数按十进制字符串存0.1 就是 0.10.2 就是 0.2加起来严格 0.3。语法DECIMAL(M, D)M 是总位数D 是小数点后位数。常用配置订单金额、余额、商品价格DECIMAL(10,2)最大 99999999.99大额交易、企业账务DECIMAL(16,2)汇率、税率、利率DECIMAL(8,4)留 4 位小数⚠️坑别把 M 设得过大。DECIMAL(65,30)听着安全实际占的存储是按 M 算的每多一位都在浪费。DECIMAL 上限是 M65、D30但没人真用到那么大。按业务最大值选单价封顶 9999 元的业务DECIMAL(10,2)完全够。金额字段的默认值是0.00不是NULL也不是整数0——后者会让小数位丢精度。温度、身高、体重这种不要求精确的数用 DOUBLE 是对的但把它用在金额上就是事故。还有一层兜底数据库存 DECIMAL 不代表业务代码可以躺平。入库前用BigDecimal.setScale(2, RoundingMode.HALF_UP)截一下不然传进来一个0.123456数据库按 D2 静默截断成0.12业务层完全无感知对账单又差一分。记住资金字段一律 DECIMAL(10,2)FLOAT/DOUBLE 留给科学计算别碰钱。一张标准订单表长什么样把前面四个选择拼起来一张能直接上线的订单表大致是这样CREATETABLEorders(order_idBIGINTUNSIGNEDNOTNULLAUTO_INCREMENT,user_idBIGINTUNSIGNEDNOTNULL,statusTINYINTUNSIGNEDNOTNULLDEFAULT0,phoneVARCHAR(18)NOTNULLDEFAULT,amountDECIMAL(10,2)NOTNULLDEFAULT0.00,create_timeDATETIMENOTNULLDEFAULTCURRENT_TIMESTAMP,update_timeDATETIMENOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMP,PRIMARYKEY(order_id))ENGINEInnoDBDEFAULTCHARSETutf8mb4;对照一下前面讲的每一条主键order_id用 BIGINT 预见未来状态status用 TINYINT 省空间手机号phone用 VARCHAR 容纳前导 0金额amount用 DECIMAL 保精度create_time/update_time双字段 DATETIME 自动维护全表NOT NULL 默认值没有 NULL 字段。这就是一套能跑的最小规范。结尾速查与常见坑业务字段选型对照业务字段推荐类型标准写法用户 ID、订单 IDBIGINTBIGINT UNSIGNED NOT NULL AUTO_INCREMENT状态、是否删除TINYINTTINYINT UNSIGNED NOT NULL DEFAULT 0昵称、地址VARCHARVARCHAR(50) NOT NULL DEFAULT 手机号、身份证VARCHARVARCHAR(18) NOT NULL DEFAULT 创建/更新时间DATETIMEDATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP订单金额DECIMALDECIMAL(10,2) NOT NULL DEFAULT 0.00汇率、税率DECIMALDECIMAL(8,4) NOT NULL DEFAULT 0.0000生日DATEDATE NOT NULL DEFAULT 1970-01-01常见坑清单按踩中频率排序全表用 VARCHAR——数值没法排序、没法运算、索引效率掉。金额用 FLOAT/DOUBLE——对账永远差几分钱。TIMESTAMP 用在新项目——2038 溢出 时区错乱。手机号/身份证用 INT——前导 0 丢失、超长溢出。纠结 INT(11) 还是 INT(5)——显示宽度而已别浪费时间。字段默认 NULL——WHERE ! x漏行、索引效率下降。VARCHAR 一律 255——短文本浪费空间长文本又截断。用字符串存时间——时间函数全废范围查询慢。下一步你可以做的找一张你最近建的表跑一句SHOW CREATE TABLE 表名\G把字段类型拉出来对照上面这张表逐字段过一遍。我赌至少有一个字段要么用大了、要么用错了类型。改完再跑一次EXPLAIN看看索引有没有变化。参考链接MySQL 官方文档 - 数据类型MySQL 官方文档 - Fixed-Point Types (Exact Value)MySQL 官方文档 - The DATE, DATETIME, and TIMESTAMP Types
延伸阅读

更多相关文章

2026/9/28 21:23:50

基于微信小程序的社区志愿活动系统的设计与实现

摘 要 在基层治理精细化与公益服务数字化的发展趋势下,传统社区志愿管理模式的弊端日益凸显。活动招募依赖线下渠道,覆盖面窄且效率低,志愿时长统计、人员技能匹配全靠人工,易出现错漏,居民需求与志愿资源也难以精准对…

2026/9/28 21:23:50

深度学习是大模型的操作系统,不是工具箱

1. 这不是“AI大模型之深度学习”——而是一场被严重误读的技术关系澄清很多人看到“AI大模型之深度学习”这个标题,第一反应是:“哦,这是讲怎么用深度学习去训练大模型?”或者“这是深度学习在大模型里的应用案例?”—…

2026/9/28 22:28:56

微信API大流量下的Java后端数据库索引设计与查询优化

微信API接口一接入生产环境,流量往往不是你写代码时能预想到的。前阵子帮一个做企业服务的朋友排查线上问题,他们的Java后端对接微信公众号接口,平时一天几万请求,某天做活动突然涌进来几十万并发,数据库CPU直接飙到99…

2026/9/28 22:28:56

Spring Boot实战:钱币收藏交流系统的架构设计与开发全解析

1. 项目概述与需求拆解1.1 钱币收藏圈的真实痛点钱币收藏这个小众圈子,看着不大,但信息分散的问题比大多数行业都严重。玩钱币的人都知道,找一枚特定版别的钱币有多难——袁大头九年精发版、船洋二十三年、一版人民币的暗记区别,这…

2026/9/28 22:28:56

性能瓶颈为何总卡在RAX?深入AX调度与指令级优化

1. 一次代码级优化引发的思考:性能瓶颈怎么会卡在"AX"上1.1 一个让所有人挠头的现场上个月给团队做性能评审,遇到一个挺有意思的case。某个底层数据处理函数,单次调用耗时只有不到两微秒,但它在整个服务里被高频反复调用…

2026/9/28 22:28:56

Agent-native架构实战:从认知到落地的关键设计

1. 先聊清楚:agent-native到底在说哪件事Agent这个词快被用烂了。有人把接了个大模型API的聊天框叫agent,有人把带function calling的demo叫agent,还有人把定时跑批的任务叫agent。直到"agent-native"这个说法慢慢浮出水面&#xf…

2026/9/28 22:28:56

Agent-Native架构落地:五大核心部件与避坑指南

过去这半年,“agent-native”几乎成了AI工程圈最常挂在嘴边的词。我第一次认真琢磨它,不是从哪篇论文里,而是看一个新项目的架构图:整个系统里没有传统意义上的聊天框,取而代之的是一群互相协作的Agent节点&#xff0c…

2026/9/28 22:23:56

Java Swing+SqlServer学生成绩管理系统:毕业设计实现与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/28 3:03:23

东莞市品牌网站建设报价常见报错与解决

东莞品牌网站建设报价单背后:一份保姆级建站教程避坑实录 网站做好了没人访问,这大概是很多老板最头疼的事。花了大几万做的品牌站,上线后流量惨淡,比路边摊还冷清。别急着骂外包公司,很多“东莞品牌网站建设报价”里藏着不少猫腻,比如用模板站冒充定制…

2026/9/28 6:05:15

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/9/28 6:07:41

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/9/28 0:02:03

广州外贸网站建设推广:从零搭建全流程拆解与真实报价避坑

广州外贸网站建设推广:从零搭建全流程拆解与真实报价避坑 改个需求建站公司拖一周,后台改个文案还得再交一笔“技术维护费”。这种憋屈事儿,做外贸的朋友太熟悉了。很多老板在找广州外贸网站建设推广服务商时,光盯着首页好不好看,却忽略了从零搭建一个能…

2026/9/28 0:02:04

搞懂百度竞价推广价格,网站性能优化别掉链子

搞懂百度竞价推广价格,网站性能优化别掉链子 网站突然打不开,浏览器弹出红色警告“此网站存在安全风险”,后台一看全是乱码代码和奇怪的跳转链接。这种网站被黑挂马的绝望感,很多刚转行做网站的朋友都经历过,尤其是那些为了省几百块钱服务器费用的新手。…

2026/9/25 20:55:38

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/26 19:58:38

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/28 1:59:25

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑