SQL Server 数据库表设计的18条军规
当前位置:点晴教程→知识管理交流
→『 技术文档交流 』
前言对于后端开发同学来说,访问数据库,是代码中必不可少的一个环节。 系统中收集到用户的核心数据,为了安全性,我们一般会存储到数据库,比如:mysql,oracle等。 后端开发的日常工作,需要不断的建库和建表,来满足业务需求。 通常情况下,建库的频率比建表要低很多,所以,我们这篇文章主要讨论建表相关的内容。 如果我们在建表的时候不注意细节,等后面系统上线之后,表的维护成本变得非常高,而且很容易踩坑。 今天就跟大家一起聊聊,数据库建表的18个小技巧。 文章中介绍的很多细节,我在工作中踩过坑,并且实践过的,非常有借鉴意义,希望对你会有所帮助。 1.名字建表的时候,给 1.1 见名知意名字就像 好的名字,言简意赅,见名知意,让人心情愉悦,能够提高沟通和维护成本。 坏的名字,模拟两可,不知所云。而且显得杂乱无章,看得让人抓狂。 反例:
你看了可能会一脸懵逼,这是什么骚操作? 正例:
1.2 大小写名字尽量都用 反例:
全部大写,看起来有点不太直观。而一部分大写,一部分小写,让人看着更不爽。 正例:
名字还是使用全小写字母,看着更舒服。 1.3 分隔符很多时候,名字为了让人好理解,有可能会包含多个单词。 那么,多个单词间的 反例:
单词间没有分隔,或者单词间用驼峰标识,或者单词间用空格分隔,或者单词间用@分隔,这几种方式都不太建议。 正例:
强烈建议大家在单词间用 1.4 表名对于表名,在言简意赅,见名知意的基础之上,建议带上 如果是订单相关的业务表,可以在表名前面加个前缀: 例如:order_pay、order_pay_detail等。 如果是商品相关的业务表,可以在表名前面加个前缀: 例如:product_spu,product_sku等。 这样做的好处是为了方便归类,把相同业务的表,可以非常快速的聚集到一起。 另外,还有有个好处是,如果哪天有非订单的业务,比如:金融业务,也需要建一个名字叫做pay的表,可以取名:finance_pay,就能非常轻松的区分。 这样就不会出现 1.5 字段名称
比如有些表,使用flag表示状态,另外的表用status表示状态。 可以统一一下,使用status表示状态。 如果一个表使用了另一个表的主键,可以在另一张表的名后面,加 在product_sku表中有个字段,是product_spu表的主键,这时候可以取名:product_spu_id或product_spu_sys_no。 还有创建时间,可以统一成:create_time,修改时间统一成:update_time。 删除状态固定为:delete_status。 其实还有很多公共字段,在不同的表之间,可以使用全局统一的命名规则,定义成相同的名称,以便于大家好理解。 1.6 索引名在数据库中,索引有很多种,包括:主键、普通索引、唯一索引、联合索引等。 每张表的主键只有一个,一般使用: 普通索引和联合索引,其实是一类。在建立该类索引时,可以加 唯一索引,可以加 2.字段类型在设计表时,我们在选择 时间格式的数据有:date、datetime和timestamp等等可以选择。 字符类型的数据有:varchar、char、text等可以选择。 数字类型的数据有:int、bigint、smallint、tinyint等可以选择。 说实话,选择很多,有时候是一件好事,也可能是一件坏事。 如何选择一个 如果字段类型选大了,比如:原本只有1-10之间的10个数字,结果选了 其实,1-10之间的10个数字,每个数字 这样会白白浪费7个字节的空间。 如果字段类型择小了,比如:一个18位的id字段,选择了 所以选择一个合适的字段类型,还是非常重要的一件事情。 以下原则可以参考一下:
3.字段长度前面我们已经定义好了 比如:varchar(20),biginit(20)等。 那么问题来了, 答:在mysql中除了 biginit(n) 这个 假如我们定义的字段类型和长度是:bigint(4),bigint实际长度是 现在有个数据a=1,a显示4个字节,所以在不满4个字节时前面填充0(前提是该字段设置了zerofill属性),比如:0001。 当满了4个字节时,比如现在数据是a=123456,它会按照实际的长度显示,比如:123456。 但需要注意的是,有些mysql客户端即使满了4个字节,也可能只显示4个字节的内容,比如会显示成:1234。 所以bigint(4),这里的4表示显示的长度为4个字节,实际长度还是占8个字节。 4.字段个数我们在建表的时候,一定要对 我之前见过有人创建的表,有几十个,甚至上百个字段,表中保存的数据非常大,查询效率很低。 如果真有这种情况,可以将一张 建议每表的字段个数,不要超过 5. 主键在创建表时,一定要创建 因为主键自带了主键索引,相比于其他索引,主键索引的查询效率最高,因为它不需要回表。 此外,主键还是天然的 在 但在 除此之外,主键建议保存跟业务无关的值,减少业务耦合性,方便今后的扩展。 不过我也见过,有些一对一的表关系,比如:用户表和用户扩展表,在保存数据时是一对一的关系。 这样,用户扩展表的主键,可以直接保存用户表的主键。 6.存储引擎在 之前我们还在创建表时,还一直纠结要选哪种存储引擎?
而 以前的建议是:读多写少的表,用myisam存储引擎。而写多读多的表,用innodb。 但虽说mysql对innodb存储引擎性能的不断优化,现在myisam和innodb查询性能相差已经越来越小。 所以,建议我们在使用 7. NOT NULL在创建字段时,需要选择该字段是否允许为 我们在定义字段时,应该尽可能明确该字段 为什么呢? 我们主要以innodb存储引擎为例,myisam存储引擎没啥好说的。 主要有以下原因:
因此,建议我们在定义字段时,能定义成NOT NULL,就定义成NOT NULL。 但如果某个字段直接定义成NOT NULL,万一有些地方忘了给该字段写值,就会 这也算合理的情况。 但有一种情况是,系统有新功能上线,新增了字段。上线时一般会先执行sql脚本,再部署代码。 由于老代码中,不会给新字段赋值,则insert数据时,也会报错。 由此,非常有必要给NOT NULL的字段设置默认值,特别是后面新增的字段。 例如:
8.外键在mysql中,是存在 外键存在的主要作用是:保证数据的 例如:
有个班级表class。 然后有个student表:
其中student表中的cid字段,保存的class表的id,这时通过 这时,如果你直接通过student表的id删除数据,会报异常:
必须要先删除class表对于的cid那条数据,再删除student表的数据才行,这样能够保证数据的一致性和完整性。
如果只有两张表的关联还好,但如果有十几张表都建了外键关联,每删除一次主表,都需要同步删除十几张子表,很显然性能会非常差。 因此,互联网系统中,一般建议不使用外键。因为这类系统更多的是为了性能考虑,宁可牺牲一点数据一致性和完整性。 除了 9. 索引在建表时,除了指定 例如:
在创建商品表时,使用spu_id(商品组表)和brand_id(品牌表)的id。 像这类保存其他表id的情况,可以增加普通索引:
后面查表的时候,效率更高。 但索引字段也不能建的太多,可能会影响保存数据的效率,因为索引需要额外的存储空间。 建议单表的索引个数不要超过: 如果在建表时,发现索引个数超过5个了,可以删除部分 顺便说一句:在创建联合索引的时候,需要使用注意 对于数据重复率非常高的字段,比如:状态,不建议单独创建普通索引。因为即使加了索引,如果mysql发现 如果你对索引失效问题比较感兴趣,可以看看我的另一篇文章《聊聊索引失效的10种场景,太坑了》,里面有非常详细的介绍。 10.时间字段
但如果哪天我们要通过时间范围查询数据,效率会非常低,因为这种情况没法走索引。
而 但它们有略微区别。
优先推荐使用
11.金额字段mysql中有多个字段可以表示浮点数:float、double、decimal等。 而 一般我们是这样定义浮点数的:decimal(m,n)。 其中 假如我们定义的金额类型是这样的:decimal(10,2),则表示整数长度是8位,并且保留2位小数。 12. json字段我们在设计表结构时,经常会遇到某个字段保存的数据值不固定的需求。 举个例子,比如:做异步excel导出功能时,需要在异步任务表中加一个字段,保存用户通过前端页面选择的查询条件,每个用户的查询条件可能都不一样。 这种业务场景,使用传统的数据库字段,不太好实现。 这时候就可以使用MySQL的json字段类型了,可以保存json格式的结构化数据。 保存和查询数据都是非常方便的。 MySQL还支持按字段名称或者字段值,查询json中的数据。 13.唯一索引
你可以给单个字段,加唯一索引,比如:组织机构code。 也可以给多个字段,加一个联合的唯一索引,比如:分类编号、单位、规格等。 单个的唯一索引还好,但如果是联合的唯一索引,字段值出现null时,则唯一性约束可能会失效。 关于唯一索引失效的问题,感兴趣的小伙伴可以看看我的另一篇文章《明明加了唯一索引,为什么还是产生重复数据?》。
14.字符集mysql中支持的 这4种字符集情况如下:
而 从目前来看,mysql的字符集使用最多的还是: 其中 但utf-8有个问题:即无法存储emoji表情,因为emoji表情一般需要4个字节。 由此,使用utf-8字符集,保存emoji表情时,数据库会直接报错。 所以,建议在建表时字符集设置成: 15. 排序规则不知道,你关注过没,在mysql中创建表时,有个 例如:
它是用来设置 字符排序规则跟字符集有关,比如:字符集如果是 其中utf8mb4_general_ci排序规则,对字母的大小写不敏感。说得更直白一点,就是不区分大小写。 而utf8mb4_bin排序规则,对字符大小写敏感,也就是区分大小写。 说实话,这一点还是非常重要的。 假如order表中现在有一条记录,name的值是大写的YOYO,但我们用小写的yoyo去查,例如:
如果字符排序规则是utf8mb4_general_ci,则可以查出大写的YOYO的那条数据。 如果字符排序规则是utf8mb4_bin,则查不出来。 由此,字符排序规则一定要根据实际的业务场景选择,否则容易出现问题。 16.大字段我们在创建表时,对一些特殊字段,要额外关注,比如: 比如:用户的评论,这就属于一个大字段,但这个字段可长可短。 但一般会对评论的总长度做限制,比如:最多允许输入500个字符。 如果直接定义成 当然,我还见过更大的字段,即该字段直接保存合同数据。 一个合同可能会占 在mysql中保存这种数据,从系统设计的角度来说,本身就不太合理。 像合同这种非常大的数据,可以保存到 17.冗余字段我们在设计表的时候,为了性能考虑,提升查询速度,有时可以冗余一些字段。 举个例子,比如:订单表中一般会有userId字段,用来记录用户的唯一标识。 但很多订单的查询页面,或者订单的明细页面,除了需要显示订单信息之外,还需要显示用户ID和用户名称。 如果订单表和用户表的数据量不多,我们可以直接用userId,将这两张表join起来,查询出用户名称。 但如果订单表和用户表的数据量都非常多,这样join是比较消耗查询性能的。 这时候我们可以通过冗余字段的方案,来解决性能问题。 我们可以在订单表中,可以再加一个userName字段,在系统创建订单时,将userId和userName同时写值。 当然订单表中历史数据的userName是空的,可以刷一下历史数据。 这样调整之后,后面只需要查询订单表,即可查询出我们所需要的数据。 不过冗余字段的方案,有利也有弊。 对查询性能有利。 但需要额外的存储空间,还可能会有数据不一致的情况,比如用户名称修改了。 我们在实际业务场景中,需要综合评估,冗余字段方案不适用于所有业务场景。 18.注释我们在做表设计的时候,一定要把表和相关字段的注释加好。 例如下面这样的:
表和字段的注释,都列举的非常详细。 特别是有些状态类型的字段,比如:valid_status字段,该字段表示有效状态, 1:有效 0:无效。 让人可以一目了然,表和字段是干什么用的,字段的值可能有哪些。 最怕的情况是,你在表中创建了很多status字段,每个字段都有1、2、3、4、5、6、7、8、9等多个值。 没有写什么注释。 谁都不知道1代表什么含义,2代表什么含义,3代表什么含义。 可能刚开始你还记得。 但系统上线使用一年半载之后,可能连你自己也忘记了这些status字段,每个值的具体含义了,埋下了一个巨坑。 由此,我们在做表设计时,一定要写好相关的注释,并且经常需要更新这些注释。 该文章在 2024/4/9 23:51:22 编辑过 |
关键字查询
相关文章
正在查询... |