数据库的一些问题

什么是事务?
  • 事务是数据库并发控制的基本单位
  • 事务可以看做是一系列SQL语句的集合
  • 事务必须要么全部执行,要么全部执行失败(回滚)
事务的ACID特性
  • 原子性:一个事务中所有操作全部完成或失败
  • 一致性:事务开始和结束之后数据完整性没有被破坏
  • 隔离性:允许多个事务同时对数据库修改和读写
  • 持久性:事务结束后,修改是永久的不会丢失
事务的并发控制可能产生哪些问题
  • 如果不对事务进行并发控制,可能会产生四种异常情况

    • 幻读:一个事务第二次查出现第一次没有的结果
    • 非重复读:一个事务重复读两次得到不同的结果
    • 脏读:一个事务读取到另外一个事务没有提交的修改
    • 丢失修改:并发写入造成其中一些修改丢失
  • 为了解决并发控制,定义了4种事务隔离级别

    • 读未提交:别的事务可以读取到未提交的改变
    • 读已提交:只能读取已经提交的数据
    • 可重复读:同一事务先后查询结果一样
    • 串行化:事务完全串行化的执行,隔离级别最高,执行效率最低
    mysql innodb默认实现可重复读级别
如何解决高并发场景下的插入重复
  • 高并发场景下,写入数据库会有数据重复问题
    • 使用数据库的唯一索引
    • 使用队列异步写入
    • 使用redis等实现分布式锁
什么是乐观锁,什么是悲观锁
  • 悲观锁是先获取锁再进行操作。一锁二查三更新 select for update
  • 乐观锁先修改,更新的时候发现数据已经变了就回滚check and set
  • 乐观锁一般是通过版本号或者时间戳实现
InnoDB vs MyISAM常见的区别
  • MyISAM不支持事务,InnoDB支持事务
  • MyISAM不支持外键,InnoDB支持外键
  • MyISAM只支持表锁,InnoDB支持行锁和表锁
为什么需要索引?
  • 索引是数据表中一个或者多个列进行排序的数据结构
  • 索引能够大幅提升检索速度
查找结构进化史
  • 线性查找:一个个找;实现简单;太慢
  • 二分查找:有序;简单;要求是有序的,插入特别慢
  • HASH:查询快;占用空间;不太适合存储大规模数据
  • 二叉查找树:插入和查询很快(logn);无法存大规模数据,复杂度退化
  • 平衡树:解决bst退化的问题,树是平衡的;节点非常多的时候,树依然很高
  • 多路查找树:一个父亲多个孩子节点;节点过多树高不会特别深
  • 多路平衡查找树 B-Tree
什么是B-Tree,为什么要使用B-Tree
  • 多路平衡查找树(每个节点最多m(m>=2)个孩子,称为m阶或者度)
  • 叶节点具有相同的深度
  • 节点中的数据key从左到右是递增的
B+树是B-Tree的变形
  • mysql实际使用的B+Tree作为索引的数据结构
  • 只在叶子节点带有指向记录的指针(可以增加树的度)
  • 叶子节点通过指针相连(实现范围查询)
mysql创建索引类型
  • 普通索引(create index)
  • 唯一索引,索引列的值必须唯一(create unique index)
  • 多列索引
  • 主键索引(primary key),一个表只能有一个
  • 全文索引(fulltext index),innodb不支持
什么时候创建索引
  • 经常用作查询条件的字段(where)
  • 经常用作表连接的字段
  • 经常出现在order by ,group by之后的字段
创建索引有哪些需要注意的
  • 非空字段not null,mysql很难对空值作查询优化
  • 区分度高,离散度大,作为索引的字段值尽量不要有大量相同值
  • 索引的长度不要太长(比较耗费时间)
索引什么时候失效
  • 记忆口诀:模糊匹配、类型隐转、最左匹配.key不能直接比较是原因
  • 以%开头的like语句,模糊搜索
  • 出现隐式类型转换
  • 没有满足最左前缀原则
什么是聚集索引?什么是非聚集索引
  • 聚集还是非聚集指的是B+Tree叶节点存的是指针还是数据记录
  • myisam索引和数据分离,使用的是非聚集索引
  • innodb数据文件就是索引文件,主键索引就是聚集索引
如何排查慢查询
  • 慢查询通常是缺少索引,索引不合理或者业务代码实现导致
    • slow_query_log_file开启并且查询慢查询日志
    • 通过explain排查索引问题
    • 调整数据修改索引;业务代码层限制不合理访问

内连接(inner join):两个表都存在匹配时,才会返回匹配行

  • 将左表和右表能够关联起来的数据连接后返回
  • 类似于求两个表的“交集”
  • select * from A inner join B on a.id = b.id
外连接(left/right join):返回一个表的行,即时另一个没有匹配
  • 左连接返回左表中所有记录,即使右表中没有匹配的记录
  • 右连接返回右表中所有的记录,即使左表中没有匹配的记录
  • 没有匹配的字段会设置成null
全连接(full join):只要某一个表存在匹配就返回
什么是缓存?为什么要使用缓存?
  • 缓存关系数据库(常见的是mysql)并发访问的压力:热点数据
  • 减少响应时间:内存IO速度比磁盘快
  • 提升吞吐量:redis等内存数据单机就可以支撑很大并发
请简述redis常用数据类型和使用场景
  • string:用来实现简单的kv键值对存储,比如计数器
  • list:实现双向链表,比如用户的关注,粉丝列表
  • hash:用来存储彼此相关信息的键值对
  • set:存储不重复元素,比如用户的关注者
  • sorted set:实时信息排行榜
redis内置实现
  • string:整数或者sds(Simple Dynamic String)
  • list:ziplist或者double linked list
  • hash:ziplist或者hashtable
  • set:intset或者hashtable
  • sorted set:skiplist跳跃表
redis实现的跳跃表是什么结构
  • sorted set为了简化实现,使用sKiplist而不是平衡树实现
redis有哪些持久化方式
  • 快照方式:把数据快照放在磁盘二进制文件中,dump.rdb
  • AOF(Append Only File):每一个写命令追加到appendonly.aof中
  • 可以通过修改redis配置实现
什么是redis事务
  • 和mysql的事务有什么不同?
    • 将多个请求打包,一次性、按序执行多个命令的机制
    • redis通过multi、exec、watch等命令实现事务功能
    • python redis-py pipeline=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的超时时间随机设置,防止同时超时
    • 架构层:提升系统可用性。监控、报警完善
原文地址:https://www.cnblogs.com/tianshug/p/11299047.html