数据库知识要点,面试向
数据库原理、sql语句、mysql数据库、数据库优化、redis
数据库原理
知识点:事务、范式、多粒度和意向锁、XS锁、封锁协议、两段锁协议、死锁、隔离级别
事务ACID
事务就是指数据库的要做的一件事情,可以是一条sql语句,可以是一系列操作。把这些操作总体当作一个要么完成要么不完成的事情来看,完成就是commit,不完成就是rollback
事务的四个特性:
A 原子性 要么完成,要么rollback
C 一致性 事物之行前后保持一致性
I 隔离性 事务之间不影响也不可见
D 持久性 修改是永久的,即使系统奔溃,也不可以出问题
脏数据、不可重复读、修改丢失、幻影读
脏数据:就是读出来的数据,由于被别人修改了,但是丢改又取消了,其实没有修改,但是读出来的数据是修改的,所以是脏数据
不可重复读:读了两次数据,但是读的时候,别的事务修改了数据的值,导致读的不对
修改丢失:多个事务同时读取数据,然后修改,但是先写入的被后修改的覆盖了
幻影读:范围读取的时候,由于别的事务的修改,导致两次读取结果不一样
锁
写锁X:加了之后,只有我可以读改数据,其他程序不可以读写
读锁S:加了之后,只有我和其他加了读锁读事务可以读,不可以写也不可以加X锁,只可以加S锁
封锁协议
一级、二级、三级封锁协议
一级封锁协议:写入之前加X锁,直到事务结束,释放X。防止丢失修改,同时只有一个事务可以修改数据
二级封锁协议:一的基础上,在读取之前加S,读完释放S。防止读取脏数据,因为A修改x的值的时候,没办法第二次读取,如果回滚了,读取到的数据是脏数据。
三级封锁协议:一的基础上,读之前加S,事务结束释放S。防止不可重复读。
多粒度锁和意向锁
锁的粒度可以是表级也可以是行级别,mysql中myisam就是表,innoDB就是行级别
意向锁:为了更好的支持多粒度锁
IX锁:获取某个行的X锁之前,需要获得表的IX锁
IS锁:获取某个行的S锁之前,需要获得表的IS锁及更强锁
表的IX锁和X锁不兼容,就是说加了IX,不可以加表的X,只能加行的X
原理:
没有意向锁的话,如果想获取一个表的X锁,就需要对表的X锁和每一行的X锁进行检测,非常消耗资源。
但是有了意向锁就不一样了,如果有一个事务获得了行的X锁,那它一定获得了表的IX锁,其他事务如果想来获取这个表的锁,就不可以,只能获得行的X锁
两段锁协议
就是说加锁和解锁分为两段来执行,可以对不同事务中的所有加锁解锁操作串行,判断是否可以冲突可串行化调度
冲突可串行化调度,就是说按照一个串行顺序调度,不会出现死锁
死锁
预防:一次封锁法:一次获得所有资源,顺序封锁法:按照一个合理的顺序封锁
诊断和解除:超时法,等待图法(检测回路),从一个最小事务,释放它的所有资源
隔离级别
未提交读:修改未提交就可以读,不能防任何
已提交读:只能读取已经提交的结果,可以防止脏数据
可重复读:事务多次读取结果一样,防止不可重复读,不防幻影
可串行化 :事务串行执行,不会互相干扰,不会出现一致性问题,需要加锁实现
多版本并发控制MVCC
InnoDB实现提交读和可重复读的一种实现。可串行无法实现。
基本实现:
数据有版本快照,只可以读取已经提交的快照,从而防止脏数据和不重复读,脏数据和不重复读是由于读取了为提交的修改导致的。
多版本指的是多个版本的快照,储存在Undo日志中。
每一个事务会有一个版本号。日志就记录了操作这些数据的版本号等信息。
ReadView结构,里保存了未提交的事务列表的版本号,通过比较快找的版本号和列表的版本号,如果快照小,则修改为提交,可以使用,如果快照大,则不能使用,如果在列表中间,则需要判断在列表中就表示没提交,提交读不可,不在就可以提交读。可重复读不可以。
MVCC不可以解决幻影读,所以使用nextkeylocks解决幻影读
recordlocks和gaplocks结合,锁定索引的一个区间
MCVV详解参考:https://www.codercto.com/a/88775.html
范式
第一、第二、第三范式
第一范式:属性不可分
第二范式:非主属性只依赖键码
第三范式:不存在非主属性的函数依赖传递
BCNF:每个决定因素都包含码(我的理解是都在码内)
第四范式:没有非平凡的非函数依赖的多值依赖
多值依赖:就是说ABC三属性,AC虽然决定B,但是B中很多组值(B1B2、B3B4B5)只取决于A。
比如课程、老师、书本,不同老师用不同的书,一门课好几个老师,课程可以决定一坨老师和书,
所以老师和书都是对课程多值依赖的。
非平凡就是C不为空,例子里就是有课本。
mysql数据库
对比
之前是myisam,现在是InnoDB
InnoDB:支持事务,支持行级锁、支持外键、聚簇索引、多版本控制、commit和rollback、热备份
myisam:不支持事务,表级锁、不支持外键、非聚簇索引
索引实现
B+Tree索引或者哈希索引
哈希索引:O1复杂度,查询速度快,只支持单个条目查询
B+tree索引:支持范围查找
全文索引:倒排索引实现,记录关键字到文档的映射。用于全文查找关键字
空间数据索引:myisam支持,用于地理数据存储。空间数据索引会从所有维度来索引数据,可以有效地使用任意维度来进行组合查询。
BTree比红黑好:1因为出度大,所以查找快。2磁盘预读,索引和文件放在一起
索引种类
单列索引、多列索引、前缀索引、覆盖索引
覆盖索引:索引包含需要查询的字段的值
索引使用
优点:加快查询速度,随机IO变顺序IO,避免排序和分组创立临时表
使用:中大型表,特大表代价太大,小表直接扫描
索引总结
https://github.com/Snailclimb/JavaGuide/blob/master/docs/database/MySQL%20Index.md
锁
InnoDB
-
Record lock:单个行记录上的锁
-
Gap lock:间隙锁,锁定一个范围,不包括记录本身
-
Next-key lock:record+gap 锁定一个范围,包含记录本身
数据库优化
大表优化
限定数据的取值范围
读写分离,主库写,从库读
垂直分区:按照相关性和列拆分乘多个表,优点:减少读取数据量,缺:增加了冗余和连接
水平分区:水平拆分可以支持海量的数据
分区要谨慎使用,不然跨区会有很大代价
索引优化
限制索引数量
最左侧原则
频繁查询和使用的列索引
频繁更新的列不要索引
避免冗余的索引
其他优化和规范
redis数据库
redis是一个内存中的Nosql数据库,广泛用于缓存方向。也经常用来做分布式锁。此外还支持事务,支持LUA脚本,支持持久化和集群方案。高性能,高并发。
线程模型
单线程,单线程其实是指他的文件事务分派器是单线程的。
redis是由于:
多个socket
IO多路复用程序
文件事务分派器
时间处理器
组成。
流程:多个socket并发产生多个操作,然后IO多路复用程序从socket中监听,将socket中时间放在一个队列中,文件事务分派器按照事务将事件一个一个派发给事件处理器。
redis和memcached区别
类型:redis是数据库,而memcached是缓存系统
数据类型:redis五种,string、set、map、list、Zset
集群:redis原生支持,memcached不支持,需要程序支持
线程:redis是单线程的非阻塞IO复用,memcached是多线程的多路IO复用
持久化:redis支持持久化,memcached只是一个缓存系统
操作:redis:批量操作、假事务、不同类型不同curd,memcached支持curd和其他少量操作
内存淘汰
可以设置过期时间。
定期删除:定期扫描一定数量的设置了过期时间的key,过期则删除。不全部扫描,因为开销太大。
惰性删除:定期删除肯定长时间会存在很多没有被删掉的过期变量,需要惰性删除,就是说检查一下这个key,然后删除。
因为删除还会导致大量过期的变量,所以引入淘汰机制
6种
设置了过期中最近最少使用
设置了过期中最快过期
设置了过期中随机
所有中最近最少使用
所有中随机
不删除
4.0后加了两种:
设置了过期中最少使用
全部中最少使用
持久化
快照持久化:定期产生快照,然后对快照进行备份
AOF持久化(只追加文件持久化):每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。每秒同步一次,最多损失一秒的数据。实时性很好,是目前对主流方案。
4.0后支持混合持久化
事务
事务提供了一种将多个命令请求打包,然后一次性、按顺序地执行多个命令的机制,并且在事务执行期间,服务器不会中断事务而改去执行其他客户端的命令请求,它会将事务中的所有命令都执行完毕,然后才去处理其他客户端的命令请求。redis支持事务的方式就是一起做,顺序执行。
缓存穿透和缓存雪崩
缓存穿透:大量的请求不在缓存中,需要请求数据库
解决方法:处理无效key过期、布隆过滤器(类似于白名单,判断key是否合法)
缓存雪崩;短时间缓存大量失效,导致请求直接交给数据库
解决方法:事前:保证redia集群的高可用性,选择合适的淘汰机制,事中:ehcache缓存 + hystrix限流&降级,避免MySQL崩掉,事后:持久化机制快速回复。
sql语句
略