MySQL基础建表实战:从学生信息管理看数据类型怎么选
摘要这篇文章咱们不搞那些虚头巴脑的理论就对着一段最基础的MySQL建表SQL拆开了揉碎了讲。我会拿学校里最常见的“学生信息管理”这个真实场景当例子告诉你int、varchar、datetime这些东西到底啥时候该用哪个为啥有时候存个名字会乱码为啥时间戳存成数字反而更香。最后咱们真刀真枪跑一遍代码看看建出来的表长啥样顺便聊聊新手最容易踩的那些坑。描述咱们刚学数据库的时候老师一上来就甩给你一堆建表语句什么create table什么varchar(50)当时可能背下来了但真让你自己设计一个表大概率会懵学生年龄用int还是tinyint性别存“男/女”还是“0/1”生日用date还是datetime甚至有人直接把手机号存成int结果查出来发现科学计数法了。其实这些问题本质上都是没搞懂数据类型和实际业务的匹配关系。今天咱们就拿“学校学生信息管理系统”里的students表当靶子从最基础的建表语法开始一步步把它变成一个能真正用的表顺便把char和varchar的区别、timestamp的坑、小数怎么存这些知识点串起来讲清楚。题解答案咱们最终要实现的是一个能存学生核心信息的表包含学号、姓名、年龄、身高、生日、性别这几个字段。针对原代码的不足比如没主键、性别用char(1)可能存中文报错、身高精度不够优化后的建表SQL如下-- 切换到day02数据库没有的话先创建create database day02;useday02;-- 如果表已经存在就先删掉练习环境用生产环境千万别这么干droptableifexistsstudents;-- 创建学生表createtablestudents(stuNointunsignedauto_incrementcomment员工ID无符号自增,stuNamevarchar(30)notnullcomment学生姓名最长30个字符,stuAgetinyintunsigneddefault0comment年龄0-255足够存学生年龄,stuHeightdecimal(4,2)comment身高最大999.99cm精确到厘米,stuBirthdaydatecomment出生日期只需要年月日,stuSexbit(1)default1comment性别1男0女用bit省空间,primarykey(stuNo)comment学号设为主键)engineinnodbdefaultcharsetutf8mb4;这个表能完美支撑学校里最基础的学生信息管理新增学生时自动生成学号姓名最多存30个字够装少数民族长名字年龄用tinyint比int省3字节身高精确到小数点后两位比如175.50cm生日只存年月日性别用bit只占1位空间。题解代码分析咱们一行行拆解这个SQL把每个设计决策都讲透数据库切换与环境准备useday02;这行就是告诉MySQL“接下来的操作都在day02这个数据库里搞”。如果之前没创建过这个库得先执行create database day02;。实际工作中一个项目通常对应一个数据库比如电商项目用shop_db学生系统用edu_db别把所有表都堆到一个库里后期维护会疯。表删除练习专用droptableifexistsstudents;这是“暴力清空”如果表存在就直接删掉重建。⚠️重点提醒生产环境也就是已经在给真实用户用的系统绝对不能用这行不然你把用户数据删了老板可能会请你喝茶。咱们现在只是学习每次改表结构前删了重建最方便。核心字段设计重头戏stuNo int unsigned auto_incrementint unsignedint默认是有符号的能存负数但学号不可能是负数加unsigned后范围从-2147483648~2147483647变成0~4294967295容量翻倍。auto_increment自增长。不用手动输学号插数据时写nullMySQL会自动给你填1、2、3……再也不怕学号重复。comment 学号注释超级重要半年后再来看表你根本不记得stuNo是啥comment能救你的命。stuName varchar(30) not nullvarchar(30)变长字符串。比如存“张三”只占2个字符的空间不像char(30)会补28个空格占满30个。30的长度是因为中国大部分人名字是2-4个字少数民族可能有长的比如“马尔扎哈·买买提”30个字符足够覆盖99%的情况。not null非空约束。姓名肯定不能为空吧如果不写这个有人插数据时漏了姓名表里就会出现空值后期统计人数就会出错。stuAge tinyint unsigned default 0tinyint unsigned小整数范围0~255。学生年龄最大也就20多岁用int占4字节太浪费tinyint只占1字节省空间。default 0默认值。如果插数据时没填年龄就默认存0实际业务里可能会用NULL表示未知这里为了演示默认值。stuHeight decimal(4,2)原代码用的是double但double是浮点数会有精度问题。比如存175.55可能实际存的是175.5499999这在身高这种需要精确的场景下不行。decimal(4,2)定点数总共4位数字其中2位是小数。最大值是999.99比如篮球特长生身高2米多够存最小值是0.00。如果是体重可能需要decimal(5,2)比如150.50斤。stuBirthday date原代码用的是datetime但生日只需要年月日比如2005-10-01不需要时分秒。date只占3字节datetime占8字节省空间。注意date的范围是1000-01-01到9999-12-31完全够存学生的生日。stuSex bit(1)原代码用char(1)存性别比如存“男”“女”但中文占3个字节utf8mb4编码。用bit(1)只占1位0或1极致省空间。约定1男0女。如果要存“未知”可以用tinyint因为bit只有0和1两个状态。主键约束primarykey(stuNo)主键是表的“身份证”必须唯一且非空。stuNo是自增的天然适合当主键。实际业务中主键一般用“无意义的数”比如自增ID、UUID不要用业务字段比如身份证号因为身份证号可能会变虽然概率低一旦变了所有关联这个主键的外键都会出问题。引擎和字符集engineinnodbdefaultcharsetutf8mb4;innodbMySQL默认引擎支持事务、外键、行锁99%的场景都用它。utf8mb4字符集。别用utf8MySQL的utf8其实是“假utf8”最多存3个字节存不了emoji表情和一些特殊汉字比如“”。utf8mb4才是真正的UTF-8占1-4字节啥都能存。示例测试及结果咱们来插几条真实数据看看表是怎么工作的插入数据-- 插入3个学生stuNo写null让自增生效insertintostudentsvalues(null,张三,18,175.50,2005-10-01,1),(null,李四,19,180.00,2004-05-15,1),(null,王小花,17,162.30,2006-02-20,0);查询数据select*fromstudents;查询结果stuNostuNamestuAgestuHeightstuBirthdaystuSex1张三18175.502005-10-0112李四19180.002004-05-1513王小花17162.302006-02-200验证约束试试插一个年龄为300的“老妖精”insertintostudentsvalues(null,老神仙,300,170.00,1723-01-01,1);结果成功因为tinyint unsigned的最大值是255300超了MySQL会报错Out of range value for column stuAge at row 1。这就是约束的作用——防止脏数据进库。试试插一个姓名为空的记录insertintostudentsvalues(null,null,20,170.00,2003-01-01,1);结果报错Column stuName cannot be null。因为咱们加了not null约束姓名必须填。时间复杂度建表操作本身是O(1)的因为MySQL只要修改元数据表结构信息就行和数据量没关系。插入数据单条也是O(1)但如果表有索引比如主键索引插入时需要维护索引树时间复杂度会变成O(log n)n是表中数据量。不过咱们这个表只有主键索引对于百万级数据插入速度依然很快。空间复杂度咱们算一下每条记录占多少空间按InnoDB默认配置stuNoint unsigned→ 4字节stuNamevarchar(30)→ 假设平均10个字符utf8mb4每个字符最多4字节加上长度标识1-2字节→ ~42字节stuAgetinyint unsigned→ 1字节stuHeightdecimal(4,2)→ 4字节MySQL中decimal占用的空间是固定的和定义的长度有关stuBirthdaydate→ 3字节stuSexbit(1)→ 1位约0.125字节实际存储会按字节对齐可能占1字节总空间约442143155字节/条。如果存100万学生大约占用55MB空间不算索引非常轻量。总结今天咱们从一个最简单的students表出发把建表的核心知识点串了一遍数据类型要“够用就好”年龄用tinyint别用int身高用decimal别用double生日用date别用datetime。约束是数据的“保镖”not null防止空值primary key保证唯一性default减少手动输入。字符集一定要用utf8mb4不然emoji和生僻字存不进去。注释比代码更重要半年后你再看表全靠comment救命。实际工作中建表前一定要和业务方确认清楚这个字段会不会为空最大值是多少要不要支持小数有没有特殊字符把这些想清楚了才能设计出靠谱的表结构。下次咱们再聊聊怎么给表加索引让查询速度快10倍