B+树与B树差异的点
叶子节点最底部的节点才会存放实际数据(索引+记录),非叶子节点只会存放索引
所有索引都会在叶子节点出现,叶子节点之间构成一个有序链表
为什么mysql使用B+树
单点查询:B+树的非叶子节点不存放实际的记录数据,仅存放索引,因此数据量相同的情况下,相比存储即存索引又存记录的B树,B+树的非叶子节点可以存放更多的索引,因此B+树可以比B树更矮胖,查询底层节点的磁盘I/O次数会更少
插入和删除效率:B+树有大量的冗余节点,这样使得删除一个节点的时候,可以直接从叶子节点中删除,甚至可以不动非叶子节点。B树则不同,B树没有冗余节点,删除节点的时候非常复杂,
范围查询:B+树的所有叶子节点还有一个链表进行连接,查询12.1-12.12之间订单,就可以先查找12.1所在的叶子节点,然后利用链表向右遍历,指导找到12.12的节点,不需要从根节点查询
为什么主键索引最好是自增的
InnoDB创建主键索引默认为聚簇索引,数据被存放在B+tree的叶子节点,同一个叶子节点内的各个数据是按照主键顺序存放的,每当一条新的数据插入时,数据库会根据主键将其插入到对应的叶子节点中
如果使用自增主键,那么每次插入的新数据就会按照顺序添加到当前索引节点的位置,不需要移动已有的数据,当页面写满,就会自动开辟一个新页面,因为每次插入一条新纪录,都是追加操作,不需要重新移动数据
如果使用非自增主键,由于每次插入主键的索引值都是随机的,因此插入新的数据时,就可能会插入到现有数据页中间的某个位置,将不得不移动其他数据来满足新数据的插入,甚至需要从一个页面复制数据到另外一个页面,通常叫做页分裂,页分裂还有可能会造成大量的内存碎片,导致索引结构不紧凑,从而影响查询效率。
类加载过程
加载(Loading)->连接Linking(验证,准备,解析)->初始化->使用->卸载
载入:JVM载该阶段的目的是将字节码从不同的数据源(class文件,jar包,网络中)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.class对象
验证:jvm会在该阶段对二进制字节流进行校验,只有符合JVM字节码规范的才能被JVM正确执行
准备:对使用static关键字修饰的静态变量分配内存并初始化,对应数据类型的默认初始值 如0,0L,null,false。使用static final修饰的变量称为常量,直接赋最终值,使用static修饰的变量赋初值
解析:将符号引用转化为直接引用,符号引用是一组符号(任何形式的字面量,只要在使用时能够无歧义的定位到目标即可)来描述所引用的目标。直接引用通过对符号引用进行解析,找到引用的实际内存地址
初始化:类变量赋上代码期望赋的值,执行类构造器方法的过程
一条sql语句的查询过程
1.客户端发送sql查询语句到mysql服务器
2.mysql服务器的连接器开始处理这个请求,跟客户端建立连接,获取权限,管理连接
3.解析器对sql语句进行解析,检查语句是否符合sql语法规则,确保引用的数据库,表和列都是存在的,并处理sql语句中的名称解析和权限验证
4.优化器负责确定sql语句的执行计划,这包括选择使用那些索引,以及决定表之间的连接顺序等
第一步 连接器
先连接mysql服务,然后才能执行sql语句,tcp三次握手,验证用户名和密码,获取用户权限
第二步 解析SQL
词法分析 会根据你输入的字符串识别出关键字出来 如select from
语法分析:语法分析器会根据语法规则,判断你输入的这个sql语句是否满足mysql语法,如果没问题就会构建sql语法树,这样方便后面模块获取SQL类型,表名,字段名,where条件
执行SQL
prepare阶段:预处理阶段
检查SQL查询语句中的表或者字段是否存在
将select*中的*符号,扩展为表上的所有列
optimize阶段 优化阶段
经过预处理阶段后,还需要为SQL查询语句先制定一个执行计划,这个工作交由优化器来完成。优化器主要负责将SQL查询语句的执行方案确定下来,比如表里面有多个索引,优化器会基于查询成本的考虑,来决定选择使用哪个索引
execute阶段 执行阶段
Java反射原理
对于任意一个类,都能够知道这个类中的所有属性和方法,对于任意一个对象,都能够调用他的任意一个方法和属性。
运行时类信息访问:反射机制允许程序在运行时获取类的完整结构信息,包括类名,包名,父类,实现的接口,构造函数,方法和字段
动态对象创建:可以使用反射api动态地创建对象实例,即使在编译时不知道具体的类名,通过class类的newInstance方法
动态方法调用:可以在运行时动态调用对象的方法,包括私有方法,通过Method类的invoke方法实现,允许传入对象实例和参数值来执行方法
访问和修改字段值:反射允许程序在运行时访问和修改对象的字段值,即使是私有的
Redis的数据备份(AOF和RDB)
AOF日志:如果Redis每执行一条写操作命令,就把该命令以追加的方式写入到一个文件里,然后重启Redis的时候,先去读取这个文件里的命令,并且执行它
AOF写会硬盘的策略:
Always策略的话,可以最大程度保证数据不丢失,但是由于他每执行一条写操作就同步将AOF内容写会硬盘,所以不可避免影响主进程的性能
No策略:是交由操作系统来决定何时将AOF日志内容写会硬盘,相比Always策略性能较好,但是操作系统写回硬盘的时机不可预知,如果AOF日志内容没有写回硬盘,一旦服务器宕机,就会丢失不定数量的数据
Everysec策略:每一秒将写操作日志写回到磁盘
RDB快照:记录某一瞬间的内存数据,记录的是实际数据,而AOF文件记录的是命令操作的日志,而不是实际的数据
混合持久化工作
AOF重写日志时,fork出来的重写子进程会先将与主进程共享的内存数据以RDB方式写入到AOF文件,然后主线程处理的操作命令会被记录在重写缓存区里,重写缓冲区里的增量命令会以AOF方式写入到AOF文件,写入完成后通知主进程将新的含有RDB格式和AOF格式的AOF文件替换旧的AOF文件
执行快照时,数据能被修改吗
执行bgsave过程,交给子进程构建RDB文件,主线程要修改共享数据的某一块数据时,就会发生写时复制,于是这块数据的物理内存就会被复制一份,然后主线程在这个数据副本进行修改操作,与此同时,bgsave子进程可以继续把原来的数据写入到RDB文件。主线程修改共享数据,发生了写时复制,RDB快照保存的时原本的内存数据,主线程刚修改的数据是没办法在这一时间写入RDB文件的,只能交给下一次bgsave快照
索引分类
按物理存储的角度来看,索引分为聚簇索引(主键索引),二级索引(辅助索引)
主键索引的B+Tree的叶子节点存放的是实际数据,所有完整的用户记录都存放在主键索引的B+Tree的叶子节点里
二级索引的B+Tree的叶子节点存放的是主键值,而不是实际数据
按字段特性分为 主键索引,唯一索引,普通索引,前缀索引
主键索引是建立在主键字段上的索引,通常在创建表的时候一起创建,一张表最多只有一个主键索引,索引列的值不允许有空值
唯一索引
建立在unique字段上的索引,一张表可以有多个唯一索引,索引列的值必须唯一,但是允许有空值
普通索引
建立在普通字段上的索引,既不要求字段为主键,也不要求字段为unique
按字段个数分类
建立在单列上的索引称为单列索引
建立在多列上的索引称为联合索引