《酒店项目》数据库

在具体业务代码开发前,要先定义好数据库。数据是 Web 应用的核心了,没有数据就不叫 Web 应用了。

我们选用的是关系型数据库 MySQL 为基础数据库,因为业务中有很明确的实体划分以及实体关系,所以必然是关系型数据库主导的系统。

设计原则

  1. 实体与表的对应关系:通常为一对一,也存在一对多和多对一。比如,员工履历资料在人力资源系统中对应三张表:员工基本信息表、社会关系表和工作简历表。
  2. 主键与外键:在 E-R 图中处于叶子部分的实体可以没有主键,但必须有外键,因为需要使用外键表示叶子与父节点的关系。主键其实代表的是一个实体的高度抽象,外键表示与其他实体的关系。
  3. 基本表:基本表有四个特征:
    1. 原子性:字段不可再分解。
    2. 原始性:基本表中记录的是原始数据或称基础数据。
    3. 演绎性:所有数据都能从基本表派生出来。
    4. 稳定性:基本表的结构应该是长期不变。
  4. 三个范式:
    1. 第一范式:原子性约束,即字段不可分解。
    2. 第二范式:唯一性约束,即记录有唯一标识,对应了实体的唯一性。
    3. 第三范式:字段冗余性约束,即无冗余字段。
  5. 合理冗余:满足第三范式的数据库可是让存储空间最低,但是有时需要提高查找效率,据需要使用冗余字段。这是一种用空间换时间的做法。比如一个商品的存在:单价、数量和价格三个字段,其中价格就是冗余字段,价格字段可以提高统计查询的效率。
  6. 处理多对多关系:为了避免两实体表之间的多对多关系,可以在两表之间增加一个实体表,从而形成两个一对多关系。比如学生和图书之间存在多对多关系,一个学生借阅多本书,一本书被不同的学生借阅过。在这两者之间增加一个“借还记录”实体,每条借还记录都是只对应一本书和一名学生。其实处理多对多的方式就是把实体间的每一条连线(实体间的关系)当作实体看待。
  7. PK取值:可以使用 id,也可以使用多个字段的组合,但不要太多,会使得索引占据空间增加。
  8. E-R 图没有标准答案:好的 E-R 图结构清晰、关联简洁、实体个数适中、属性分配合理、没有低级冗余。
  9. 视图:视图是数据保密手段中的一种。为了进行复杂处理和提高运算速度,视图深度一般不超过三层,如果超过则在视图上定义临时表,再在临时表上添加视图。
  10. 中间表:中间表是一个业务概念,它是为数据仓库、输出报表或查询结果而设计的,有时它没有主键与外键(数据仓库除外)。
  11. 三少原则:表个数少、组合主键包含的字段少、表中字段少

阿里设计规范

  1. 适当冗余:冗余字段不能是频繁修改的字段,不是超长字段。
  2. 单表行数超500万才建议分库分表,如果预计两年后达不到这个数量级就不要分。
  3. id 必须是主键,每个表都要有主键,且保持增长趋势的, 小型系统可以依赖于 MySQL 的自增主键,大型系统或者需要分库分表时才使用内置的 ID 生成器
  4. id类型没有特殊要求,必须使用bigint unsigned,禁止使用int,即使现在的数据量很小。
  5. 字段尽量设置为 NOT NULL,为字段提供默认值。 如字符型的默认值为一个空字符值串’’;数值型默认值为数值 0;逻辑型的默认值为数值 0。
  6. 每个字段和表必须提供清晰的注释。
  7. 时间统一格式:‘YYYY-MM-DD HH:MM:SS’。
  8. 更新数据表记录时,必须同时更新记录对应的 gmt_modified 字段值为当前时间。

阿里命名规范

  1. 表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 unsigned tinyint ( 1表示是,0表示否)。正例:表达逻辑删除的字段名 is_deleted,1 表示删除,0 表示未删除。
  2. 表名、字段名必须使用小写字母或数字,禁止出现数字开头,禁止两个下划线中间只 出现数字。数据库字段名的修改代价很大。说明:MySQL 在 Windows 下不区分大小写,但在 Linux 下默认是区分大小写。
  3. 表名不使用复数名词。
  4. 禁用保留字,如 desc、range、match、delayed 等,请参考 MySQL 官方保留字。
  5. 主键索引名为 pk_字段名;唯一索引名为 uk_字段名;普通索引名则为 idx_字段名。MySQL 主键索引自动生成,其他索引可以选择性创建并按规范命名。
  6. 小数类型为 decimal,禁止使用 float 和 double。
  7. 如果存储的字符串长度几乎相等,使用 char 定长字符串类型。
  8. varchar 是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长 度大于此值,定义字段类型为 text,独立出来一张表,用主键来对应,避免影响其它字段索 引效率。
  9. 表必备三字段:id, is_delete,gmt_create, gmt_modified。gmt_create, gmt_modified 是 date_time 类型。
  10. 所有命名必须使用全名,有默认约定的除外,如果超过 30 个字符,使用缩写,请尽量名字易懂简短,如 description --> desc;information --> info;address --> addr 等。
  11. 表的命名最好是加上“业务名称_表的作用”。 正例:health_user / trade_config。
  12. 库名与应用名称尽量一致。如 health。
  13. 如果修改字段含义或对字段表示的状态追加时,需要及时更新字段注释。
  14. 所有时间字段,都以 gmt_开始,后面加上动词的过去式,最后不要加上 time 单词,例如 gmt_create。

阿里类型规范

  1. 表示状态字段(0-255)的使用 TINYINT UNSINGED,禁止使用枚举 类型,注释必须清晰地说明每个枚举的含义,以及是否多选等。
  2. 表示 boolean 类型的都使用 TINYINT(1),因为 MySQL 本身是没有 boolean 类型的,在自动生成代码的时候,DO 对象的字段就是 boolean 类型,例如 is_delete;其余所有时候都使用 TINYINT(4)。

TINYINT(4),这个括号里面的数值并不是表示使用多大空间存储,而是最大显示宽度,并且只有字段指定 zerofill 时有用,没有 zerofill,(m)就是无用的,例如 id BIGINT ZEROFILL NOT NULL,所以建表时就使用默认就好了,不需要加括号了,除非有特殊需求,例如 TINYINT(1) 代表 boolean 类型。

TINYINT(1),TINYINT(4) 都是存储一个字节,并不会因为括号里的数字改变。例如 TINYINT(4) 存储 22 则会显示 0022,因为最大宽度为 4,达不到的情况下用 0 来补充。

  1. 合适的字符存储长度,不但节约数据库表空间、节约索引存储,更重要的是提升检索速度。
  2. 非负的数字类型字段,都添加上 UNSINGED,如可以使用 INT UNSINGED 字段存 IPV4。
  3. 时间字段使用时间日期类型,不要使用字符串类型存储,日期使用 DATE 类型,年使用 YEAR 类型,日期时间使用 DATETIME。
  4. 字符串 VARCHAR(N),其中 N表示字符个数,请尽量减少 N 的大小,参考:code VARCHAR(32);name VARCHAR(32);memo VARCHAR(512);
  5. Blob 和 Text 类型所存储的数据量大,删除和修改操作容易在数据表里产生大量的碎片,避免使用 Blob 或 Text 类型。

阿里索引规范

  1. 业务上具有唯一特性的字段,即使是多个字段的组合,也必须建成唯一索引。
  2. 超过三个表禁止 join。需要 join 的字段,数据类型必须绝对一致;多表关联查询时,保证被关联的字段需要有索引。
  3. 在 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据 实际文本区分度决定索引长度即可。 说明:索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为 20 的索引,区分度会高达 90% 以上,可以使用 count(distinct left(列名, 索引长度))/count(*)的区分度来确定。
  4. 页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。

索引文件具有 B-Tree 的最左前缀匹配特性,如果左边的值未确定,那么无法使用此索引。

  1. 如果有 order by 的场景,请注意利用索引的有序性。order by 最后的字段是组合索引的一部分,并且放在索引组合顺序的最后,避免出现 file_sort 的情况,影响查询性能。

正例:where a=? and b=? order by c; 索引:a_b_c 。反例:索引中有范围查找,那么索引有序性无法利用,如:WHERE a>10 ORDER BY b;索引 a_b 无法排序。

  1. 利用覆盖索引来进行查询操作,避免回表。如果 select 的字段都是索引的部分,那么数据库不用再对主键索引查询(即回表)。
  2. 利用延迟关联或者子查询优化超多分页场景。

说明:MySQL 并不是跳过 offset 行,而是取 offset+N 行,然后返回放弃前 offset 行,返回 N 行,那当 offset 特别大的时候,效率就非常的低下,要么控制返回的总页数,要么对超过特定阈值的页数进行 SQL 改写。

  1. SQL 性能优化的目标:至少要达到 range 级别,要求是 ref 级别,如果可以是 consts 最好。

    • consts 单表中最多只有一个匹配行(主键或者唯一索引),在优化阶段即可读取到数据。
    • ref 指的是使用普通的索引(normal index)。
    • range 对索引进行范围检索。
  2. 建组合索引的时候,区分度最高的在最左边。

  3. 防止因字段类型不同造成的隐式转换,导致索引失效。

创建索引时避免有如下极端误解:

  • 宁滥勿缺。认为一个查询就需要建一个索引。
  • 宁缺勿滥。认为索引会消耗空间、严重拖慢更新和新增速度。
  • 抵制惟一索引。认为业务的惟一性一律需要在应用层通过“先查后插”方式解决。

总结

  • 索引占磁盘空间,不要重复的索引,尽量短
  • 只给常用的查询条件加索引
  • 过滤性高的列建索引,取值范围固定的列不建索引
  • 唯一的记录添加唯一索引
  • 频繁更新的列不要建索引
  • 不要对索引列运算
  • 同样过滤效果下,保持索引长度最小
  • 合理利用组合索引,注意索引字段先后顺序
  • 多列组合索引,过滤性高的字段最前
  • order by 字段建立索引,避免 filesort
  • 组合索引,不同的排序顺序不能使用索引
  • <>!=无法使用索引

你可能感兴趣的:(酒店项目,java)