数据库小知识(持续更新)
1. 缓存雪崩:
布隆过滤器(1970)、分布式锁
比如说双十一某宝,redis缓存中key大面积失效,导致某宝直接和数据库进行沟通,把请求直接打到数据库 解决方法:
- 随机初始化缓存失效时间,让其不要在同一时间失效
- redis一般都是集群部署,我们把热点key放到不同的节点上去,让热点的缓存平均的分布在不同的redis节点上
- 最暴力的方法:不设置缓存的失效时间,让它永远不失效,或者跑定时任务,让它定时刷这个缓存让其不失效
2. 缓存穿透:
指缓存与数据库中都没有所要请求的数据:比如请求id=-1的数据,redis没有,直接打到数据库,数据库返回空。大量的这种请求导致数据库繁忙(数据库的主键从0开始递增,没有负数) 解决方法:
- 每次无论数据库查出什么结果,是空还是有值,都会缓存到redis里面。
- 把对面IP拉黑
- 对参数合法性做检测
- 使用布隆过滤器(好方法)
3. 缓存击穿:
比如说某宝,某个商品秒杀(该key事先存入redis缓存),大量用户抢购,但是某时刻该redis缓存到达失效时间失效了,一瞬间大量该key的请求打到数据库上
- 让这个缓存永远不过期(不好)
- 分布式锁:失效时某个查询数据库,然后加锁,其他的查询就不能查询数据库了,就先睡几毫米然后重新去redis里面查(好方法,实现方式有互斥锁、zookeeper、redis)
- (雪崩是多key失效,击穿是单key)
4. 布隆过滤器
插入时利用多个hash函数映射到一串二进制数组中,从0置1;查询时,多个hash对应的二进制位置必须都是1才能证明该数据存在
改造加强版:布谷鸟过滤器
优点:
- 二进制数组组成的数据,占用空间很小
- 插入和查询的速度很快
- 保密性很好
缺点:
- 很难做删除操作
- 存在误判的情况(解决不了,只能减少出现的概率)
存在就再去查一次数据库,误判也没关系;但不存在,那就是真的不存在。性能也比每次都查询数据库好得多。
代码中可以设置误判率,但是设置太小,性能速度就变得太差了(要增大布隆过滤器二进制数组的大小以及要采用更多的hash函数)
5. 索引如何查到真实数据的
InnoDB是聚簇索引(即将索引和数据放在一个文件里) MyISAM是非聚簇索引
innodb
- 主索引树和辅助索引树
- 主索引树:以主键id位key,叶子节点直接存储数据记录(一行)
辅助索引树:
例如select * from user_info where user_name = 'Jim'
会创建以user_name为key的索引树。其叶子节点存储的是主键key,拿到key后再去主索引树去查找相应的数据(即,回表查询)
MyISAM
无论是主键索引还是普通索引,查找数据的流程都是一样的,叶子节点存储的是数据的物理地址,拿到地址后再去内存或磁盘获得数据
延伸话题
6. 索引为什么会失效
索引失效主要针对联合索引。联合索引在B+树上的排序是按照字典序,即第一个字段、第二个字段...比如说(a, b),只有a相同下,b才是有序的;如果a有多个值,那b基本上就无序了(1, 1)(1, 2)(1, 3)(1, 4)(2, 1)(2, 2)(2, 3)(2, 4)...
最佳左前缀法则
EXPLAIN SELECT * from test_user where a = 1 and b = 1
范围查找的右边它索引会失效:
EXPLAIN SELECT * from test_user where a>1 and b=1
like会失效
EXPLAIN SELECT * from test_user where a like "1%"
- "1%": 查找以1开头的数据 - "%1": 查找以1结尾的数据 - "%1%": 查找任意位置有1的数据
7. 为什么采用B+树索引
hash索引:
- 虽然单次的访问很快,但是是无序的,如果采用hash索引的话,无法进行范围查找以及排序操作
- 存在hash碰撞问题,速度就慢下来了。
平衡二叉树索引:
- 随着树深增加,查找速度逐渐变慢
- 致命缺点:每次都是一个一个查找,不好进行范围查找
B树索引:
- 虽然解决了树高问题,但是依旧不好进行范围查找 (优点一个结点多放几个值,树可以变矮,虽然有内部查找,即一个节点内进行顺序查找的情况存在,但是内部可以理解为内存比较,不同节点可以理解为磁盘IO,内存比较就可以忽略不计了!)
B+树索引:
- 解决了范围查找问题
- 最下层 [叶子节点] 采用链表的方式顺序排序,上面的 [非叶子节点] 只存储索引key,不存储数据value,因此也不会浪费很多空间,[叶子结点] 既存key也存value(数据地址)
- 排序的时候要使用索引排序,因为已经排序好了,按照索引排序就不会产生文件的排序