导读

redis字典与rehash redis hash同样采用数组加链表的方式实现,采用拉链发解决冲突,rehash过程
redis三种集群 redis三种集群模式详解 三种集群知乎redis底层数据结构 redis底层

B+树索引

  • B树结构特性描述
    对于m阶B树,根节点至少有2个子树,其它非叶节点至少m/2个子树,最多m个子树。有k个关键字的节点拥有k+1个子树。每个关键字都存储key和data。
  • redis 为什么不采取一致性hash redis为什么不用b+树_缓存

  • B+树结构特性描述
    与B树不同的是,有k个关键字的节点拥有k个子树,只有叶子节点的关键字存储key和data,非叶节点仅作为索引。所有关键字信息都会在叶子节点出现,叶子节点拥有顺序访问指针。
  • redis 为什么不采取一致性hash redis为什么不用b+树_数据_02

  • MyISAM实现(非聚集索引) data存储的是数据地址。
  • redis 为什么不采取一致性hash redis为什么不用b+树_redis 为什么不采取一致性hash_03

  • InnoDB实现(聚集索引) 主索引的data存储数据本身,辅助索引的data存储主键的值。
  • redis 为什么不采取一致性hash redis为什么不用b+树_缓存_04

  • 使用B+树而不使用红黑树的原因 红黑树出度为2,B+树出度大,拥有更小的树高,IO访问次数少。

redis设计key的相关内容

把mysql里面的表名换成redis里面key的前缀(it_user前缀)。
把mysql表里面的主键名称放在上面的前缀后面,一般用冒号分割(it_user:id)。
对应记录的主键值作为key的第三步(it_user: id:1)。
把mysql里面的其他字段作为key的第四部分(it_user: id:1:username)。

讲讲红黑树

性质
节点是红色或黑色。
根节点是黑色。
每个叶节点是黑色的。
从每个叶子到根的所有路径上不能有两个连续的红色节点。
从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
复杂度
能保证在最坏情况下,基本操作的时间均为O(lgn)。
优点
牺牲了严格的高度平衡性,降低了对旋转的要求。任何不平衡都会在三次旋转之内解决。
相比BST:BST最坏情况下查找达到O(N)。
相比AVL:统计性能比AVL树更高,插入和删除比红黑树耗时。如果你的数据分布较好,则比较宜于采用 AVL树,但是如果你想处理比较杂乱的情况,则红黑树是比较快的。

Redis缓存不一致问题

Cache Aside Pattern(旁路缓存模式)

  • 首先尝试从缓存读取,读到数据则直接返回;如果读不到,就读数据库,并将数据会写到缓存,并返回。
  • 需要更新数据时,先更新数据库,然后把缓存里对应的数据失效掉(删掉)。
    不一致产生的原因
    更新数据库成功,但是删除缓存失败。
    解决方案
    缓存失效时间变短(不推荐,治标不治本) :我们让缓存数据的过期时间变短,这样的话缓存就会从数据库中加载数据。另外,这种解决办法对于先操作缓存后操作数据库的场景不适用。
    增加cache更新重试机制(常用): 如果 cache 服务当前不可用导致缓存删除失败的话,我们就隔一段时间进行重试,重试次数可以自己定。如果多次重试还是失败的话,我们可以把当前更新失败的 key 存入队列中,等缓存服务可用之后,再将 缓存中对应的 key 删除即可。

索引失效场景

在索引列上使用内置函数,一定会导致索引失效
对索引列进行运算,一定会导致索引失效
联合索引中,where中索引列违背最左匹配原则,一定会导致索引失效
MySQL优化器的最终选择,不走索引
在查询条件中使用OR
使用like时通配符在前

如何优化查询性能

创建索引
选择不为 NULL 的字段、被频繁查询的字段、被作为条件查询的字段、被经常频繁用于连接的字段。不能选择被频繁更新的字段,避免冗余索引,尽可能的考虑建立联合索引而不是单列索引。
优化数据访问
只返回必要的行(使用 LIMIT 语句来限制返回的数据)、必要的列(不要使用 SELECT * 语句)。
缓存重复查询的数据。
使用索引来覆盖查询
重构大查询
大查询切分为多个小查询,每次只返回小部分结果。一个大查询如果一次性执行的话,可能一次锁住很多数据、占满整个事务日志、耗尽系统资源、阻塞很多小的但重要的查询。
分解大的连接查询,在应用程序中进行关联。让缓存更高效(单表查询的缓存结果更可能被其它或以后的查询使用),减少了锁竞争。

B+树的分裂

当一个结点满时,分配一个新的结点,并将原结点中1/2的数据复制到新结点,最后在父结点中增加新结点的指针;B+树的分裂只影响原结点和父结点,而不会影响兄弟结点,所以它不需要指向兄弟的指针。

解释数据库三大范式

第一范式,确保每列保持原子性。需要根据系统的实际需求来定,如地址属性,如果会访问具体的省份、城市,那就需要拆分。
第二范式,确保表中的每列都和主键相关,而不能只与主键的某一部分相关。
第三范式,确保每列都和主键直接相关,而不是间接相关。如订单表中不可以添加关于客户其它信息,而应单独设计一张客户表。

事务四大特性的理解

原子性事务被视为不可分割的最小单元,事务的所有操作要么全部提交成功,要么全部失败回滚。
一致性事务执行前和执行后须处于一致性状态。比如转账,设用户A和用户B两者的钱加起来一共5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还是5000。
隔离性一个事务所做的修改在最终提交以前,对其它事务是不可见的。
持久性一旦事务提交,则其所做的修改将会永远保存到数据库中。即使系统发生崩溃,事务执行的结果也不能丢失。

MySQL事务ACID是如何实现的

(1)利用undo log保证原子性。
undo log名为回滚日志,记录了回滚需要的信息,当事务执行失败或调用了rollback,导致事务需要回滚,便可以利用undo log中的信息将数据回滚到修改之前的样子。
(2)利用redo log保证持久性。
redo log名为重做日志。
(3)利用锁和MVCC机制保证隔离性。
当事务隔离级别为读已提交,一个事务能够读到另一个事务已经提交的数据,是不满足隔离性的。当事务隔离级别为可重复读,是满足隔离性的。
(4)通过原子性、持久性、隔离性来保证一致性。

三级封锁协议

一级封锁协议
事务要修改数据时必须加写锁,直到事务结束才释放锁。
可以解决丢失修改问题,因为不能同时有两个事务对同一个数据进行修改,那么事务的修改就不会被覆盖。
二级封锁协议
在一级的基础上,要求读取数据时必须加读锁,读取完马上释放读锁。
可以解决读脏数据问题,因为如果一个事务在对数据进行修改,根据 1 级封锁协议,会加写锁,那么就不能再加读锁了,也就是不会读入数据。
三级封锁协议
在二级的基础上,要求读取数据时必须加读锁,直到事务结束了才能释放读锁。
可以解决不可重复读的问题,因为读数据时,其它事务不能对数据加写锁,从而避免了在读的期间数据发生改变。

两段锁协议

所有的事务必须分两个阶段对数据项加锁和解锁。即事务分两个阶段,第一个阶段是获得封锁。事务可以获得任何数据项上的任何类型的锁,但是不能释放;第二阶段是释放封锁,事务可以释放任何数据项上的任何类型的锁,但不能申请。
若并发执行的所有事务均遵守两段锁协议,则对这些事务的任何并发调度策略都是可串行化的。

B+树层数相关

一个高度为3的B+树大概可以存放:1170117016=21902400行数据。所以在InnoDB中B+树高度一般为1-3层,它就能满足千万级的数据存储。在查找数据时一次页的查找代表一次IO,所以通过主键索引查询通常只需要1-3次逻辑IO操作即可查找到数据。
计算方法:一个页大小为16k。设一行数据为1k,则一个叶节点能存放16行;设主键 ID 为 bigint 类型,长度为 8 字节,指针大小在 InnoDB 源码中设置为 6 字节,这样一共 14 字节,一个页中能存放约16384/14=1170个指针。

联合索引原理

联合索引中的索引项会先根据第一个索引列进行排序,第一个索引列相同的情况下,会再按照第二个索引列进行排序,依次类推。