本文主要是介绍数据库之十 三大范式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
【零】序
【1】范式分类
- 数据库范式中,最为人所知的有三大范式(
1NF
、2NF
、3NF
) - 但除此之外也有一些其他设计规范,如第四范式(
4NF
)、第五范式:完美范式(5NF
)、巴斯-科德范式(BCNF
)以及反范式设计。
【2】三大范式
- 范式(Normal Form)是设计数据库时要遵守的一些原则。
- 数据库的三大范式是递进的关系,也就是后续的范式都基于前一个范式的基础上推行。比如,第二范式必须建立在第一范式的基础之上,如果设计的库表第一范式都不满足,那定然是无法满足第二范式的。
【一】第一范式(1NF
)
【1】说明
-
原子性、原子性、原子性、
-
即每一列都是不可分割的原子数据项
【2】举例
(1)改前
- 让我们来看看这个订单表
# 创建表
drop table if exists order_form;
create table if not exists order_form(
order_id int auto_increment primary key,
user_info varchar(255),
goods_info varchar(255),
order_info varchar(255),
total_prices float
);
# 插入数据
insert order_form(user_info, goods_info, order_info, total_prices) values
('bruce, beijing', 'phone, 1200', '5, 2022-12-12', 6000),
('tom, shanghai', 'computer, 5555', '10, 2022-12-15', 55550),
('lily, shanghai', 'laptop, 1000', '11, 2022-11-15', 11000),
('lala, beijing', 'phone, 1200', '8, 2022-12-15', 9600),
('lany, shanghai', 'computer, 5555', '6, 2022-11-15', 33330);
- 查看表内容
select * from order_form;
+----------+----------------+----------------+----------------+--------------+
| order_id | user_info | goods_info | order_info | total_prices |
+----------+----------------+----------------+----------------+--------------+
| 1 | bruce, beijing | phone, 1200 | 5, 2022-12-12 | 6000 |
| 2 | tom, shanghai | computer, 5555 | 10, 2022-12-15 | 55550 |
| 3 | lily, shanghai | laptop, 1000 | 11, 2022-11-15 | 11000 |
| 4 | lala, beijing | phone, 1200 | 8, 2022-12-15 | 9600 |
| 5 | lany, shanghai | computer, 5555 | 6, 2022-11-15 | 33330 |
+----------+----------------+----------------+----------------+--------------+
- 在这个数据表中,很明显可以看出来
- 用户信息为什么要写在一起呢,完全可以分开写
- 将
user_info
这个字段拆写成user_name
和user_address
- 同理商品信息的东西也没必要写在一起
- 将
goods_info
这个字段拆写成goods_name
和goods_price
- 同理订单信息也是的
- 将
order_info
这个字段拆写成order_num
和order_time
(2)改后
- 按照原子性要求,重新创建表
drop table if exists order_form;
create table if not exists order_form(
order_id int auto_increment primary key,
user_name varchar(255),
user_address varchar(255),
goods_name varchar(255),
goods_price float,
order_num int,
order_date date,
total_prices float
);
- 重新插入数据
insert into order_form(user_name, user_address, goods_name, goods_price, order_num, order_date, total_prices) VALUES
('bruce', 'beijing', 'phone', 1200, 5, '2022-12-12', 6000),
('tom', 'shanghai', 'computer', 5555, 10, '2022-12-15', 55550),
('lily', 'shanghai', 'laptop', 1000, 11, '2022-11-15', 11000),
('lala', 'beijing', 'phone', 1200, 8, '2022-12-15', 9600),
('lany', 'shanghai', 'computer', 5555, 6, '2022-11-15', 33330);
- 查看数据
+----------+-----------+--------------+------------+-------------+-----------+------------+--------------+
| order_id | user_name | user_address | goods_name | goods_price | order_num | order_date | total_prices |
+----------+-----------+--------------+------------+-------------+-----------+------------+--------------+
| 1 | bruce | beijing | phone | 1200 | 5 | 2022-12-12 | 6000 |
| 2 | tom | shanghai | computer | 5555 | 10 | 2022-12-15 | 55550 |
| 3 | lily | shanghai | laptop | 1000 | 11 | 2022-11-15 | 11000 |
| 4 | lala | beijing | phone | 1200 | 8 | 2022-12-15 | 9600 |
| 5 | lany | shanghai | computer | 5555 | 6 | 2022-11-15 | 33330 |
+----------+-----------+--------------+------------+-------------+-----------+------------+--------------+
- 这样就满足了原子性要求,看着也舒服了很多
【二】第二范式(2NF
)
【1】说明
-
完全依赖、完全依赖、完全依赖、
-
第二范式要求在第一范式的基础上,表中的每一列都必须完全依赖于全部主键,而不是部分主键
【2】举例
(1)改前分析
- 上面的第一范式还是很好理解的
- 我们在分析分析这个第二范式
- 在这个订单表中,用户的地址和订编号是完全依赖的吗
- 看这并不需要,我们订单锁定用户名字就可以了
- 同理商品信息呢,也是一样的
- 所以我们可以创建三个表
- 用户表:用户id,用户名字,用户地址
- 商品表:商品id, 商品名字,商品价格
- 订单表:订单id,用户id,商品id,商品数量,总价格
(2)改后
- 按照完全依赖性要求,重新创建表
# 订单表
drop table if exists orders;
create table if not exists orders (order_id int auto_increment primary key,user_id int,goods_id int,order_num int,order_date date,total_prices float
);
# 用户表
drop table if exists users;
create table if not exists users (user_id int auto_increment primary key,user_name varchar(255),user_address varchar(255)
);
# 商品表
drop table if exists goods;
create table if not exists goods (goods_id int auto_increment primary key,goods_name varchar(255),goods_price float
);
- 将原来的内容去重插入新表
# 用户表
insert into users(user_name, user_address)
select distinct user_name, user_address from order_form;
# 商品表
insert into goods(goods_name, goods_price)
select distinct goods_name, goods_price from order_form;
# 订单表
insert into orders(user_id, goods_id, order_num, order_date, total_prices)
select users.user_id, goods.goods_id, order_form.order_num, order_form.order_date, order_form.total_prices
from order_form
join users on order_form.user_name = users.user_name and order_form.user_address = users.user_address
join goods on order_form.goods_name = goods.goods_name and order_form.goods_price = goods.goods_price;
- 查看数据
select * from users;
# 用户表
+---------+-----------+--------------+
| user_id | user_name | user_address |
+---------+-----------+--------------+
| 1 | bruce | beijing |
| 2 | tom | shanghai |
| 3 | lily | shanghai |
| 4 | lala | beijing |
| 5 | lany | shanghai |
+---------+-----------+--------------+
select * from goods;
# 商品表
+----------+------------+-------------+
| goods_id | goods_name | goods_price |
+----------+------------+-------------+
| 1 | phone | 1200 |
| 2 | computer | 5555 |
| 3 | laptop | 1000 |
+----------+------------+-------------+
select * from orders;
# 订单表
+----------+---------+----------+-----------+------------+--------------+
| order_id | user_id | goods_id | order_num | order_date | total_prices |
+----------+---------+----------+-----------+------------+--------------+
| 1 | 1 | 1 | 5 | 2022-12-12 | 6000 |
| 2 | 2 | 2 | 10 | 2022-12-15 | 55550 |
| 3 | 3 | 3 | 11 | 2022-11-15 | 11000 |
| 4 | 4 | 1 | 8 | 2022-12-15 | 9600 |
| 5 | 5 | 2 | 6 | 2022-11-15 | 33330 |
+----------+---------+----------+-----------+------------+--------------+
- 以上内容就满足第二范式的完全依赖要求
【三】第三范式(3NF
)
【1】说明
-
非传递依赖、非传递依赖、非传递依赖、
-
表中的每一列都必须直接依赖于主键,而不能传递依赖
【2】举例
(1)改前
- 再让我们看看订单表
select * from orders;
# 订单表
+----------+---------+----------+-----------+------------+--------------+
| order_id | user_id | goods_id | order_num | order_date | total_prices |
+----------+---------+----------+-----------+------------+--------------+
| 1 | 1 | 1 | 5 | 2022-12-12 | 6000 |
| 2 | 2 | 2 | 10 | 2022-12-15 | 55550 |
| 3 | 3 | 3 | 11 | 2022-11-15 | 11000 |
| 4 | 4 | 1 | 8 | 2022-12-15 | 9600 |
| 5 | 5 | 2 | 6 | 2022-11-15 | 33330 |
+----------+---------+----------+-----------+------------+--------------+
total_price
字段,这个字段是goods_price
(在goods
表中)和orders
表的order_num
的乘积。- 这样,
total_price
就会依赖于非主键字段goods_price
和order_num
,违反第三范式。
(2)改后
-
这里的修改很简单
-
为了满足第三范式,我们直接移除这个
total_price
字段姐可以 -
毕竟它可以通过其他字段得出
alter table orders drop column total_prices;
- 重新查看订单表
+----------+---------+----------+-----------+------------+
| order_id | user_id | goods_id | order_num | order_date |
+----------+---------+----------+-----------+------------+
| 1 | 1 | 1 | 5 | 2022-12-12 |
| 2 | 2 | 2 | 10 | 2022-12-15 |
| 3 | 3 | 3 | 11 | 2022-11-15 |
| 4 | 4 | 1 | 8 | 2022-12-15 |
| 5 | 5 | 2 | 6 | 2022-11-15 |
+----------+---------+----------+-----------+------------+
- 这样所有的表就都满足了三大范式要求
【四】总结
【1】三大范式
- 第一范式(
1NF
):- 确保原子性
- 每一列都是不可分割的原子数据项
- 第二范式(
2NF
):- 确保完全依赖
- 每一列都必须完全依赖于全部主键
- 第三范式(
3NF
):- 确保非传递依赖
- 每一列都必须直接依赖于主键
【2】必要性讨论
-
虽然遵循三范式的数据库设计可能会导致表的数量增加,但这并不意味着设计过程更加复杂或麻烦。实际上,如果不遵循这些范式,可能会导致以下问题:
- 数据冗余:如果不遵循范式,一张表可能包含大量重复的数据。
- 表结构臃肿:如果一张表包含多种业务属性,那么这张表可能会变得非常大,不易于操作和管理。
- 更新困难:如果表中的数据存在依赖关系,那么更新一部分数据可能需要修改大量的记录。
-
因此,遵循三范式的数据库设计可以使表结构更加优雅,提高数据库的灵活性和可维护性。
这篇关于数据库之十 三大范式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!