第一范式 1NF
定义:
- 字段不可再分
这是一张选课表,没有违反第一范式,但是存在以下问题:
数据冗余、创建时插入异常。删除学生会导致系消失、学生转系时会改动多处。
结论:第一范式不够强
第二范式 2NF
定义(不够严谨):
- 在1NF的基础上,要有键(键可由多个字段组合)
- 所有字段分别完全依赖于键
- 如果键是多个字段组合,则不允许部分依赖于该键
依赖关系:
- 给出键,就能唯一确定字段的值
- 如给出学号,就能唯一确定姓名,反之则不行
- 则称姓名依赖于学号
不满足第二范式的地方:
- 上表的键为(学号,课名)
- 但 存在部分依赖:姓名依赖于学号
改进:
- 选课表(学号、课名、分数)
- 学生表(学号、姓名、系名、系主任)
第三范式 3NF
定义(不够严谨):
- 一张表里不能有两层依赖
- 给出学号,就能确定系名:系名依赖于学号
- 给出系名,就能确定系主任:系主任依赖于系名
- 所以,系主任间接依赖于学号
解决办法:
- 把系名和系主任单独建表
总结:
- 第一范式,属性不可分割
- 第二范式,字段完全依赖于键
- 第三范式,字段没有间接依赖于键
- 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
- 出版:id:2002 作者id:1002 书id:4003,出版社id
- 书id:4002 名称:数据库XXX
多对多
假设一个学生可以加入多个班级,每个班级也可以有多个学生,可以把班级放在学生表里吗?
- 某些DBMS支持数组就可以放
- 如果不支持数组,就不能放了
单独建立关系表(推荐)
- 学生id:1001 姓名:小明
- 学生班级:id:2001 学生id:1001 班级id:4002,有效期
- 学生班级:id:2002 学生id:1002 班级id:4003,有效期
- 班级id:4002 名称:入门1班
什么时候建关联表
当关联自身存在属性时
- 比如管理的有效期,有效期为一年
- 比如关联的级别,店铺会员为vip1~6
JOIN
连接表:
- inner join
- left join:会保留右边的null,以保证左边都显示
- right join:会保留右边的null,以保证右边都显示
- full outer join:会保留两边的null,以保证两边都显示
语法:
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_AA INNER JOIN Table_BB ON A.PK=B.PK
缓存字段
假设一个博客blog包含多个评论comments,如何获取博客的评论数?
select count(id) from comments where blog_id=8 这样太慢了。
可以在blog表上加一个comment_count字段,每次添加comment则 +1,每次删除comment则 -1。
事务
有些操作必须一次完成
用户评论知乎,要做两件事情:
第一步,在comments表新增记录
第二步,在blogs表将对应的comment_count + 1
如果第一步执行了,第二部没有执行怎么办?数据就乱了。
使用事务(菜鸟教程):
start transaction;
语句1; 语句2; 语句3;
commit
只要一句出错,则全部不生效。
MySql储存引擎
命令 SHOW ENGINES;
常见的:
- InnoDB:默认,目前版本是新版InnoDB
- MyISAM:拥有较高的插入、查询速度,但不支持事务
- Memory:内存中,快速访问数据
- Archive:只支持 inerst 和 select
InnoDB:
- InnoDB 是事务型数据库的首选,支持事务、遵循ACID、支持行锁和外键。
索引
语法(菜鸟教程):
- CREATE UNIQUE INDEX index1 ON users(name(100))
- show index in users;
用途,提高搜索效率:
- where xxx>100 我们则可以创建 xxx 的索引
- where xxx>100 and yyy<200,创建 xxx,yyy 的索引