当前位置:网站首页 > 技术博客 > 正文

数据库设计怎么设计



尽管我们不是DBA,但我们平时都会涉及到数据库表的设计,那么我们该怎么设计呢?,表名怎么取?字段名怎么取?字段类型如何设置?字段长度如何设置?.....

我们还是从一个大家觉得很无聊的范式开始说起,

,忍住,加油!看完哟

范式与反范式

优秀的库表设计是高性能数据库的基础。如何才能设计出高性能的库表结构呢?这里必须要提到数据库范式。范式是基础规范,反范式是针对性设计。

范式

范式是关系数据库理论的基础,也是我们在设计数据库结构过程中所要遵循的规则和指导方法。数据库的设计范式是数据库设计所需要满足的规范。只有理解数据库的设计范式,才能设计出高效率、优雅的数据库,否则可能会设计出低效的库表结构。

目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,还又称完美范式)。

满足最低要求的叫第一范式,简称 1NF。在第一范式基础上进一步满足一些要求的为第二范式,简称 2NF。其余依此类推。各种范式呈递次规范,越高的范式数据库冗余越小。通常所用到的只是前三个范式,即:第一范式(1NF),第二范式(2NF),第三范式(3NF)。

第一范式

第一范式无重复的列,表中的每一列都是拆分的基本数据项,即列不能够再拆分成其他几列,强调的是列的原子性.。

如果在实际场景中,一个联系人有家庭电话和公司电话,那么以“姓名、性别、电话”为表头的表结构就没有达到 1NF。要符合 1NF 我们只需把电话列拆分,让表头变为姓名、性别、家庭电话、公司电话即可。

第二范式

第二范式属性完全依赖于主键,首先要满足它符合 1NF,另外还需要包含两部分内容:

第三范式

第三范式属性不传递依赖于其他非主属性,首先需要满足 2NF,另外非主键列必须直接依赖于主键,不能存在传递依赖。即不能存在:非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况。

BCNF(BC范式)

它构建在第三范式的基础上,如果关系模型R是第一范式,且每个属性都不传递依赖于R的候选键,那么称R为BCNF的模式。

第二范式和第三范式的区别

通过对前三个范式的了解,我们知道 3NF 是 2NF 的子集,2NF 是 1NF 的子集。

设计符合 2NF 的表

接下来以订单信息表为例,讲述如何设计一个符合 2NF 的表,首先,我们看原始的订单信息表,如下图所示。

图中,以订单编号和商品编号作为联合主键,商品名称、单位、价格等信息不与主键相关,只与编号相关,违反了第二范式。应该对订单信息表进行拆分,商品信息单独一张表,订单项目一张表,如下所示,拆分分成 3 张表。

范式优缺点
优点
缺点

表的数量越多,查询所需要的时间越多。也就是说所用的范式越高,对数据操作的性能越低。

反范式

范式是普适的规则,满足大多数的业务场景的需求。对于一些特殊的业务场景,范式设计的表,无法满足性能的需求。此时,就需要根据业务场景,在范式的基础之上进行灵活设计,也就是反范式设计。

反范式设计主要从三方面考虑:

反范式设计就是用空间来换取时间,提高业务场景的响应时间,减少多表关联。主要的优点如下。

范式与反范式异同
范式化模型
反范式化模型

关于范式,咱们就说这么多,下面我们来说说关于MySQL的一些使用原子和设计规范。

MySQL使用原则和设计规范

MySQL 虽然具有很多特性并提供了很多功能,但是有些特性会严重影响它的性能,比如,在数据库里进行计算,写大事务、大 SQL、存储大字段等。

想要发挥 MySQL 的最佳性能,。

这里在实践中有个小问题,如何让系统中区分大小写的库表转换为不区分大小写的库表呢?因为要修改底层数据,还是比较麻烦的,操作步骤如下。

MySQL 数据库提供的功能很全面,但并不是所有的功能性能都高效。

以上是基础规范的内容,但并不是全部,只是以点带面,进行粗略的介绍。下面我们开始讲解命名规范,统一的规范命名,可以增加可读性,减少隐式转换。

如何规范命名

这样包含了更多的业务信息,比如:

,格式:名称_后缀。

用户是否有留言 hasmessage,用户是否通过检查 ischecked 等。

程序账号与数据库名称保持一致。如果所有的程序账号都是 root@‘%’,密码也一样,很容易错连到其他的数据库,造成误操作。

数据库规范库表字段的命名,能够提高数据库的易读性,为数据库表设计打下基础。下面我们具体看看表设计的一些规则。

不同表之间的相同字段或者关联字段,字段类型/命名要保持一致;库表字符集和前端程序、中间件必须保持一致的 UTF8mb4。

InnoDB 表的注意事项

备份表/临时表等常见表的设计规范

备份表/临时表等常见表的设计规范如下。

垂直拆分:

按列关联度。

水平拆分:
字段设计要求
禁用 ENUM、SET 类型。

解决方案:使用 TINYINT,在 COMMENT 信息中标明被枚举的含义。is_disable TINYINT UNSIGNED DEFAULT '0' COMMENT '0:启用 1:禁用 2:异常’。

禁用列为 NULL。

解决方案:在列上添加 NOT NULL DEFAULT 缺省值。

禁止 VARBINARY、BLOB 存储图片、文件等。

不建议使用 TEXT/BLOB:

解决方案:拆分成单独的表。

存储字节越小,占用空间越小。尽量选择合适的整型,如下图所示。

int(3)/int(5) 区别

int(3)/int(5) 的区别,如下图所示。

浮点数与定点数区别

浮点数与定点数区别,如下图所示。

从上图中可以观察到:

N 解释

字符集都为 UTF8mb4,中文存储占三个字节,而数据或字母,则只占一个字节。

下面看一下字符类型中 N 的解释。

char 与 varchar 类型

存储字符串长度相同的全部使用 Char 类型;字符长度不相同的使用 Varchar 类型,不预先分配存储空间,长度不要超过 255。

Char 和 Varchar 占用空间的对比,如下图所示。

Varchar 值存储为 1 字节或 2 字节长度前缀加数据。如果值不超过 255 个字节,则列使用一个字节长度;如果值可能需要超过 255 个字节,则列使用两个字节长度。

为什么超过 255 个字节时,必须使用两个字节长度。

使用案例

前面我们说了相关理论,接下来,我们就来搞几个案例实战一把。

IP 处理

因此,我们使用 INT UNSIGNED(占用 4 个字节)存储 IP,非 Char(15)。占 15 个字节。

下图所示,IP:192.168.0.1 与整数之间的转换。

将 IP 的存储从字符型转换成整形,转化后数字是连续的,提高了查询性能,使查询更快,占用空间更小。

TIMESTAMP 处理

同样的方法,我们使用 MySQL 内置的函数(FROM_UNIXTIME(),UNIX_TIMESTAMP()),可以将日期转化为数字,用 INT UNSIGNED 存储日期和时间。

下图示所示,时间 2007-11-30 10:30:19 与整数之间的转换,转化后数字是连续的,占用空间更小,并且可以使用索引提升查询性能。

本案例展示的是,不当的数字类型,导致表无法插入新数据,如下图所示。

当我们使用 load data 进行批量加载数据时,会导致 1467 错误。根据分析,导致 1467 错误是由于 auto_increment 的值,超过了 int 类型的取值范围。

原因分析部分显示,max(seq_id) 为 ,而 int 的范围为 -~ ,还剩余空间 5896,而程序需要导入 1 万行,所以报错。

:将 int 改为 bigint 或者将数据分表。

表大小及使用频率

设计表时,必须考虑表的大小和使用频率,避免由于取值范围过小,导致程序运行失败。

对于 InnoDB 表,要求创建一个与业务无关的主键,比如:每张表以 id 列为主键。但是 id 列非常常见,完全无法表达更深层次的意思,特别是在做两张表的联合查询时,它们都有相同的 id 主键的情况下。

如果你的程序用的是列名,该如何区分 Accounts 表的 id 和 Bugs 的 id 呢?如下图所示,列名 id 并不会使查询变得更加清晰。但如果列名叫作 bug_id 或者 account_id,事情就会变得更加简单。

我们使用主键来定位唯一一条记录,因此主键的列名就应该更加便于理解,如下图所示。

这张新表 Contacts,实现了 Products 和 Accounts 的多对多关系。当一张表有指向两张表的外键时,称这种表为交叉表,它实现了两张表之间的多对多关系。这意味着每个产品都可以通过交叉表和多个账号关联;同样地,一个账号也可以通过交叉表和多个产品关联。当我们“查询指定产品的账号”时,就可以直接使用下面的联合查询语句高效实现。

总结

本次主要是聊一些高性能表设计的规则和案例,大佬勿喷!

本文主要内容可以归纳为以下五点:

本次就说到这里,主要讲了范式和反范式、基础规范、命名规范、表设计规范、高性能数据库表实践。索引相关的,下次分享。

参考 : http://ii066.cn/0klab

版权声明


相关文章:

  • 时间序列分析预测模型2025-06-09 08:30:05
  • 电脑硬盘搜索功能不能用2025-06-09 08:30:05
  • hsqldb与mysql区别2025-06-09 08:30:05
  • udp接口编程2025-06-09 08:30:05
  • linux安装automake2025-06-09 08:30:05
  • 软件的发布2025-06-09 08:30:05
  • layer获取弹出层2025-06-09 08:30:05
  • 代码 对比2025-06-09 08:30:05
  • java中网络编程2025-06-09 08:30:05
  • 使用fread函数读取文本文件2025-06-09 08:30:05