MySQL 数据库设计经验总结

背景

此文仅在数据库设计层面进行探讨,数据库的运维与底层调优不在讨论范围以内。html

更丰富的知识能够在 MySQL 官网文档 查阅。前端

学习官方文档也是一种好的习惯,能更系统更全面的掌握某一领域的知识,具体知识点也能够经过搜索引擎快速获取,可是很难让你深刻到细节或者上升到宏观层面。mysql

基础知识

存储引擎

  • 一般来讲,咱们作业务开发,指定存储引擎为 InnoDB 便可。

字符集

  • 一般来讲,只要指定为 utf8 便可。git

  • 若是业务中须要使用 emoji 表情,那么就必需要设置为 utf8mb4sql

MySQL 能够在 server 级、database 级、table 级、column 级进行字符集的设置。数据库

数据库设计

总则

  • 命名以“_”分割
数据库层面仍是推荐使用“_”做为分割,这里多说几点:
一、约定俗成。长久以来不只 MySQL ,其余数据库也推荐使用“_”,这是一种 SQL 规范。
二、JSON 返回的数据通常也会将驼峰转化为“_”来分割。
三、JAVA POJO 对象仍是使用驼峰命名,如今的 JSON 转换工具, ORM 工具能够很便捷的指定参数来设置驼峰或者下划线的偏好。

若是仅是使用 Mybatis ,为了减小配置,也能够考虑使用驼峰命名数据库字段,或者使用 Mybatis 的 mapUnderscoreToCamelCase 的参数来解决。
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true" />
    </settings>
</configuration>
注意:resultType="hashMap" 的时候,不会生效,必定要有对应的实体。
Spring Boot 中指定 mybatis.configuration.mapUnderscoreToCamelCase=true
  • 综合考虑应用场景,合理分库分表
  • 合理冗余字段,合理参考范式,以空间换时间
  • 尽可能保证数据库单表操做,减小关联查询
  • 合理使用索引
  • 合理设计全部字段及表关联
  • 尽可能避免在数据库层面实现逻辑

尽可能避免使用触发器,视图,储存过程,将业务逻辑与统计逻辑分离。不要在业务库中大量统计计算。避免使用各类数据库函数。mybatis

库设计

  • 不容许物理删除,须要逻辑删除的使用 is_deleted 字段。除非是一些可有可无的关联关系变动,能够物理删除再插入,而后经过操做日志进行追踪。
  • 日志表、关联关系表等固定数据表,须要包含 create_by, create_at 三个字段,业务表必须带 create_by,create_at,update_by,update_at 四个字段。若是常常查询,须要展现建立者修改者名称,能够增长 create_name 和 update_name 字段来进行冗余,且应该使用真实姓名,name 仅作展现用,id 字段便于数据统计。
  • 流水表是不可变动表,不须要带 is_deleted,create_by 等字段。
  • 业务表状态简单的只要使用 status 字段便可,若是状态复杂且要对不一样状态分组,能够考虑使用 status_group 之类的额外字段来进行简化。

表设计

  • 不建议以 “t_” 开头

通常来讲以“t_”开头是为了表示这是一张表,区别于视图,触发器,存储过程等。而如今互联网架构通常不建议使用视图,触发器,存储过程等。并且不少企业只有一个库,全是 t_ 开头的数十上百张表,根本不知道怎么快速检索。架构

  • 直接使用业务对象为表名 order,也不建议使用复数形式

若是已经按照功能模块作了数据库的拆分,能够不要使用任何前缀,直接使用表名,如 order 。若是还在使用一个库放全部的表的话,那就最好已模块名开头,比较客服系统的工单表,能够命名为 cs_job 。oracle

注意:不要与数据库关键字冲突运维

  • 关系表以 “_rel” 结尾( rel 这个结尾不必定很合适,有更好的能够推荐)
  • 日志表以 “_log” 结尾
  • 表名要简约(这一点可能也挺难,尽可能避免拼音做为表名,英文能够适当采起缩写,好比 rel-关联关系 或者 corp-公司,可是也要避免滥用缩写,或者本身创造缩写 )

字段设计

  • 每张表都应该有独立的 id 字段,不论是自增字段仍是本身制定的 id(uuid 及其余类型的惟一主键均可以,如某宝的订单号和支付 ID )

扩展知识点:第二范式 聚簇索引 非聚簇索引

  • 尽可能保证全部字段非空
更新时间,更新者ID,更新者姓名等字段能够根据本身喜爱设置初始值或者为空
支付时间,退款时间,发货时间,收货时间等业务上后续发生的行为能够为空
其余字段一概不为空,更好的数据库约束,减小理解不一致和性能损耗。

B.4.4.3 Problems with NULL Values

22.2.7 How MySQL Partitioning Handles NULL

  • 注意整型的长度修饰并不表明字段存储值的范围,只是展现长度。

这一点不少开发人员都没有注意过。咱们仍是看一下官网的描述。11.1.1 Numeric Type Overview int(11) 中的 11 只是展现位数,并不影响实际存储的值,配合 ZEROFILL ,改变的只是查询的值,好比数据库字段定义为 INT(4),值为 1,启用了 ZEROFILL, SELECT 的结果展现为 0001。

INT[(M)] [UNSIGNED] [ZEROFILL]

A normal-size integer. The signed range is -2147483648 to 2147483647. The unsigned range is 0 to 4294967295.

M indicates the maximum display width for integer types. The maximum display width is 255. Display width is unrelated to the range of values a type can contain, as described in Section 11.2, “Numeric Types”. For floating-point and fixed-point types, M is the total number of digits that can be stored.

MySQL supports the SQL standard integer types INTEGER (or INT) and SMALLINT. As an extension to the standard, MySQL also supports the integer types TINYINT, MEDIUMINT, and BIGINT.

若是要考虑数据迁移的话,尽可能使用 INT 或者 SMALLINT。
  • 整型合理使用UNSIGNED

整型的UNSIGNED很魔性,须要结合实际场景使用。ZEROFILL 默认使用 UNSIGNED。UNSIGNED 修饰有两大做用:一是保证列为非负数,二是能够扩大使用范围,我的推荐使用 UNSIGNED。

  • 确保每列的原子性,每一个字段的含义应该惟一(第一范式)

不能用一个字段来表示两种逻辑含义,还有就是字段要存储直接的字面量,不要存储须要计算的值,好比使用类 Linux 文件系统权限的模式来处理状态

  • 表中不能存储文件,只能存放 url

若是使用了分布式文件储存系统,或者用了第三方的文件存储服务。能够不用存储域名前缀,应用层实现拼接或者前端处理。

  • 尽可能避免使用 text 或 blog 字段

确实须要存储的能够考虑拆表,将基本字段与扩展大字段分开。甚至能够考虑采用 MongoDB 之类的数据库才存储大量的文本表。

索引设计

  • 尽可能使用单列索引,避免使用联合索引,不要建 3 列以上的联合索引。
  • 单表的索引数量不要过多,控制在6个之内,索引的创建和更新也须要时间,能够关注因此占用的存储空间,多列索引还要注意保持顺序才能生效,多列索引也要考虑每一个字段的检索效率,效率高的字段在前。
索引失效的几种状况:
一、字段值的区分度过小,好比性别的 0,1
二、like 使用了前模糊匹配 like '%asdf'
三、使用了函数 date(birthday) 或者进行了计算 a + 50
四、违反左匹配原则 如联合索引 a, b 实际查询使用顺序为 b, a
五、索引列中含有 NULL
相关文章
相关标签/搜索