数据库

关系型数据库的范式

范式可以理解为设计标准

第一范式 1NF

  • 定义

字段不可再分

  • 举例
存储体检者的双眼视力
那么应该存为左眼视力和右眼视力两个字段
即user表里应该有 left_eye 和  right_eye 
而不能把它们存在一个字段

第一范式 的缺点

image.png

存在如下问题:
  • 数据冗余
  • 创建系时插入异常
  • 删除学生会导致系消失
  • 学生转系时改动多处
结论:第一范式不够强

第二范式 2NF

  • 定义(不准确)
在1NF的基础上,要有键(键可由多个字段组成)
所有字段分别完全依赖于键
如果键是多个字段组合,则不允许部分依赖于该键
  • 依赖关系
给出键,就能唯一确定字段的值
如给出学号,就能唯一确定姓名,反之则不行
则称姓名依赖于学号
  • 上表不满足第二范式的地方
上表的键为(学号,课名)
但存在部分依赖:姓名依赖于学号
  • 改进
选课表(学号、课名、分数)
学生表(学号、姓名、系名、班主任)
image.png

第三范式 3NF

  • 定义(不准确)
一个表里不能有两层依赖
给出学号,就能确定系名:系名依赖于学号
给出系名,就能确定系主任:系主任依赖于系名
所以,系主任间接依赖于学号
  • 解决办法
    把系名和系主任单独建表
    image.png

总结

  • 第一范式:属性不可分割
  • 第二范式:字段完全依赖于键
  • 第三范式:字段没有间接依赖于键
  • BC范式:键中的属性也不存在间接依赖(多个键之间互相依赖)

数据库设计经验

  • 高内聚

把相关的字段放在一起,不相关的分开建表

如果两个字段能够单独建表,那就单独建表

  • 低耦合

如果两个表之间有弱关系

一对一可放在一个表,也可两个表加外键

一对多一般用外键

多对多一般建中间表

一对一

假设一个学生只能加入一个班

  • 可以把班级放在学生表里

学生id:1001; 姓名:小明;班级id:4002

班级id:4002; 名称:入门1级

  • 也可以单独建立关联表

如果两个表之间有弱关系

一 学生id:1001; 姓名:小明;

一 学生班级id:2003; 学生id:1001;班级id:4002

班级id:4002; 名称:入门1级

一对多

假设一个作者能写多本书

  • 可以把书放在作者表立吗?

某些DBMS支持数组,可以存两个id到一个字段

作者id:1001;姓名:大牛;books:[2001,3002]

如果不支持数组,就不能这么做了

  • 单独建立关联表(推荐)

作者id:1001;姓名:大牛

出版id:2001;作者id:1001;书id:4002

出版id:2002;作者id:1001;书id:4003

书id:4002;名称:JS入门

什么时候建关联表

  • 当关联自身存在属性时

比如关联的有效期,有效期为一年

比如关联的级别,店铺会员分为VIP1~6

JOIN

  • 连接表

inner join

left join

right join

full outer join

  • 看图巧记


    image.png

    image.png

参考文章

语法

把表名改为

T1{INNER|{LEFT|RIGHT|FULL}[OUTER]} JOIN T2 ON boolean_expression
例如

SELECT A.PK AS A_PK, B.PK AS B_PK,
       A.Value AS A_Value, B.Value AS B_Value
FROM Table_A A
INNER JOIN Table_B B
ON A.PK = B.PK;

试试看1

  • 创建数据库
    CREATE DATABASE IF NOT EXISTS han DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_520_ci;
  • 创建表
create tables users(id serial, name text);
create table staffs(id serial, name text);
create table orders(id serial, user_id bigint unsigned, staff_id bigint unsigned, amount int unsigned);
image.png

试试看2

  • 创建记录
insert into users (name) values ('XiaoMing');
insert into staffs (name) values ('XiaoHong');
insert into orders (user_id,staff_id,amount) values (1,1,100);
image.png
  • 使用inner join

select users.name, orders.amount from users inner join orders on users.id=orders.user_id;

image.png

  • 使用left join

select users.name, orders.amount from users left join orders on users.id = orders.user_id;

image.png

其他 join

  • Left join

会保留右边的null,以保证左边都显示

  • Right join

会保留左边的null,以保证右边都显示

  • Full outer join

会保留两边的null,以保证两边都显示

缓存字段

假设一个博客包含多个评论comments

  • 如何获取博客的评论数
select count(id) from comments where blog_id=8
这样太慢了
可不可以在blog表上加一个comment_count字段
每次添加comment则+1
每次删除comment则-1
可以的

事务

  • 有些操作必须一次完成
用户评论之后,要做两件事
第一步,在comment表新增记录
第二部,在blogs表将对应的comment_count+1
如果第一步执行了,第二步没执行怎么办
数据就乱了

使用事务

菜鸟教程

create table runoob_transaction_test( id int(5)) engine=innodb;  # 创建数据表
begin;  # 开始事务
语句1;语句2;语句3;
commit; # 提交事务
rollback;   # 回滚
select * from runoob_transaction_test;   # 因为回滚所以数据没有插入

只要有一句出错,则全都不生效

image.png

索引

  • 语法
create unique index index1 on users(name(100));  //这里的100是索引长度,规定不能超过该字段类型的最大字符长度
show index in users;
image.png
  • 用途

提高搜索效率

where xxx>100 那么我们可以创建xxx的索引

where xxx>100 and yyy>200, 创建xxx,yyy的索引

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式,各种范式呈递次...
    海边的蜗牛ng阅读 6,743评论 0 2
  • 数据库开发规范1. 数据库命名规范前缀对象前缀命名: 前缀命名一般用小写表的前缀: 业务模块组名前缀存储过程前缀:...
    PowerYangSoft阅读 7,414评论 0 8
  • 数据库设计范式及其意义和不足 补充:现在大型项目倾向于反范式设计,得益于大容量硬盘的白菜价和计算机的性能提升,表的...
    七枷琴子阅读 7,838评论 0 1
  • 文/Bruce.Liu1 1.建模简介 范式:英文名称是 Normal Form,它是英国人 E.F.Codd(埃...
    BruceLiu1阅读 10,976评论 0 9
  • 范式:英文名称是 Normal Form,它是英国人 E.F.Codd(关系数据库的老祖宗)在上个世纪70年代提出...
    42c64edf12e9阅读 4,628评论 0 0