python数据库

问题:

  • 事务的原理,特性,事务并发控制
  • 常用的字段,含义和区别
  • 常用数据库引擎之间区别

什么是事务?

  • 事务是数据库并发控制的基本单位
  • 事务可以看做一系列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
2
3
4
5
6
7
8
# 内连接
select * from Channel inner JOIN Tage on Channel.id = Tage.id
# 左链接
select * from Channel left JOIN Tage on Channel.id = Tage.id
# 右链接
select * from Channel right JOIN Tage on Channel.id = Tage.id
# 全链接
from Channel left JOIN Tage on Channel.id = Tage.id union select * from Channel right JOIN Tage on Channel.id = Tage.id

缓存的使用场景

问什么要使用缓存?

  • 缓解关系数据库(常见的是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单个节点宕机,如何处理,还有其他方式实现分布式锁吗