数据库结构设计

数据库结构设计

  • 减少数据冗余

  • 尽量避免数据维护中出现更新,插入和删除异常

    • 插入异常:如果表中的某个实体随着另一个实体而存在
    • 更新异常:如果更改表中的某个实体的单独属性时,需要对多行进行更新
    • 删除异常:如果删除表中的某一实体则会导致其他实体的消失
  • 节约数据存储空间

  • 提高查询效率

数据库结构设计的步骤

    1. 需求分析:全面了解产品设计的存储需求
    • 存储需求
    • 数据处理需求
    • 数据的安全性和完整性
    1. 逻辑设计:设计数据的逻辑存储结构
    • 数据实体之间的逻辑关系,解决数据冗余和数据维护异常
    1. 物理设计:根据所使用的数据库特点进行表结构设计
    • 关系型数据库:Oralce,SQLServer,Mysql,postgresSQL
    • 非关系型数据库:mongo,Redis,Hadoop
    • 存储引擎: Innodb
    1. 维护优化:根据实际情况对索引,存储结构等进行优化

数据库设计范式

设计出没有数据冗余和数据维护异常的数据库结构。

  • 数据库设计的第一范式:
    • 数据库表中的所有字段都只具有单一属性
    • 单一属性的列是由基本的数据类型所构成的
    • 设计出来的表都是简单的二维表
  • 数据库设计的第二范式:
    • 要求一个表中只具有一个业务主键,也就是说符合第二范式的表中不能存在非主键列对只对部分主键的依赖关系。
  • 数据库设计的第三范式:
    • 指每一个非主属性既不部分依赖于也不传递依赖于业务主键,也就是在第二范式的基础上消除了非主属性对主键的传递依赖。

物理设计

根据所选择的关系型数据库的特点,对逻辑模型进行存储结构设计。包括:

  • 定义数据库、表及字段的命名规范
  • 选择合适的存储引擎
  • 为表中的字段选择合适的数据类型
  • 建立数据库表具体结构

定义数据库、表及字段的命名规范

数据库、表及字段的命名要遵守:

  • 可读性原则
  • 表意性原则
  • 长名原则

选择合适的存储引擎

存储引擎 事务 锁粒度 主要应用 忌用
MyISAM 不支持 支持并发插入的表级锁 select,insert 读写操作频繁
MRG_MYISAM 不支持 支持并发插入的表级锁 分段归档,数据仓库 全局查找过多的场景
Innodb 支持 支持MVCC的行级锁 事务处理
Archive 不支持 行级锁 日志记录,只支持insert,select 需要随机读取,更新,删除
Ndb cluster 支持 行级锁 高可用性 大部分应用

数据类型的选择

为表中的字段选择合适的数据类型:

  • 当一个列可以选择多种数据类型时,应该优先考虑数字类型。
  • 其次是日期或二进制类型
  • 最后是字符类型。
  • 对于相同级别的数据类型,应该优先选择占用空间小的数据类型。

在对数据进行比较(查询条件、Join条件有关联排序时):字符类型是与排序规则有关系;而数字类型和二进制类型不需要参照这种这种规则,是按照二进制大小进行排序的,同样的数据字符类型处理就比较慢。

数据库中数据存储是以页为单位的,每一页存储的数据量是一定的,Innodb中是16k,数据的长度越小,在每页中能容纳的数据行数就越多,这样在加载同样的数据时,使用的宽度较小的类型就比宽度较大的类型加载的数据页较少,也就减少了磁盘IO,有利于性能的提升。

如何选择正确的整数类型

列类型 存储空间 取值范围(SIGNED) 取值范围(UNSIGNED)
tinyint 1个字节 -128~127 (2^7 ~ 2^7-1) 0~255
smallint 2个字节 -32768 ~ 32767 0~65535
mediumint 3个字节 -8388608 ~ 8388607 0~16777215
int 4个字节 -2147483648 ~ 2147483647 0~4294967295
bigint 8个字节 -9223372036854775808 ~ 9223372036854775807 0 ~ 18446744073709551615

如果只存储两位数,就使用 tinyint 类型,不要使用 int 类型,可以节约空间。

如何选择正确的实数类型

列类型 存储空间 是否精确类型
FLOAT 4个字节
DOUBLE 8个字节
DECIMAL 每4个字节存9个数字,小数点占一个字节

DECIMAL(18,9) 需要 9 个字节来存储。

如何选择 VARCHAR 和 CHAR 类型

  • VARCHAR 类型的存储特点:

    • varchar 用于存储变长字符串,只占用必要的存储空间
    • 列的最大长度小于255则只占用一个额外字节用于记录字符串长度
    • 列的最大长度大于255则要占用两个额外字节用于记录字符串长度
  • VARCHAR 长度的选择问题

    • 使用最小的符合需求的长度
    • varchar(5)和varchar(200)存储’Mysql’字符串性能不同
      • mysql 为了更有效的优化查询,在内存中对字符串的使用是固定的宽度,列太长就会消耗更多的内存。
  • VARCHAR 的适用场景:

    • 字符串列的最大长度比平均长度大很多(发挥变长存储的特点)
    • 字符串列很少被更新(更新,字符串长度会产生变化,可能引起存储页的分裂;还会产生很多存储碎片)
    • 使用了多字节字符集存储字符串(例如utf8,不同字符存储字节数不同,中文和英文就不同)
  • CHAR 类型的存储特点:

    • CHAR 类型是定长的
    • 字符串存储在 CHAR 类型的列中会删除末尾的空格
    • CHAR 类型的最大宽度为 255
  • CHAR 的适用场景:

    • CHAR 类型适合存储所有长度近似的值 (eg: md5值,身份证号,手机号)
    • CHAR 类型适合存储短字符串
    • CHAR 类型适合存储经常更新的字符串列

如何存储日期类型

  • DATATIME 类型

YYYY-MM-DD HH:MM:SS[.fraction] 格式存储日期时间

datetime = YYYY-MM-DD HH:MM:SS

datetime(6) = YYYY-MM-DD HH:MM:SS.fraction

DATATIME类型与时区无关,占用8个字节的存储空间

时间范围:1000-01-01 00:00:00 到 9999-12-31 23:59:59

  • TIMESTAMP 类型

时间戳,存储了由格林尼治时间1970年1月1日到当前时间的秒数

以 YYYY-MM-DD HH:MM:SS.[.fraction] 的格式显示,占用4个字节。

时间范围: 1970-01-01 到 2038-01-19

timestamp 类型显示依赖于所指定的时区

在行的数据修改时,可以自动修改 timestamp 列的值。

  • date类型

存储用户生日时,只需要存储日期部分

一是把日期部分存储为字符串(至少要8个字节)

二是使用int类型来存储(4个字节)

三是使用datetime类型来存储(8个字节)

date 类型的优点:

  1. 占用的字节数比使用字符串、datetime、int存储要少,使用date类型只需要3个字节。

  2. 使用Date类型还可以利用日期时间函数进行日期之间的计算

date类型用于保存 1000-01-01 到 9999-12-31 之间的日期

  • time类型

time类型用于存储时间数据,格式为:HH:MM:SS

  • 存储日期时间数据的注意事项

    • 不要使用字符串类型来存储日期时间数据
      • 日期时间类型通常比字符串占用的存储空间小
      • 日期时间类型在进行查找过滤时可以利用日期来进行对比
      • 日期时间类型还有着丰富的处理函数,可以方便的对时期类型进行日期计算
    • 使用Int存储日期时间不如使用 Timestamp 类型

如何为 Innodb 选择主键

  • 主键应该尽可能的小
  • 主键应该是顺序增长的
    • (Innodb 内部的逻辑顺序是和主键顺序相同的,主键的顺序是顺序增长的,那么插入数据就能顺序插入,避免了随机IO的产生,所以这样可以增加数据的插入效率)
  • Innodb 的主键和业务主键可以不同 (业务主键可以添加唯一索引)

数据库结构:(查询性能要求、范式化要求)

从数据库架构方面优化数据库;
维护和优化:索引&sql优化。