数据库范式
第一范式( 1NF )
数据库表中的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性
第二范式( 2NF )
第二范式必须先满足第一范式,第二范式要求数据库的每个实例或行必须可以被唯一的区分,即表中要有一列属性可以将实体完全区分,这个属性就是主键
第三范式( 3NF )
第三范式必须先满足第二范式,第三范式要求一个数据库表中不包含已在其他表中已包含的非主关键字信息
第四范式( 4NF )
必须满足第三范式, 表中不能包含一个实体的两个或多个互相独立的多值因子
优点
因为相对来说有较少的重复数据,范式化的更新操作要比反范式快。同时范式化需要更少的distinct和order by
缺点
通常需要关联,不仅代价昂贵,也可能会使的一些索引无效
反范式
1. 复制:在两个表中根据实际业务情况存储部分相同的字段列,即有利于查询,也不会把表搞的太大
2. 缓存:对于需要多次join查询的表,可以在一个表中加入一个缓存列,用来缓存所join表的部分常用数据,如count等,我们需要实时更新该缓存
数据库连接
内连接
只有两个表相匹配的行才能在结果集中出现。返回的结果集选取两个表中所匹配的数据,舍弃不匹配的数据
select fieldlist from table1 [inner] join table2 on table1.column = table2.column
外连接
外连接不仅仅包含符合连接条件的行,而且还包括左表(左外连接),右表(右外连接),或者两个边表(全外连接)中的所有数据行
select fieldlist from table1 left/ right outer join table2 on table1.column = table2.column
数据库优化方式
查询优化
- 选择索引
- 使用连接代替子查询
- 尽量用
IN
代替OR
,OR
的效率是n级别,IN
的效率是log(n)级别,IN
的个数建议控制在200以内 - 能用
BETWEEN
不用IN
- 尽量用
LIMIT
,同时尽量不用count *
- 切分一个连接时间很长的查询,或返回数据量很大的查询
- 分解关联查询,在应用层做关联,可以更容易对数据库进行拆分,减少锁的竞争,减少冗余记录的查询
大数据量下的优化
建表时
- 如何建立索引
- 字段类型尽量精确,尽量小,能用
int
不要用bigint
- 尽量不要用
null
,声明not null
,如果是null
用0代替 - 尽量使用
TIMESTAMP
而非DATETIME
- 用整型来存ip
- 注意反范式和范式的优化
查询时
- 参考查询优化
- 参考前面的查询在什么情况下不走索引
加缓存NoSQL
- Memcached
- Redis
分区
- MySQL内置的是水平分区,分为range,list,hash,key
- 在分区的基础上还可以有子分区,一个分区创建子分区,其他分区也要创建子分区;每个分区的子分区数必须相同;所有分区必须使用相同的存储引擎
- 分区表的数据还可以分布在不同的物理设备上
分表
-
垂直分表:把表中的一些字段移到其他表或者新建表
-
水平分表:和分区类似
-
垂直分库:把不同数据表分到不同库,不同服务器上
-
可以使用MyCat等中间件来实现
InnoDB和MySIAM
差异 | MyISAM | InnoDB |
文件格式 | 数据和索引是分别存储的,数据.MYD ,索引.MYI
|
数据和索引是集中存储的.ibd
|
文件能否移动 | 能,一张表就对应.frm 、MYD 、MYI 3个文件 |
否,因为关联的还有data 下的其它文件 |
记录存储顺序 | 按记录插入顺序保存 | 按主键大小有序插入 |
空间碎片(删除记录并flush table table_name 之后,表文件大小不变) |
产生。定时整理:使用命令optimize table table_name 实现 |
不产生 |
事务 | 不支持 | 支持 |
外键 | 不支持 | 支持 |
锁支持 | 表级锁定 | 行级锁定、表级锁定 |
语句执行过程
查询语句
- client先发送一条查询给服务器,#连接器# (此时的通信协议的半双工的)
- 服务器先检查缓存,如果命中缓存,则返回结果,如果没有,进入下一阶段(查询缓存是通过大小写敏感的hash表实现的,但是MySQL8.0之后把缓存删除了)
- 进行SQL解析#解析器#*,预处理#预处理器#,再由查询优化器#优化器#*生成对应的查询执行计划
- 根据优化计划来调用存储引擎的API来查询,并将结果返回给客户端
更新语句
-
先按照上述步骤,分析SQL语句,然后拿到要修改的行
-
执行器修改拿到的行,同时调用引擎把修改后的行写入表中
-
引擎将这行数据更新到内存中,同时使redo log进入prepare状态
-
告知执行器执行完毕,随时可以提交事物
-
-
执行器生成操作的binlog,并写入磁盘
-
执行器调用引擎的提交事物接口,引擎把刚才的redo log改成提交状态,更新完成
redo log和binlog
- redo log是InnoDB引擎特有的;binlog是MySQL的Server层实现的,所有引擎都可以使用
- redo log是物理日志,记录的是“在某个数据页上做了什么修改”;binlog是逻辑日志,记录的是这个语句的原始逻辑,比如“给ID=2这一行的c字段加1 ”
- redo log是循环写的,空间固定会用完;binlog是可以追加写入的。“追加写”是指binlog文件写到一定大小后会切换到下一个,并不会覆盖以前的日志
- binlog可以作为恢复数据使用,主从复制搭建,redo log作为异常宕机或者介质故障后的数据恢复使用