数据库三范式简单理解

数据库设计当中三范式是经常遇到的,如果实际项目数据库设计中能达到第三范式基本也就满足要求了,那么如何快速有效的理解三个范式,同时应用于实际项目中去呢?

首先看看标准定义的三个范式:

第一范式(1NF)

所谓第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。如果出现重复的属性,就可能需要定义一个新的实体,新的实体由重复的属性构成,新实体与原实体之间为一对多关系。在第一范式(1NF)中表的每一行只包含一个实例的信息。

在任何一个关系数据库中,第一范式(1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据库。

我的理解:列不可分。

第二范式(2NF)

第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。第二范式(2NF)要求数据库表中的每个实例或行必须可以被惟一的区分。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。要求实体的属性完全依赖于主关键字。

我的理解:不能部分依赖。即:一张表存在组合主键时,其他非主键字段不能部分依赖。

第三范式(3NF)

 满足第三范式(3NF)必须先满足第二范式(2NF)。简而言之,第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。

在第二范式的基础上,数据表中如果不存在非关键字段对任一候选关键字段的传递函数依赖则符合第三范式。

我的理解:不能存在传递依赖。即:除主键外,其他字段必须依赖主键。

官方标准的定义,我个人感觉说得非常术语化,比较难以理解消化。我简单的理解为三句话,非常简短,比较好理解。如果各位路过朋友们,有更好理解的总结,请不吝指出!


二,,

1.第一范式(确保每列保持原子性)

第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值,就说明该数据库表满足了第一范式。

第一范式的合理遵循需要根据系统的实际需求来定。比如某些数据库系统中需要用到“地址”这个属性,本来直接将“地址”属性设计成一个数据库表的字段就行。但是如果系统经常会访问“地址”属性中的“城市”部分,那么就非要将“地址”这个属性重新拆分为省份、城市、详细地址等多个部分进行存储,这样在对地址中某一部分操作的时候将非常方便。这样设计才算满足了数据库的第一范式,如下表所示。

上表所示的用户信息遵循了第一范式的要求,这样在对用户使用城市进行分类的时候就非常方便,也提高了数据库的性能。

                

2.第二范式(确保表中的每列都和主键相关)

第二范式在第一范式的基础之上更进一层。第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。也就是说在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。

比如要设计一个订单信息表,因为订单中可能会有多种商品,所以要将订单编号和商品编号作为数据库表的联合主键,如下表所示。

 订单信息表

这样就产生一个问题:这个表中是以订单编号和商品编号作为联合主键。这样在该表中商品名称、单位、商品价格等信息不与该表的主键相关,而仅仅是与商品编号相关。所以在这里违反了第二范式的设计原则。

而如果把这个订单信息表进行拆分,把商品信息分离到另一个表中,把订单项目表也分离到另一个表中,就非常完美了。如下所示。

这样设计,在很大程度上减小了数据库的冗余。如果要获取订单的商品信息,使用商品编号到商品信息表中查询即可。

                 

3.第三范式(确保每列都和主键列直接相关,而不是间接相关)

第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关

比如在设计一个订单数据表的时候,可以将客户编号作为一个外键和订单表建立相应的关系。而不可以在订单表中添加关于客户其它信息(比如姓名、所属公司等)的字段。如下面这两个表所示的设计就是一个满足第三范式的数据库表。

这样在查询订单信息的时候,就可以使用客户编号来引用客户信息表中的记录,也不必在订单信息表中多次输入客户信息的内容,减小了数据冗余。



三,,,

sql sever 中如何在两个表之间建立参照关系
这个是通过创建一种称为   “外键”  的东西, 来建立  参照关系的。



例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
-- 创建测试主表. ID 是主键.
CREATE  TABLE  test_main (
   id       INT    NOT  <a href= "https://www.baidu.com/s?wd=NULL&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1dWPWczPH0vnhnYmW6vrHD40ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6K1TL0qnfK1TL0z5HD0IgF_5y9YIZ0lQzqlpA-bmyt8mh7GuZR8mvqVQL7dugPYpyq8Q1DdnH0knjmsPWR3PHb4PWc3PW0"  target= "_blank"  class= "baidu-highlight" > NULL </a>,
   value   <a href= "https://www.baidu.com/s?wd=VARCHAR&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1dWPWczPH0vnhnYmW6vrHD40ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6K1TL0qnfK1TL0z5HD0IgF_5y9YIZ0lQzqlpA-bmyt8mh7GuZR8mvqVQL7dugPYpyq8Q1DdnH0knjmsPWR3PHb4PWc3PW0"  target= "_blank"  class= "baidu-highlight" > VARCHAR </a>(10),
   PRIMARY  <a href= "https://www.baidu.com/s?wd=KEY&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1dWPWczPH0vnhnYmW6vrHD40ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6K1TL0qnfK1TL0z5HD0IgF_5y9YIZ0lQzqlpA-bmyt8mh7GuZR8mvqVQL7dugPYpyq8Q1DdnH0knjmsPWR3PHb4PWc3PW0"  target= "_blank"  class= "baidu-highlight" > KEY </a>(id)  
);
 
 
-- 创建测试子表. 
CREATE  TABLE  test_sub (
   id       INT   NOT  <a href= "https://www.baidu.com/s?wd=NULL&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1dWPWczPH0vnhnYmW6vrHD40ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6K1TL0qnfK1TL0z5HD0IgF_5y9YIZ0lQzqlpA-bmyt8mh7GuZR8mvqVQL7dugPYpyq8Q1DdnH0knjmsPWR3PHb4PWc3PW0"  target= "_blank"  class= "baidu-highlight" > NULL </a>,
   main_id  INT  ,
   value   <a href= "https://www.baidu.com/s?wd=VARCHAR&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1dWPWczPH0vnhnYmW6vrHD40ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6K1TL0qnfK1TL0z5HD0IgF_5y9YIZ0lQzqlpA-bmyt8mh7GuZR8mvqVQL7dugPYpyq8Q1DdnH0knjmsPWR3PHb4PWc3PW0"  target= "_blank"  class= "baidu-highlight" > VARCHAR </a>(10),
   PRIMARY  <a href= "https://www.baidu.com/s?wd=KEY&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1dWPWczPH0vnhnYmW6vrHD40ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6K1TL0qnfK1TL0z5HD0IgF_5y9YIZ0lQzqlpA-bmyt8mh7GuZR8mvqVQL7dugPYpyq8Q1DdnH0knjmsPWR3PHb4PWc3PW0"  target= "_blank"  class= "baidu-highlight" > KEY </a>(id)  
);
 
 
-- 插入测试主表数据.
INSERT  INTO  test_main(id, value)  VALUES  (1,  'ONE' );
INSERT  INTO  test_main(id, value)  VALUES  (2,  'TWO' );
 
-- 插入测试子表数据.
INSERT  INTO  test_sub(id, main_id, value)  VALUES  (1, 1,  'ONEONE' );
INSERT  INTO  test_sub(id, main_id, value)  VALUES  (2, 2,  'TWOTWO' );
 
 
 
下面这个语句,  在  主表与子表之间, 创建一个关系
ALTER  TABLE  test_sub  ADD  CONSTRAINT  main_id_cons   FOREIGN  <a href= "https://www.baidu.com/s?wd=KEY&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1dWPWczPH0vnhnYmW6vrHD40ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6K1TL0qnfK1TL0z5HD0IgF_5y9YIZ0lQzqlpA-bmyt8mh7GuZR8mvqVQL7dugPYpyq8Q1DdnH0knjmsPWR3PHb4PWc3PW0"  target= "_blank"  class= "baidu-highlight" > KEY </a> (main_id)   REFERENCES   test_main;


四,,举个例子

请问,如何将如图所示的这张数据库表分割成符合第三范式(3NF)的几张表?




用户,学院,专业,年级,班级
用户(用户编号userid,用户名username,密码password,性别sex,权限authority,班级编号classid),主键是userid,外键是classid
学院(学院编号collegeid,学院名称college),主键是collegeid
专业(专业编号specialtyid,专业名称specialty,方向direction,学院编号collegeid),主键是specialtyid,外键是collegeid
年级(年级编号gradeid,年级名称grade),主键是gradeid
班级(班级编号classid,班级名称class,专业编号specialtyid,辅导员mother,班长monitor,年级编号gradeid),主键是classid,外键是专业编号specialtyid,辅导员mother(参照userid),班长monitor(参照userid),年级编号gradeid

五,,,好处
数据库的三范式对数据库来说是是具有一定好处的,先抛开定义不谈,每当设计数据库的时候,往往会具有较大的数据库体系,也就是每个表之间的关系,不同表中某些属性都具有一定的关系,因为具有关联,所以数据在存储的时候逻辑会比较复杂,如果不按照一定的规则来存储数据就会有乱子,就像你开车一样,没有交通规则不就混乱了么?因此,在数据库设计的时候满足范式要求可以很大限度的合理的处理数据,减少数据的冗余,即多余的用数据,当然范式的优点也不仅仅体现在这方面。
但换句话说,如果在某些特定的情况下还死死遵循范式也是不可取的,因为可能降低数据库的效率,数据库的设计应该根据当前情况和需求做出灵活的处理。
<think>好的,我现在需要详细解释数据库范式及其应用场景。首先,用户已经提供了一些参考资料,我需要仔细阅读这些引用内容,确保准确理解每个范式的定义和目的。同时,用户要求使用中文回答,并且符合特定的格式要求,比如行内数学表达式用$...$,独立公式用$$...$$,不过根据引用内容,可能数学公式较少,但需要注意LaTeX语法的正确性。 首先,我需要明确范式的每个级别: 第一范式(1NF)要求每个字段都是不可分割的原子值。比如,地址字段不能包含省、市、区等多个信息,而应拆分成多个字段。引用[1]和[2]都提到了这一点,我需要确认是否正确。 第二范式(2NF)在满足1NF的基础上,消除非主属性对候选码的部分函数依赖。这意味着每个非主属性必须完全依赖于主键,而不是部分依赖。例如,订单详情表中,如果主键是订单ID和产品ID,那么其他字段如产品数量应完全依赖于这两个字段,而不是仅依赖其中一个。引用[1]、[2]和[5]可能对此有描述,需要核对。 第范式(3NF)在满足2NF的基础上,消除非主属性之间的传递依赖。即非主属性必须直接依赖于主键,不能通过其他非主属性间接依赖。例如,学生表中包含学号、学院和院长,如果院长依赖于学院,而学院依赖于学号,那么院长就传递依赖于学号,这不符合3NF,需要拆分。引用[1]、[3]、[4]和[5]应该提到了这点。 应用场景方面,需要说明何时应该遵循范式,何时可以反范式。引用[3]和[4]提到,高范式可能降低查询效率,因为需要更多的JOIN操作,因此在读多写少或性能要求高的情况下,可能采用反范式设计,增加冗余字段。例如,在用户信息表中,如果经常需要查询用户名和头像,可以在多个表中冗余这些字段,避免频繁关联用户表。 同时,需要确保回答结构清晰,分点解释每个范式,给出示例,然后讨论应用场景和反范式的权衡。还要注意引用标记的正确添加,例如在提到消除数据冗余时引用[1],在讨论查询效率时引用[3]和[4]。 接下来,检查是否有遗漏点,比如每个范式的优缺点,以及它们解决的问题。例如,1NF解决数据原子性问题,2NF解决部分依赖带来的冗余,3NF解决传递依赖的问题。同时,反范式设计可能带来的数据冗余和潜在的一致性问题,如更新异常,但提升查询性能。 最后,生成相关问题,要确保问题与范式相关,并且覆盖概念、应用、优缺点等方面。例如,如何判断是否符合某个范式,反范式的具体例子,范式与性能的权衡等。 现在需要组织内容,确保符合用户的格式要求,正确使用引用标记,语言简洁明了,结构清晰。同时,避免使用Markdown格式,但根据用户提供的示例,可能需要使用代码块来展示示例,比如表格结构。不过用户示例中的代码块是Python,这里可能需要用SQL示例,但根据引用内容,是否有必要?例如,引用[4]提到反范式化的例子,如增加冗余字段,可以用一个用户表和订单表中冗余用户名的例子。 总结步骤: 1. 分点介绍范式,每个范式的定义、示例、解决的问题。 2. 应用场景:何时遵循范式,何时反范式。 3. 优缺点对比。 4. 相关问题生成。</think>### 数据库范式详解及应用场景 #### 一、范式定义与作用 1. **第一范式(1NF)** - **定义**:字段是原子的、不可再分的。 - **示例**:若用户表包含字段$(\text{地址})$存储“北京市海淀区”,需拆分为$(\text{省})$、$(\text{市})$、$(\text{区})$。 - **作用**:消除重复数据存储,避免查询复杂度[^1]。 2. **第二范式(2NF)** - **定义**:在满足1NF的基础上,消除非主属性对候选码的**部分函数依赖**。 - **示例**:订单详情表中,若主键为$(\text{订单ID}, \text{产品ID})$,但$(\text{产品价格})$仅依赖$\text{产品ID}$,则需拆分为订单表和产品表[^2]。 - **作用**:解决数据冗余和更新异常(如修改产品价格需更新多条记录)[^5]。 3. **第范式(3NF)** - **定义**:在满足2NF的基础上,消除非主属性间的**传递依赖**。 - **示例**:学生表中,若$\text{学号} \rightarrow \text{学院} \rightarrow \text{院长}$,需拆分为学生表和学院表[^3]。 - **作用**:进一步减少冗余,避免因间接依赖导致的数据不一致[^1]。 #### 二、应用场景与权衡 1. **遵循范式的场景** - **事务型系统(OLTP)**:如银行系统,需频繁插入、更新数据,范式设计可减少冗余并保证一致性。 - **数据规范性要求高**:如政府档案管理,需避免数据重复和歧义[^1]。 2. **反范式化的场景** - **分析型系统(OLAP)**:如报表统计,通过冗余字段减少多表关联,提升查询效率[^4]。 - **高并发读场景**:如电商首页展示商品信息,冗余商品名称、价格到订单表,避免频繁JOIN。 #### 、优缺点对比 | **范式级别** | **优点** | **缺点** | |--------------|----------------------------|------------------------------| | 高范式(3NF)| 数据冗余少,更新效率高 | 查询需多表关联,性能可能下降 | | 反范式 | 查询速度快,结构简单 | 数据冗余,需维护一致性 | #### 四、示例:反范式化设计 ```sql -- 用户表(范式设计) CREATE TABLE user ( user_id INT PRIMARY KEY, username VARCHAR(50), avatar_url VARCHAR(100) ); -- 订单表(反范式设计:冗余用户名和头像) CREATE TABLE order ( order_id INT PRIMARY KEY, user_id INT, username VARCHAR(50), -- 冗余字段 avatar_url VARCHAR(100), -- 冗余字段 amount DECIMAL ); ``` 此设计避免查询订单时频繁关联用户表,但需通过触发器或应用层保证冗余字段一致性。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值