问题:
- 事务的原理,特性,事务并发控制
- 常用的字段,含义和区别
- 常用数据库引擎之间区别
什么是事务?
- 事务是数据库并发控制的基本单位
- 事务可以看做一系列sql语句的集合
- 事务必须要么全部执行,要么全部执行失败(回滚)
事务的ACID特性
- 原子性(Atomicity): 一个事务所有操作全部完成或全部失败
- 一致性(Consistency)事务开始和结束之后数据完整性没有被破坏
- 隔离性(Isolation): 允许多个事务同事对数据库修改和读写
- 持久性(Durability) 事务结束后,修改是永久不会丢失的
事务的并发控制可能产生那些问题
- 幻读(phantom read) 一个事务第二次查出现第一次没有的结果
- 非重复读(nonrepeatable read)一个事务重复读两次得到不同的结果
- 脏读(dirty read) 一个事务读取到另一个事务没有提交的修改
- 修改丢失(lost update) 并发写入造成的一些修改丢失
四种事务的隔离级别
- 读未提交(read uncommitted) 别的事务可以读取到未提交改变
- 读已提交(read committed)只能读取已经提交的数据
- 可重复读(repeatable read): 同一个事务先后查询的结果都一样
- mysql innoDB 默认实现可重复读级别
- 串行化(serializable) 事务完全串行化执行,隔离级别最高,但是效率最低
如何解决高并发场景下的插入重复?
- 使用数据库的唯一索引
- 使用队列异步写入
- 使用redis等实现分布式锁
乐观锁和悲观锁
- 悲观锁是先获取到锁之后再进行操作:一锁二差三更新 select for update
- 乐观锁 先修改,更新的时候发现数据已经变了,就回滚(check and set)
- 乐观锁一般通过版本号或时间戳来实现
- 使用需要根据响应速度,冲突频率,重试代价来判断使用哪一种
mysql常用的数据类型



InnoDB 与 MyIsAM的区别
- MyISAM不支持事务,InnoDB支持事务
- MyISAM不支持外键,InnoDB支持外键
- MyISAM只支持表锁,InnoDB支持行锁和表锁
- MyISAM支持全文索引,InnoDB不支持全文索引(5.6.24之后加上了索引)
mysql索引原理及优化常见考题
索引的原理,类型,结构
创建索引的注意事项,使用原则
如何排查和消除慢查询
什么是索引?
- 索引是数据库表中一个或多个列进行排序的数据结构
- 索引能够大幅度提升检索速度
- 创建,更新索引本身也会耗费空间和时间的
什么是B-Tree(为什么数据库要使用B+Tree)
- 线性查找:一个一个找,实现简单,但是太慢了
- 二分查找: 有序,简单,要求是有序的,插入特别慢
- hash : 查询快,占用空间,不适合存储大规模数据
- 二叉树:插入和查询很快(log(n)),无法存大规模数据,复杂度退化
- 平衡树:解决bst 退化的问题,树是平衡的
- 多路查找树:一个父亲多个孩子节点,节点过多树高不会特别深
- 多路平衡查找树:B-Tree
什么是B-Tree,为什么使用B-Tree?
- 多路平衡查找树(每个节点最多m(m>=2)个孩子,称为m阶或度)
- 叶节点具有相同的深度
- 节点中的数据key从左到右是递增的
什么是B+Tree
- B+树是B-Tree树的变形
- mysql实际使用B+Tree作为索引的数据结构
- 只在叶子节点带有指向记录的指针(为什么,可以增加树的度)
- 叶子节点通过指针相连,为什么,实现范围查询
msyql索引的类型
- 普通索引(create index)
- 唯一索引:索引列的值必须唯一(create unioue index)
- 多列索引
- 主键索引(primary key )一个表中只能有一个主键
- 全文索引(fulltext index),innoDB不支持(5.6后支持)
什么时候创建索引
- 建表的时候需要根据查询需求来创建索引
- 经常用作查询条件的字段(where条件)
- 经常用作表连接的字段
- 经常出现在order by,group by之后的字段
创建索引有那些需要注意的
- 非空字段 not null ,mysql很难对空值做查询优化
- 区分度高,离散度大,作为索引的字段值尽量不要有大量相同值
- 索引的长度不要太长(比较耗费时间)
索引什么时候失效
- 模糊匹配,类型隐转,最左匹配
- 以%开头的like语句,模糊搜索
- 出现隐式类型转换(在python这种动态语言查询中需要注意)
- 没有满足最左前缀原则
什么是聚集索引和非聚集索引
- 聚集还是非聚集指的是B+Tree叶节点存的是指针还是数据记录
- MyISAM索引和数据分离,使用的是非聚集索引
- InnoDB数据文件就是索引文件,主键索引就是聚集索引
如何排查慢查询
- 慢查询通常是缺少索引,索引不合理或者业务代码实现导致的
- slow_query_log_file 开启兵器查询慢查询日志
- 通过explain 排查索引问题
- 调整数据修改索引,业务代码层限制不合理访问
sql语句编写常考题
sql语句考察各种链接为重点
- 内连接(inner join) 两个表都存在匹配时,才会匹配行
- 外链接(left、right join)返回一个表的行,即使另一个没有匹配
- 全连接(full join) 只要某一个表存在匹配就返回 (mysql中不支持full join 可以使用left join+ union+right join)
1 | # 内连接 |
缓存的使用场景

问什么要使用缓存?
- 缓解关系数据库(常见的是Mysql)并发访问的压力,热点数据
- 减少响应时间: 内存IO速度比磁盘快
- 提升吞吐量:Redis等内存数据库单机就可以支撑很大的并发
简述redis常用的数据类型和使用场景
- string(字符串) 用来实现简单的kv键值对存储,比如计数器
- List(链表):实现双向链表,比如用户关注,粉丝列表
- Hash(哈希表):用来存储彼此相关信息的键值对
- Set(集合) 存储不重复元素,比如用户的关注者
- sorted Set(有序集合) 实时信息排行榜
redis各种类型的底层实现
- string:整数或者sds(Simple Dynamic String)
- List: ziplist 或者double linked list
- ziplist:通过一个连续的内存块实现list结构,其中的每个entry节点头部保存节点前后长度信息,实现双向链表功能
- Hash:ziplist 或者hashtable
- set intset 或者hashtable
- sortedSet: skiplist跳跃表
redis实现的跳跃表是什么
- sorted set 为了简化实现,使用skiplist 而不是平衡树实现
redis支持两种方式实现持久化
- 快照方式:把数据快照放在磁盘二进制文件中,dump.rdb
- 快照的实现方式是指定时间间隔把redis数据库状态保存到一个压缩二进制文件中
- AOF:每个写命令追加到appendonly.aof 中
- 可以通过修改Redis配置实现
什么是Redis事务?
- 将多个请求打包,一次性,按序执行多个命令的机制
- Redis通过MULTI,EXEC,WATCH 等命令实现事务功能
1 | python redis-py plpline = conn.pipline(transaction=True) |
Redis如何实现分布式锁?
- 使用setnx实现加锁,可以同事通过expire添加超时时间
- 锁的value值可以使用一个随机的uuid或者特定的命名
- 释放锁的时候,通过uuid判断是否是该锁,是则执行delete释放锁
使用缓存的模式
- cache Aside 同时更新缓存和数据库
- Read、Write Through:先更新缓存,缓存负责同步更新数据库
- Write Behind Caching:先更新缓存,缓存定期异步更新数据库
如何解决缓存穿透问题
- 原因
- 大量查询不到的数据的请求落到后端数据库,数据库压力增大
- 由于大量缓存查不到就去数据库取,数据库也没有要查的数据
- 解决
- 对于没有查到的数据返回None的数据也缓存下来
- 插入数据的时候删除一个缓存,或者设置较短的超时时间
如何解决缓存击穿问题?
- 原因
- 某些非常热点的数据key过期,大量请求打到后端数据库
- 热点数据key失效导致大量请求打到数据库增加数据库压力
- 解决
- 分布式锁: 获取锁的线程从数据库拉数据更新缓存,其他线程等待
- 异步后台更新:后台任务针对过期的key 自动刷新
如何解决缓存雪崩问题
- 原因
- 缓存不可用或者大量缓存key,大量请求直接打到数据库
- 解决
- 多级缓存: 不同级别的key设置不同的超时时间
- 随机超时:key的超时时间随机设置,防止同时超时‘
- 架构层:提升系统可用性,监控,报警完善
练习
索引的理解?
- 为什么mysql数据库的主键使用自增证书比较好
- 使用uuid可以吗?为什么
- 如果是分布式系统下我们如何生成自己数据库中的自增id
redis的应用?
- 请基于Redis编写代码实现一个分布式锁
- 要求:支持超时时间参数
- 深入思考:如果Redis单个节点宕机,如何处理,还有其他方式实现分布式锁吗