数据库的一些问题
Posted tianshug
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库的一些问题相关的知识,希望对你有一定的参考价值。
什么是事务?
- 事务是数据库并发控制的基本单位
- 事务可以看做是一系列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的超时时间随机设置,防止同时超时
- 架构层:提升系统可用性。监控、报警完善
以上是关于数据库的一些问题的主要内容,如果未能解决你的问题,请参考以下文章