第8章 数据库考察点
Mysql 基础考点
事务的原理,特性,事务并发控制
◆常用的字段、含义和区别
◆常用数据库引擎之间区别
什么是事务?
Transaction
◆事务是数据库并发控制的基本单位
◆事务可以看作是一系列SQL语句的集合
◆事务必须要么全部执行成功,要么全部执行失败(回滚)
转账操作是事务使用的一个常见场景
![](https://img2020.cnblogs.com/blog/1165731/202102/1165731-20210210172012890-393096663.png)
事务的ACID特性
ACID是事务的四个基本特性
牢记四个特性以及它们的含义
◆原子性(Atomicity):一个事务中所有操作全部完成或失败
◆一致性(Consistency):事务开始和结束之后数据完整性没有被破坏
◆隔离性(Isolation):允许多个事务同时对数据库修改和读写
◆持久性(Durability):事务结束之后,修改是永久的不会丢失
事务的并发控制可能产生哪些问题
如果不对事务进行并发控制,可能会产生四种异常情况
◆幻读(phantom read):一个事务第二次查出现第一次没有的结果
◆非重复读(nonrepeatable read):一个事务重复读两次得到不同结果
◆脏读(dirty read):一个事务读取到另一个事务没有提交的修改
◆丢失修改(lost update):并发写入造成其中一些修改丢失
四种事务隔离级别
为了解决并发控制异常,定义了4种事务隔离级别
◆读未提交(read uncommitted):别的事务可以读取到未提交改变
◆读已提交(read committed):只能读取已经提交的数据
◆可重复读(repeatable read):同一个事务先后查询结果一样
Mysql InnoDB默认实现可重复读级别
◆串行化( Serializable):事务完全串行化的执行,隔离级别最高,执行效率最低
如何解决高并发场景下的插入重复
高并发场景下,写入数据库会有数据重复问题
◆使用数据库的唯一索引
◆使用队列异步写入
◆使用 redis等实现分布式锁
乐观锁和悲观锁
什么是乐观锁,什么是悲观锁
◆悲观锁是先获取锁再进行操作。一锁二查三更新 select for update
◆乐观锁先修改,更新的时候发现数据已经变了就回滚(check and set)
乐观锁一般通过版本,号或者时间戳实现
◆使需要根据响应速度、冲突频率、重试代价来判断使用哪一种
Mysql常用数据类型-字符串(文本)
![](https://img2020.cnblogs.com/blog/1165731/202102/1165731-20210210172013458-701420201.png)
Mysql 常用数据类型-数值
![](https://img2020.cnblogs.com/blog/1165731/202102/1165731-20210210172013888-95574033.png)
Mysql常用数据类型-日期和时间
![](https://img2020.cnblogs.com/blog/1165731/202102/1165731-20210210172014233-578277253.png)
InnoDB Vs MyISAM
两种引擎常见的区别
◆ MyISAM不支持事务, InnoDB支持事务
◆ MyISAM不支持外键, InnoDB支持外键
◆ MyISAN只支持表锁, InnoDB支持行锁和表锁
Mysql 索引原理及优化常见考题
Mysql 索引
◆索引的原理、类型、结构
◆创建索引的注意事项,使用原则
◆如何排査和消除慢查询
什么是索引?
为什么需要索引?
◆索引是数据表中一个或者多个列进行排序的数据结构
◆索引能够大幅提升检索速度(回顾下你所知道的査找结构)
◆创建、更新索引本身也会耗费空间和时间
什么是 B-Tree?
查找结构进化史
数据结构可视化:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
Binary Search Tree
AVL Tree
注意这里出现了平衡操作,但是依然无法解决节点太多树高度非常深的问题
查找结构进化史
线性查找:一个个找;实现简单;太慢
二分査找:有序;简单;要求是有序的,插入特别慢
HASH:查询快;占用空间;不太适合存储大规模数据
二叉査找树∶插入和査询很快(log(n);无法存大规模数据,复杂度退化
平衡树:解决bst退化的问题,树是平衡的;节点非常多的时候,依然树高很高
多路查找树:一个父亲多个孩子节点(度);节点过多树高不会特别深
多路平衡查找树-B-Tree
什么是B-Tree?
什么是B-Tree,为什么要使用 B-Tree
◆多路平衡查找树(每个节点最多m(m>=2)个孩子称为m阶或者度)
◆叶节点具有相同的深度
◆节点中的数据key从左到右是递增的
![](https://img2020.cnblogs.com/blog/1165731/202102/1165731-20210210172014697-2043590230.png)
B+Tree
B+ 树是B-Tree的变形
◆Mysql 实际使用的B+Tree作为索引的数据结构
◆只在叶子节点带有指向记录的指针(为什么?可以增加树的度)
◆叶子结点通过指针相连。为什么?实现范围查询
![](https://img2020.cnblogs.com/blog/1165731/202102/1165731-20210210172015171-1348258741.png)
问题:是不是树的度越多越好了呢?
![](https://img2020.cnblogs.com/blog/1165731/202102/1165731-20210210172015736-353244397.png)
![](https://img2020.cnblogs.com/blog/1165731/202102/1165731-20210210172016601-376792946.png)
根据磁盘块去确定的
Mysq索引的类型
Mysql 创建索引类型
◆普通索引(CREATE INDEX)
◆唯一索引,索引列的值必须唯一(CREATE UNIQUE INDEX)
◆多列索引
◆主键索引(PRIMARY KEY),一个表只能有一个
◆全文索引(FULLTEXT INDEX), InnoDB不支持
创建索引有哪些需要注意的?
最佳实践
◆非空字段 NOT NULL,Mysql 很难对空值作查询优化
很多互联网公司的建表规范要求索引字段有默认值
◆区分度高,离散度大,作为索引的字段值尽量不要有大量相同值
◆索引的长度不要太长(比较耗费时间)
索引什么时候失效?
记忆口诀:模糊匹配、类型隐转、最左匹配
◆以%开头的LIKE语句,模糊搜索
◆出现隐式类型转换(在 Python这种动态语言查询中需要注意)
◆没有满足最左前缀原则(想想为什么是最左匹配?)
![](https://img2020.cnblogs.com/blog/1165731/202102/1165731-20210210172017040-1080076595.png)
什么是聚集索引和非聚集索引?
什么是聚集索引?什么是非聚集索引?
◆聚集还是非聚集指的是B+Tree叶节点存的是指针还是数据记录
◆MyISAM索引和数据分离,使用的是非聚集索引
◆InnoDB数据文件就是索引文件,主键索引就是聚集索引
非聚集索引
![](https://img2020.cnblogs.com/blog/1165731/202102/1165731-20210210172017525-1041097871.png)
非聚集和聚集索引的文件存储方式
区别是在B+Tree的叶节点存储数据还是指针
![](https://img2020.cnblogs.com/blog/1165731/202102/1165731-20210210172018066-1062532611.png)
![](https://img2020.cnblogs.com/blog/1165731/202102/1165731-20210210172018589-137418338.png)
聚集索引
![](https://img2020.cnblogs.com/blog/1165731/202102/1165731-20210210172018998-674684467.png)
![](https://img2020.cnblogs.com/blog/1165731/202102/1165731-20210210172019446-2065459312.png)
聚集索引与辅助索引
![](https://img2020.cnblogs.com/blog/1165731/202102/1165731-20210210172019859-1935892710.png)
辅助索引先找到,主键以后再根据主键找到数据
如何排查慢查询
慢查询通常是缺少索引,索引不合理或者业务代码实现导致
◆slow_query_log_file 开启并且查询慢查询日志
◆通过 explain 排查索引问题
◆调整数据修改索引;业务代码层限制不合理访问
本章回顾
索引的原理是重点
◆索引的原理
◆B+Tree的结构
◆不同索引的区别
SQL语句编写常考题
考点聚焦
SQL语句以考察各种常用连接为重点
◆内连接(INNER JOIN):两个表都存在匹配时,才会返回匹配行
◆外连接(LEFT/RIGHT JOIN)返回一个表的行,即使另一个没有匹配
◆全连接(FULL JOIN):只要某一个表存在匹配就返回
内连接
INNER JOIN
◆将左表和右表能够关联起来的数据连接后返回
◆类似于求两个表的“交集”
o select * from a inner join b on a.id=b.id
![](https://img2020.cnblogs.com/blog/1165731/202102/1165731-20210210172020157-1868607038.png)
![](https://img2020.cnblogs.com/blog/1165731/202102/1165731-20210210172020523-1083522637.png)
外连接
外连接包含左连接和右连接
◆左连接返回左表中所有记录,即使右表中没有匹配的记录
◆右连接返回右表中所有记录,即使左表中没有匹配的记录
◆没有匹配的字段会设置成NULL
MysqL中使用 left join和 right join实现
![](https://img2020.cnblogs.com/blog/1165731/202102/1165731-20210210172021219-1226489412.png)
缓存的使用场景
◆为什么要使用缓存?使用场景?
◆Redis的常用数据类型,使用方式
◆缓存使用问题:数据一致性问题;缓存穿透、击穿、雪崩问题
操作时间对比
![](https://img2020.cnblogs.com/blog/1165731/202102/1165731-20210210172021804-313799281.png)
Redis的使用
Redis和 Memcached主要区别?
![](https://img2020.cnblogs.com/blog/1165731/202102/1165731-20210210172022499-1971917967.png)
Mysql + Redis 就能抗住很多业务需求
请简述 Redis常用数据类型和使用场景?
考察对 Redis使用的掌握程度
◆String(字符串): 用来实现简单的KV键值对存储,比如计数器
◆List(链表):实现双向链表,比如用户的关注,粉丝列表
◆Hash(哈希表):用来存储彼此相关信息的键值对
HSET key filed value
◆Set(集合)存储不重复元素,比如用户的关注者
◆Sorted Set(有序集合):实时信息排行榜
延伸考点:Redis内置实现
对于中高级工程师,需要了解 Redis各种类型的C底层实现方式
◆String:整数或者sds(Simple Dynamic String)
◆List:ziplist或者 double linked list
ziplist通过一个连续的內存块实现list结构,其中的每个 entry节点头部保存前后节点长度信息,实现双向链表功能
◆Hash:ziplist或者 hashtable
◆Set:Intset或者 hashtable
◆SortedSet:skiplist跳跃表
◆深入学习请参考:《Redis设计与实现》
自我检查:你知道这些数据结构操作的时间和空间复杂度么?
Redis实现的跳跃表是什么结构?
Sorted set为了简化实现,使用 skiplist而不是平衡树实现
![](https://img2020.cnblogs.com/blog/1165731/202102/1165731-20210210172022917-1150422736.png)
Redis 有哪些持久化方式?
Redis支持两种方式实现持久化
◆快照方式:把数据快照放在磁盘二进制文件中,dump.rdb
快照的实现方式是指定时间间隔把 Redis数据库状态保存到一个压缩的二进制文件中
◆AOF(Append Only File):每一个写命令追加到 appendonly.aof中
◆可以通过修改 Redis配置实现
什么是 Redis事务?
和Mysql的事务有什么不同?
◆将多个请求打包,一次性、按序执行多个命令的机制
◆Redis通过 MULTI, EXEC, WATCH等命令实现事务功能
Python redis-py pipeline=conn.pipeline(transaction=True)
Redis如何实现分布式锁?
◆使用 setnx实现加锁,可以同时通过 expire添加超时时间
◆锁的 value值可以使用一个随机的uuid或者特定的命名
◆释放锁的时候,通过uuid判断是否是该锁,是则执行 delete释放锁
使用缓存的模式?
常用的缓存使用模式
◆ Cache aside:同时更新缓存和数据库
◆Read/Write Through:先更新缓存,缓存负责同步更新数据库
◆ Write Behind Caching:先更新缓存,缓存定期异步更新数据库
数据库和缓存之间的数据一致性
先更新数据库后更新缓存,并发写操作可能导致缓存读取的是脏数据
一般先更新数据库然后删除缓存
缓存使用中的坑
如何解决缓存穿透问题?
大量查询不到的数据的请求落到后端数据库,数据库压力增大
◆由于大量缓存査不到就去数据库取,数据库也没有要查的数据
很多无脑爬虫通过自增id的方式爬取网站,网站查不到相关id的数据
◆解决:对于没查到返回为None的数据也缓存
◆插入数据的时候删除相应缓存,或者设置较短的超时时间
如何解决缓存击穿问题?
某些非常热点的数据key过期,大量请求打到后端数据库
◆热点数据key失效导致大量请求打到数据库增加数据库压力
◆分布式锁:获取锁的线程从数据库拉数据更新缓存,其他线程等待
◆异步后台更新:后台任务针对过期的key自动刷新
如何解决缓存雪崩问题?
缓存不可用或者大量缓存key同时失效,大量请求直接打到数据库
◆多级缓存:不同级别的key设置不同的超时时间
◆随机超时:key的超时时间随机设置,防止同时超时
◆架构层:提升系统可用性。监控、报警完善
Mysql 与 Redis 练习题
Mysql 思考题
索引的理解
◆为什么Mysql数据库的主键使用自增的整数比较好?
◆使用uuid 可以吗?为什么?
◆如果是分布式系统下我们怎么生成数据库的自增id呢?
Redis 应用-分布式锁
Redis的应用之一:实现分布式锁
◆请你基于 Redis编写代码实现一个简单的分布式锁
◆要求:支持超时时间参数
◆深入思考:如果 Redis单个节点宕机了,如何处理?还有其他业界的方案实现分布式锁么?
<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">