MySQL表设计(三大范式 表的设计)

news2024/11/6 23:08:13

1.上讲约束复习:


1.NOT NULL 非空约束,被指定NOT NULL的列,值不允许为空(必填)

2. UNIQUE 唯一约束,这个列里的值在表中是唯一的,也就是说不能重复

3. PRIMARY KEY 主键约束,可以看做是NOT NULL和UNIQUE的组合可以用一个bigint类型列为表单独指定主键,同时也可以指定主键自增,用auto increment关键字自增操作时,会找到当前列中最大的值,然后在这个基础上加1(+1)

4.DEFAULT 默认约束,如果写入一行记录的时候,指定了默认约束的列,如果在写入数据时没有指定一个确定的值就会用默认值进行填充该字段的值


5.FOREIGN KEY 外键约束,一张表要与另一张表的主键或唯一键进行关键,说明表与表之间的关联关系

2.三大范式

1.范式

数据库的范式是⼀组规则。在设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数 据库,这些不同的规范要求被称为不同的范式。

关系数据库有六种范式:第⼀范式(1NF)、第⼆范式(2NF)、第三范式(3NF)、巴斯-科德 范式(BCNF)、第四范式(4NF)和第五范式(5NF,⼜称完美范式),越⾼的范式数据库冗余越 ⼩。然⽽,普遍认为范式越⾼虽然对数据关系有更好的约束性,但也可能导致数据库IO更繁忙,因此 在实际应⽤中,数据库设计通常只需满⾜第三范式即可。

2.第一范式   确保每个字段的原子性

定义:
• 数据库表的每⼀列都是不可分割的原⼦数据项,⽽不能是集合,数组,对象等⾮原⼦数据。

• 在关系型数据库的设计中,满⾜第⼀范式是对关系模式的基本要求。不满⾜第⼀范式的数据库就不能被称为关系数据库

要求:

  • 每个字段只能包含一个值(没有重复组)。
  • 表中的每一行应当是唯一的,可以通过主键进行标识。

使用:

第一范式要求每个字段(列)只能有一个值,不能是多个值的集合。

不符合第一范式的设计:

假设我们一开始设计了一个学生表,课程 字段存储了多个课程:

插入数据时,可以看到 courses 列存储了多个课程:

我们可以看出这个设计存在问题,courses 列可以储存多个值,违反了第一范式。我们应该将每个课程单独存储。

符合第一范式的设计:

为了遵循第一范式,我们需要将课程数据拆成每个学生每门课程一行:

学生表:

课程表:

然后插入数据:

这样,每个课程都拆成了单独的一行,符合第一范式。

第二范式(2NF):消除部分依赖

定义:
满⾜第⼀范式的基础上,不存在⾮关键字段对任意候选键的部分函数依赖。存在于表中定义了复合 主键的情况下。

候选键:可以唯⼀标识⼀⾏数据的列或列的组合,可以从候选键中选⼀个或多个当做表的主键

要求:

  • 表必须符合第一范式(1NF)。
  • 所有非主键字段必须完全依赖于主键,而不是依赖于主键的一部分。
  • 部分依赖是指,当主键由多个字段组成时,某些非主键字段仅依赖于主键的其中一部分,而不是整个主键。
  • 问题:

    当我们使用复合主键时,如果某些列只依赖于主键的一部分而不是整个复合主键,那么这种依赖就叫做“部分依赖”,这违反了第二范式。

不符合第二范式的设计:

假设我们设计了一个订单表,其中 订单号商品ID 组成复合主键:

假设插入以下数据:

解释:

  • 主键:(order_id, product_id),这个复合主键的意思是每个订单(order_id)包含多个商品(product_id),每个商品的数量(quantity)将会是订单明细的一部分。
  • 然而,product_name 字段并不依赖于 order_id(订单号),它仅依赖于 product_id(商品ID)。也就是说,product_name 是与 product_id 紧密相关的,但不依赖于 order_id

具体来说:

  • 订单号 (order_id) 决定了订单的唯一性。
  • 商品ID (product_id) 决定了商品的唯一性。
  • 但商品的名字(product_name)只与商品ID (product_id) 相关,而与订单号 (order_id) 无关。

因此,product_name 并没有完全依赖于整个复合主键(order_idproduct_id),它只是部分依赖于 product_id。这就违反了第二范式的要求。

为什么这违反了第二范式?

根据第二范式的要求,所有非主键字段必须完全依赖于复合主键,而不能只依赖于主键的一部分。在我们的设计中,product_name 只依赖于 product_id,而不是完整的复合主键 (order_id, product_id)。因此,product_name 存在部分依赖,违反了第二范式。

符合第二范式的设计:

为了使表符合第二范式,我们需要消除部分依赖。具体来说,我们可以将 product_name 字段移到一个单独的表中,专门存储商品信息,这样 product_name 就会只依赖于 product_id,而不是依赖于复合主键 (order_id, product_id)

新的设计方案:
  1. 订单表 (orders):存储订单信息。

2.商品表 (products):存储商品信息,每个商品有一个 product_idproduct_name

3.订单明细表 (order_items):存储每个订单的商品信息。主键依然是 (order_id, product_id),但是商品信息不再在此表中存储,而是通过 product_id 关联到 products 表。

数据插入示例:

插入订单数据:

插入商品数据:

插入订单明细数据:

解释:
  • product_name 现在存储在 products 表中,且只依赖于 product_id。它不再依赖于复合主键 (order_id, product_id)
  • order_items 表只存储每个订单的商品和数量,不再包含商品名称,商品名称通过 product_id 关联到 products 表中。

通过这种设计:

  • product_name 不再存在部分依赖,它完全依赖于 product_id
  • order_items 表现在只存储与订单相关的信息,完全符合第二范式。

不满⾜第⼆范式时可能出现的问题

1. 数据冗余

学⽣的姓名、年龄、性别和课程的学分在每⾏记录中重复出现,造成了⼤量的数据冗余。

2. 更新异常

如果要调整MySQL的学分,那么就需要更新表中所有关于MySQL的记录,⼀旦执⾏中断导致某些 记录更新成功,某些数据更新失败,就会造成表中同⼀⻔课程出现不同学分的情况,出现数据不⼀致 问题。

3. 插⼊异常

⽬前这样的设计,成绩与每⼀⻔课和学⽣都有对应关系,也就是说只有学⽣参加选修课程考试取 得了成绩才能⽣成⼀条记录。当有⼀⻔新课还没有学⽣参加考试取得成绩之前,那么这⻔新课在数据 库中是不存在的,因为成绩为空时记录没有意义。

4. 删除异常

把毕业学⽣的考试数据全都删除,此时课程和学分的信息也会被删除掉,有可能导致⼀段时间 内,数据库⾥没有某⻔课程和学分的信息。

5.解决方案

将依赖于主键一部分的字段(如 product_name)移动到另一个独立的表中,确保每个非主键字段都完全依赖于整个复合主键。

第三范式(3NF):避免不必要的间接依赖

什么是第三范式?
第三范式要求数据表符合第二范式,并且消除传递依赖。传递依赖是指:如果字段A依赖于字段B,字段B又依赖于字段C,那么字段A间接依赖于字段C。为了避免这种情况,我们需要确保每个字段只直接依赖于主键。

第三范式(3NF)的要求:

  1. 表必须符合第二范式(2NF),即消除部分依赖。
  2. 消除传递依赖:如果一个非主键字段依赖于另一个非主键字段,那么这就是传递依赖。第三范式要求非主键字段只能直接依赖于主键,而不能间接依赖于主键。

什么是传递依赖?

假设有一个表,表中的字段依赖于主键的某些其他字段,而这些字段并不直接依赖于主键本身,而是通过其他非主键字段间接依赖。这种依赖称为传递依赖

不符合第三范式的设计示例:

假设我们设计了一个员工表employees),包含 部门编号部门名称 两个字段。

插入数据:

为什么这个设计违反了第三范式?

  • 传递依赖的存在
    • employee_id 是主键,它唯一标识每一行。
    • department_id 依赖于 employee_id,而 department_name 依赖于 department_id。因此,department_name 通过 department_id 间接依赖于主键 employee_id
    • 问题department_name 不应该依赖于 department_id,而是应该依赖于 department_id 的表。我们应该消除这种间接依赖,确保所有的非主键字段只直接依赖于主键。

这种情况下,department_name 是通过 department_id 间接依赖于主键 employee_id,这就是传递依赖。根据第三范式,非主键字段(department_name)应当直接依赖于主键(employee_id),而不是依赖于其他非主键字段。

符合第三范式的设计:

为了消除传递依赖,我们可以将 department_name 字段移动到一个独立的表中,专门存储部门信息。这样,department_name 就会直接依赖于 department_id,而不会通过 employee_id 间接依赖。

新的设计方案:
  1. 员工表 (employees):只存储与员工相关的信息,去掉 department_name 字段。

2.部门表 (departments):存储部门信息,每个部门有 department_iddepartment_name

数据插入示例:

插入部门数据:

插入员工数据:

解释:
  • employees 表中,department_id 作为外键引用了 departments 表中的 department_id,不再存储 department_name
  • departments 表专门存储了部门信息,department_name 直接依赖于 department_id,而 department_idemployees 表中作为外键,依赖于 employee_id

通过这种方式,department_name 不再依赖于 employee_id,而是直接依赖于 department_id,从而消除了传递依赖,符合第三范式。

总结:

  • 传递依赖:在原设计中,department_name 通过 department_id 间接依赖于主键 employee_id,这就是传递依赖。
  • 符合第三范式的设计:将 department_name 移到独立的部门表中,department_name 直接依赖于 department_id,而 employee_id 只与员工信息相关,消除了传递依赖,符合第三范式。

通过这样的调整,表结构更加简洁,避免了数据冗余和更新异常,提高了数据库的一致性和完整性。

3. 设计过程

需求分析阶段

在开始设计数据表之前,首先需要进行详细的需求分析,这一阶段的关键是了解应用的业务需求和系统的功能。通过与客户、开发团队、产品经理等的沟通,收集以下信息:

  • 业务流程:了解业务的流程和操作步骤,确定哪些数据需要存储。
  • 数据类型:识别哪些数据需要存储,并明确所有数据的属性。
  • 数据关系:明确不同数据之间的关系,是否需要多表关联,主键、外键如何设计。
  • 查询需求:确定系统将如何查询、筛选和统计数据,这有助于升级优化索引和查询性能。
  • 数据一致性:了解数据的完整性要求,确保数据的准确性和一致性。

2.定义实体和属性

在需求分析之后,接下来就是**定义实体(表)属性(字段)**的阶段。这一步的目标是确定存储哪些数据及其具体的结构。你可以通过以下步骤完成这个阶段:

实体被识别

实体是需要存储在数据库中的业务对象。例如,在一个电商系统中,常见的实体可能包括:

  • 用户(用户)
  • 订单(命令)
  • 商品(产品)
  • 支付(支付)
属性定义

每个实体都有自己的属性,这些属性决定了表中的列。比如,用户实体可能有以下属性:

  • 用户ID(user_id
  • 用户名(username
  • 密码(password
  • 电子邮箱(email
  • 注册时间(registration_date

3.设计结构

根据后续实体和属性的定义,开始设计数据库表结构。包括以下几个关键点:

确定主键(Primary Key)

每个表格必须有一个主键,主键用于唯一标识一行数据,保证数据的唯一性。主键的选择原则:

  • 唯一性:主键值必须唯一,不能重复。
  • 不可为空:主键字段不能为空(NULL)。
  • 稳定性:主键值应稳定,易于改变。

例如,用户表的主键可以是user_id

选择项

为每个存储字段的数据选择合适的数据类型。例如:

  • 对于字符串数据使用VARCHARTEXT类型。
  • 对于整数数据使用INTBIGINT类型。
  • 对于时间日期数据使用DATETIMETIMESTAMP类型。
定义约束
  • 唯一约束UNIQUE):确保字段中的值是唯一的,例如用户名和电子邮件地址。
  • 外键约束FOREIGN KEY):定义表与表之间的关联关系,例如订单表中的user_id外键,指向用户表user_id
  • 非空约束NOT NULL):确保字段不能为空。
  • 默认值DEFAULT):字段没有值时使用的默认值。
设计索引(Index)

索引是为了加速查询而创建的数据结构。可以在用于经常查询条件的字段(如user_idorder_date)上创建索引,以提高查询性能。注意:

  • 索引可以加速查询,但同时也会影响插入、更新操作的性能。
  • 不要在每个字段上都创建索引,应该根据实际的查询需求来优化索引。

4. 实体-关系图

实体-关系图(Entity-RelationshipDiagram)简称E-R图,也称作实体联系模型、实体关系模型,是 ⼀种⽤于描述数据模型的概念图,主要⽤于数据库设计阶段。

 E-R图的基本组成 E-R图包含了以下三种基本成分:

• 实体:即数据对象,⽤矩形框表⽰,⽐如⽤⼾、学⽣、班级等。

• 属性:实体的特性,⽤椭圆形或圆⻆矩形表⽰,如学⽣的姓名、年龄等。

• 关系:实体之间的联系,⽤菱形框表⽰,并标明关系的类型,并⽤直线将相关实体与关系连接起 来。

关系的类型:

1. ⼀对⼀关系(1:1)

• ⼀个⽤⼾实体包含的属性有:⽤⼾昵称,真实姓名,⼿机号,邮箱地址,性别,学校

• ⼀个账⼾实体包含的属性有:登录⽤⼾名,密码

• ⽤⼾实体与账⼾实体是⼀对⼀的关系,⽤E-R图表⽰如下:

2 ⼀对多关系(1:N)

• ⼀个学⽣实体包含的属性有:真实姓名,学号,年龄,性别,⼊学时间

• ⼀个班级实体包含的属性有:班级名,学⽣⼈数

• ⼀个班级中有多个学⽣,所以班级实体与学⽣实体是⼀对多的关系,反过来说学⽣实体与班级实体 是多对⼀着么,⽤E-R图表⽰如下:

3 多对多关系(M:N)

• ⼀个学⽣实体包含的属性有:真实姓名,学号,年龄,性别,⼊学时间

• ⼀个课程实体包含的属性有:课程名

• ⼀个学⽣可以选修改多⻔课程,⼀⻔课程也可以被多名学⽣选修改,所以学⽣与课程之间是多对多 关系,⽤E-R图表⽰如下:

• 对于多对多关系,可以使⽤中间表进⾏记录,⽐如⼀个学⽣参加了某⼀⻔课程的考试得到了相应的 成绩,⽤E-R图表⽰如下:

5.数据规范化

数据规范化是指通过剔除数据表,保证数据表的结构简洁、稳定性。规范化过程分为不同的范式,通常包括以下几个阶段:

  • 第一范式(1NF):确保表中的每一列都是原子性的,即每一列只能包含一个值。
  • 第二范式(2NF):确保每个非主键字段完全依赖于主键,消除部分依赖。
  • 第三范式(3NF):消除供货依赖,确保每个非主键字段只直接依赖于主键。

6.性能。

在完成基本的表结构设计后,考虑到数据库的查询性能和扩展性,进行一些优化:

索引优化
  • 对常用查询条件字段(如user_idorder_id)建立索引。
  • 对涉及范围查询(如时间区间查询)的字段建立合适的索引。
  • 避免对小表创建过多的索引,因为它们会增加数据库的写入操作成本。
分表

如果表的数据量非常大,可能需要进行分表(水平分割)或分区(垂直分割)。例如,可以将订单表按日期分区,或者将用户表按地区分割表。

7.安全性和备份

  • 数据安全性:确保对敏感数据(如密码)进行加密存储。可以使用加密算法存储密码,避免明文存储。
  • 数据备份:设计数据库策略备份,定期备份数据库以防止数据丢失。

8.实现和测试

最后,将设计好的数据表转化为SQL语句,执行数据库创建操作。在实现过程中,确保:

  • 测试数据的权限:确保表设计不违反数据约束、数据依赖等规则。
  • 查询性能测试:测试常用的查询是否快速,特别是对于大数据量的查询。

总结:

在数据库设计的历程中,我们最大的架构师,构建了一座数据的大厦!从需求分析到表格结构设计,每一步都充满了挑战和创意。通过仔细梳理业务需求,我们为数据定义了语音的“身份”,让每个表都成为数据的家,确保他们井然有序且不显现。

我们不仅要保证数据的一致性,还要让它们始高效性,让查询速度

而为了应对未来的增长,我们更通过索引优化和**分区设计分区设计,让数据库

设计好一个数据库表,意味着你为数据架建立了一个坚固又高效的桥梁。通过表与表之间紧密的关系,每一条数据都能顺利流动,应用系统也能流畅运行。最后,我们还要时刻关注安全性和备份

总的来说,数据库设计不仅仅是技术工作,它是一门思维的艺术!每一个设计决策都决定了系统的未来,它是数据和业务需求聚合的完美融合。希望数据库设计的旅程,能够让你愉快地掌握如何设计出、安全、易于维护的高效数据库系统

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2234583.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【修订中】js 中apply call bind 用法

一、call、apply可以翻译成继承或者借调 区别:传参不同 可以调用函数可以改变函数中this的指向 二、js 语法词法: 普通函数 构造函数: 为什么不在构造函数中写方法 function Student(n, a) {this.uname n;this.age a;this.sayHi func…

Android15音频进阶之Cuttlefish搭建音频开发环境(九十二)

简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+…

【Unity】Unity拖拽在Android设备有延迟和卡顿问题的解决

一、介绍 在制作Block类游戏时,其核心的逻辑就是拖拽方块放入到地图中,这里最先想到的就是Unity的拖拽接口IDragHandler,然后通过 IPointerDownHandler, IPointerUpHandler 这两个接口判断按下和松手,具体的实现逻辑就是下面 public void On…

如何理解ETLCloud在iPaas中的关键角色

在当今的数字化时代,企业越来越依赖于其处理和分析数据的能力。为了实现这一目标,企业需要将各种异构的应用和数据源集成在一起,形成一个统一的数据视图。在这一过程中,ETL(Extract, Transform, Load)和iPa…

Linux多线程(个人笔记)

Linux多线程 1.Linux线程概念1.1线程的优点1.2线程的缺点 2.Linux线程VS进程3.Linux线程控制3.1创建线程3.2线程tid及进程地址空间布局3.3线程终止3.4线程等待 4.分离线程5.线程互斥5.1互斥锁mutex5.2互斥锁接口5.3互斥锁实现原理5.4可重入VS线程安全 6.线程同步6.1条件变量6.2…

【案例】故障雪花屏

开发平台:Unity 6.0 开发工具:Shader Graph 参考视频:【U2D Shader Graph】❄️雪❄️花❄️屏❄️   一、效果图 二、Shader Graph 路线图 三、案例分析 核心思路:雪花屏幕效果 (混合) 原图像 最终图像…

Hunyuan-Large:推动AI技术进步的下一代语言模型

腾讯近期推出了基于Transformer架构的混合专家(MoE)模型——Hunyuan-Large(Hunyuan-MoE-A52B)。该模型目前是业界开源的最大MoE模型之一,拥有3890亿总参数和520亿激活参数,展示了极强的计算能力和资源优化优…

arkUI:Column和Rom的间距设置(列向,横向)

arkUI:Column和Rom的间距设置(列向,横向) 1 主要内容说明2 相关内容举例和说明2.1 Column的间距(列的间距)2.1.1 源码1 (Column的间距)2.1.2 源码1运行效果 2.2 Row的间距&#xff0…

QML项目实战:自定义Combox

目录 一.添加模块 import QtQuick.Controls 2.4 import QtQuick.Templates 2.4 as T import QtGraphicalEffects 1.15 import QtQuick 2.15 as T2 二.自定义Combox 1.combox文字显示 2.设置下拉图标显示 3.下拉框中选中背景设置 4.下拉框中选中文字设置 5.下拉框设置…

【设计模式系列】原型模式(十一)

一、什么是原型模式 原型模式(Prototype Pattern)是一种创建型设计模式,它使得一个对象可以复制自身,从而创建一个与自己属性一致的新对象,而无需知晓对象创建的细节。这种模式允许动态地增加对象的数量,并…

h5web浏览器获取腾讯地图经纬度

https://lbs.qq.com/dev/console/application/mine 去腾讯地图申请key 然后前端页面引用 <script type"text/javascript" src"https://apis.map.qq.com/tools/geolocation/min?key自己的key&referertest"></script>调用代码 let geoloca…

微积分复习笔记 Calculus Volume 1 - 4.6 | Limits at Infinity and Asymptotes

4.6 Limits at Infinity and Asymptotes - Calculus Volume 1 | OpenStax

开源的flash浏览器 CelfFlashBrowser

特点 不用安装flash就可以玩flash游戏。 可播放在线和本地的swf文件 下载地址 &#xff1a;https://github.com/Mzying2001/CefFlashBrowser

游戏引擎中的颜色科学

游戏引擎中的渲染组件的作用是生成一个二维图片&#xff0c;在特定的时间从给定的视点观察的方向看到的一个三维空间的状态。他们的生成每一张图片都会被称为帧&#xff0c;他们生成的速度称为帧率。 像素 在每一帧中&#xff0c;游戏引擎的视觉输出基本上是一大堆彩色像素&a…

css中pointer-events:none属性对div里面元素的鼠标事件的影响

文章目录 前倾提要当没有设置属性pointer-events时候结果 当子元素设置了pointer-events: none修改后的代码结果如下所示 当父元素设置了pointer-events: none若两个div同级也就是兄弟级 前倾提要 在gis三维开发的地图组件上放一个背景图片&#xff0c;左右两侧的颜色渐变等&a…

中科蓝汛GPIO操作说明

概述 本篇文章介绍如何使用中科蓝汛AB5681&#xff0c;GPIO管脚使用说明。 一、第一种写法 1&#xff09;、GPIO配置输入模式 //内部上拉 GPIOBDE | BIT(4); //数字IO使能: 0为模拟IO, 1 为数字IO GPIOBDIR | BIT(4); //控制IO的方向: 0为输出, 1为输入. GPIOBFEN &…

Kotlin 协程使用及其详解

Kotlin协程&#xff0c;好用&#xff0c;但是上限挺高的&#xff0c;我一直感觉自己就处于会用&#xff0c;知其然不知其所以然的地步。 做点小总结&#xff0c;比较浅显。后面自己再继续补充吧。 一、什么是协程&#xff1f; Kotlin 协程是一种轻量级的并发编程方式&#x…

LabVIEW 离心泵机组故障诊断系统

开发了一套基于LabVIEW图形化编程语言设计的离心泵机组故障诊断系统。系统利用先进的数据采集技术和故障诊断方法&#xff0c;通过远程在线监测与分析&#xff0c;有效提升了离心泵的预测性维护能力&#xff0c;保证了石油化工生产的连续性和安全性。 项目背景及意义 离心泵作…

线程函数和线程启动的几种不同形式

线程函数和线程启动的几种不同形式 在C中&#xff0c;线程函数和线程启动可以通过多种形式实现。以下是几种常见的形式&#xff0c;并附有相应的示例代码。 1. 使用函数指针启动线程 最基本的方式是使用函数指针来启动线程。 示例代码&#xff1a; #include <iostream&g…

辐射传输方程的分解

Decomposition of the Boundary Value Problem for Radiative Transfer Equation of MODIS and MISR instruments 0.Notions Let L L L be the straming-collision operator, and S S S is scattering operator: L I Ω ⋅ ∇ I ( r , Ω ) σ ( r , Ω ) I ( r , Ω ) S…