数据库的三大范式
A:第一范式
数据库表中不能出现重复的记录,每个字段是原子性的不能再分
学生编号 | 学生姓名 | 联系方式 |
---|---|---|
1001 | 张三 | zs@gmail.com,1359999999 |
1002 | 李四 | ls@gmail.com,13699999999 |
1001 | 王五 | [ww@163.net,13488888888 |
存在问题:
1: 最后一条记录和第一条重复(不唯一,没有主键)
2: 联系方式字段可以再分,不是原子性的
B:第二范式
第二范式是建立在第一范式基础上的,另外要求所有非主键字段完全依赖主键,不能产生部分依赖
学生编号 | 学生姓名 | 教师编号 | 教师姓名 |
---|---|---|---|
1001 | 张三 | 001 | 王老师 |
1002 | 李四 | 002 | 赵老师 |
1003 | 王五 | 001 | 王老师 |
1001 | 张三 | 002 | 赵老师 |
确实主键:
学生编号(PK) | 学生姓名(PK) | 教师编号 | 教师姓名 |
---|---|---|---|
1001 | 张三 | 001 | 王老师 |
1002 | 李四 | 002 | 赵老师 |
1003 | 王五 | 001 | 王老师 |
1001 | 张三 | 002 | 赵老师 |
以上虽然确定了主键,但此表会出现大量的冗余,主要涉及到的冗余字段为“学生姓名”和“教师姓名”,出现冗余的原因在于,学生姓名部分依赖了主键的一个字段学生编号,而没有依赖教师编号,而教师姓名部门依赖了主键的一个字段教师编号,这就是第二范式部分依赖。
学生信息表
学生编号(PK) | 学生姓名 |
---|---|
1001 | 张三 |
1002 | 李四 |
1003 | 王五 |
教师信息表
教师编号(PK) | 教师姓名 |
---|---|
001 | 王老师 |
002 | 赵老师 |
教师和学生的关系表
学生编号(PK) fk->学生表的学生编号 | 教师编号(PK) fk->教师表的教师编号 |
---|---|
1001 | 001 |
1002 | 002 |
1003 | 001 |
1001 | 002 |
如果一个表是单一主键,那么它就复合第二范式,部分依赖和主键有关系
以上是一种典型的“多对多”的设计
C:第三范式
建立在第二范式基础上的,非主键字段不能传递依赖于主键字段。(不要产生传递依赖)
学生编号(PK) | 学生姓名 | 班级编号 | 班级名称 |
---|---|---|---|
1001 | 张三 | 01 | 一年一班 |
1002 | 李四 | 02 | 一年二班 |
1003 | 王五 | 03 | 一年三班 |
1004 | 赵六 | 03 | 一年三班 |
从上表可以看出,班级名称字段存在冗余,因为班级名称字段没有直接依赖于主键,班级名称字段依赖于班级编号,班级编号依赖于学生编号,那么这就是传递依赖,解决的办法是将冗余字段单独拿出来建立表,如:
学生信息表
学生编号(PK) | 学生姓名 | 班级编号 | 班级名称 |
---|---|---|---|
1001 | 张三 | 01 | 一年一班 |
1002 | 李四 | 02 | 一年二班 |
1003 | 王五 | 03 | 一年三班 |
1004 | 赵六 | 03 | 一年三班 |
班级信息表
班级编号(PK) | 班级名称 |
---|---|
01 | 一年一班 |
02 | 一年二班 |
03 | 一年三班 |
以上设计是一种典型的一对多的设计,一存储在一张表中,多存储在一张表中,在多的那张表中添加外键指向一的一方的主键
总结:
第一范式:有主键,具有原子性,字段不可分割
第二范式:完全依赖,没有部分依赖
第三范式:没有传递依赖
数据库设计尽量遵循三范式,但是还是根据实际情况进行取舍,有时可能会拿冗余换速度,最终用目的要满足客户需求。
数据库的存储引擎
1.查看存储引擎
- 数据库中的各表均被(在创建表时)指定的存储引擎来处理
- 服务器可用的引擎依赖于以下因素:
• MySQL的版本
• 服务器在开发时如何被配置
• 启动选项
查看当前数据库有哪些存储引擎可用,使用mysql> SHOW ENGINES\G
• 在创建表时,可使用ENGINE选项为CREATE TABLE语句显式指定存储引擎。CREATE TABLE TABLENAME (NO INT) ENGINE = MyISAM;
• 如果在创建表时没有显式指定存储引擎,则该表使用当前默认的存储引擎
• 默认的存储引擎可在my.ini配置文件中使用default-storage-engine选项指定。
• 现有表的存储引擎可使用ALTER TABLE语句来改变:ALTER TABLE TABLENAME ENGINE = INNODB;
• 为确定某表所使用的存储引擎,可以使用SHOW CREATE TABLE或SHOW TABLE STATUS语句:
mysql> SHOW CREATE TABLE tablename\G
mysql> SHOW TABLE STATUS LIKE 'tablename' \G
2.常用的存储引擎
MyISAM存储引擎
• MyISAM存储引擎是MySQL最常用的引擎。
• 它管理的表具有以下特征:
–使用三个文件表示每个表:
• 格式文件 — 存储表结构的定义(mytable.frm)
• 数据文件 — 存储表行的内容(mytable.MYD)
• 索引文件 — 存储表上索引(mytable.MYI)
– 灵活的AUTO_INCREMENT字段处理
– 可被转换为压缩、只读表来节省空间
InnoDB存储引擎
• InnoDB存储引擎是MySQL从5.5版本的缺省引擎。
• 它管理的表具有下列主要特征:
– 每个InnoDB表在数据库目录中以.frm格式文件表示
– InnoDB表空间tablespace被用于存储表的内容
– 提供一组用来记录事务性活动的日志文件
– 用COMMIT(提交)、SAVEPOINT及ROLLBACK(回滚)支持事务处理
– 提供全ACID兼容
– 在MySQL服务器崩溃后提供自动恢复
– 多版本(MVCC)和行级锁定
– 支持外键及引用的完整性,包括级联删除和更新
MEMORY存储引擎
• 使用MEMORY存储引擎的表,其数据存储在内存中,且行的长度固定,这两个特点使得MEMORY存储引擎非常快。
• MEMORY存储引擎管理的表具有下列特征:
– 在数据库目录内,每个表均以.frm格式的文件表示。
– 表数据及索引被存储在内存中。
– 表级锁机制。
– 不能包含TEXT或BLOB字段。
• MEMORY存储引擎以前被称为HEAP引擎。
选择合适的存储引擎
• MyISAM表最适合于大量的数据读而少量数据更新的混合操作。MyISAM表的另一种适用情形是使用压缩的只读表。
• 如果查询中包含较多的数据更新操作,应使用InnoDB。其行级锁机制和多版本的支持为数据读取和更新的混合操作提供了良好的并发机制。
• 可使用MEMORY存储引擎来存储非永久需要的数据,或者是能够从基于磁盘的表中重新生成的数据。
数据库的隔离级别
1. 数据库的四大特性
(1)原子性(Atomicity):原子性是指事务包含的所有操作必须是一个整体,要么全部成功,要么全部失败。不能事务中某一条或几条操作的失败而其他操作影响到数据库。
(2) 一致性(Consistency):指数据库只能有一个一致性状态变为另一个一致性状态。卧槽,这个用语言怎么说嘛!!!举个栗子,银行转账A,B两个用户一共5000块钱,那么不管他们怎么转都只有5000块钱。
(3) 隔离性(Isolation):指当同时进行多个事务时。一个事务不能被另一个事务的操作干扰。
(4) 持久性(Durability): 指一旦一个事务提交之后,对数据库的操作是永久的,不能因为其他原因导致丢失所做的操作。
2.问题
(1)由于很多情况是在并发的环境下访问数据库,可能会带来一下几个问题:
脏读: 一个事务中读取到另一个事务未提交的数据。如转账是A正在给B账户转钱,而B正好查看账户,此时A并未提交事务,就会导致A.B两看到的账户的钱有问题。
不可重复读:不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。如AB有一个公共账户。A 不停的向这个账户转钱,B不停的查看账户(有病),会导致B每次看到的钱都不一样(妈的,加钱还想怎样)。
虚读(幻读): 解释不来。大概就是A修改了账户,B也在修改,A修改在B之后,然而B修改后查看表发现并不是自己修改的数据,就怀疑眼睛花了,就幻觉了。。。。
四种隔离级别
针对这几种问题,MySQL提供了四种隔离级别来对应:
① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。太慢。基本不用,锁,只能一个一个来。
② Repeatable read (可重复读):可避免脏读、不可重复读的发生。
③ Read committed (读已提交):可避免脏读的发生。
④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。