大家好,我是左耳君,欢迎大家关注
正如大家所预料,接下来我们针对数据库的知识点进行全方位的分析,其实数据库应该是程序员的必备技能了,也是大家最最常用的了,大家不可能在开发中不会用到数据库吧,那我有必要怀疑你是个假程序员
这一系列其实我很早之前就想写了,但是也只是处于一个想的阶段,一个构思,思考如何才能更好的把这一系列写好,其实吧,本来吧我这人写作就不太擅长,不过感觉现在比之前好多了,最起码也可以和大家瞎聊聊了
我也会坚持写下去,虽然现在的粉丝并不多,但是我写这个的初衷也是为了记录自己的学习知识点,我相信每一个程序员对于庞大的后端知识体系都不可能是手到擒来,都需要进行一段时间的回忆和思考,所以呢,正是由于这个,我就产生了写文章的这个想法,把自己对于知识点的汇总和理解记录下来,如果后续遇到一些不清楚的,可以利用自己的文章迅速的捡起来
所以呢,大家也可以在之前的rocketmq系列文章也可以看出来,我会自己记录并且转发一些自己认为比较好的文章,为的就是以后用到该知识点可以手到擒来!
数据库呢,大家用的最多的肯定就是mysql了,当然,我们接下来要分析的知识点也是围绕mysql来分析
1、数据库三大范式
2、mysql常用存储引擎
3、树结构和索引类型
4、查询性能优化、explain、索引优化
5、事务、锁类型
6、常用日志类型
7、MVCC多版本并发控制
8、分库分表策略
9、JSON
10、主从复制、读写分离
01 数据库三大范式
第一范式:确保每一列的原子性,也就是表中的每个字段都是不可分解的原子值,这个属于最基本的范式
第一范式的合理遵循需要根据系统来设定,比如有些系统中的地址属性,在系统中的出现永远都是整个地址属性,那就属于满足原子性,满足第一范式。
但是,如果如果我们系统中可能会经常用到地址中的省、市、区,而且还可能经常单独出现其中某一个属性,那这就属于不满足第一范式了
所以,是否满足第一范式不能单纯的按照我们的日常习俗去断定,需要根据系统的设定来决定是否真正满足第一范式
第二范式:确保表中的每一列都和主键相关,而不能只和主键中的其中一部分相关,主要是针对联合主键
也就是一个数据库表中,只能保存一种数据,不可能把多种数据保存到同一张数据表中,比如要统计一个地区的多个学校的学生,因为地区有多个学校,每个学校中的学生有相应的编号,所以要把学校ID和学生编号设计成一个联合主键
第三范式:确保每一列和主键都是直接相关,而不是间接相关
再说上面的例子,我们可以通过学校ID作为外键和学校教师表建立相应的关系,而不能直接把学校教师相关信息存储到学生表,这样就属于违反了第三范式了
存储引擎
存储引擎其实就是属于对数据库文件的一种存取的方式,如何实现底层的存储数据,以及如何为存储的数据建立索引
存储引擎属于表级别,这一点可千万要知道,难道你没见过在建表的时候让你选择该表的存储引擎的吗
mysql常用存储引擎有四种:MyISAM存储引擎、innoDB存储引擎、MEMORY存储引擎、ARCHIVE存储引擎
// 查看mysql所支持的存储引擎,以及从中得到mysql默认的存储引擎
show engines;
// 查看mysql 默认的存储引擎
show variables like '% storage_engine';
// 查看具体某一个表所使用的存储引擎,这个默认存储引擎被修改了!
show create table tablename ;
//准确查看某个数据库中的某一表所使用的存储引擎
show table status from database where name="tablename"
MyISAM存储引擎
不支持事务,不支持行级锁,只能对整张表进行加锁,只支持并发插入的表锁,主要用于高负载的select,读取的时候对需要读的表加共享锁,写入时则对表加排他锁
在表有读取操作的同时,也支持往表中插入新的记录,这是并发插入
底层结构也是B+树,但是属于非聚簇索引,也就是说只要查询的数据不止主键列,就需要记性回表查询,这一特性和innodb引擎还是不一样的,innodb采用的是聚簇索引,这两个概念会在下面介绍,大家先简单了解下
强调了快速读取操作,占用空间小,处理速度快,表支持三种不同类型的存储结构:静态型、动态型和压缩型
静态型:表的列的大小固定,自动使用静态的存储,性能比较高,因为在维护和访问一预定格式存储数据时需要的开销低,但是这种高性能是用空间为代价换来的,因为定义的时候固定,不管列中的值有多大,都会以最大值为准,占据整个空间
动态型:如果列定义是动态的,就会自动使用动态存储,虽然动态型的表占用了较少的空间,但是会带来性能的降低,因为某个字段内容发生改变其位置就需要移动,可能导致内存碎片的产生
对于内存碎片一般两种解决方案:
1、尽量使用静态数据类型
2、经常使用optimize table table_name语句整理表的碎片,恢复由于表数据的更新和删除导致的空间丢失
压缩型:如果在数据库中创建在整个生命周期内只读的表,则应该使用MyISAM的压缩型表来减少空间的占用。
innoDB存储引擎
mysql的默认存储引擎,支持事务,回滚以及系统崩溃的修复能力
底层存储索引也是使用B+树,和上面不同的是使用的聚簇索引,减少了回表这一操作,可以直接通过主键找到整条数据,因此性能较高
innodb内部优化,在磁盘读取数据的时候采用的可预测性读,能够在内存中创建hash索引用来加速读操作,以及能够加速插入操作的插入缓冲区
支持自增长列,自增长列的值不能为空,支持外键
采用MVCC多版本并发控制支持高并发,而且实现了四种隔离级别,每一种隔离级别对应着该等级存在的问题,可以根据业务场景选择合适的隔离级别
MEMORY存储引擎
在内存中创建表,所有数据也是存在在内存中
每个基于内存存储引擎的表都实际对应一个磁盘文件,文件名和表名是相同的,类型为.frm,该文件只存储表的结构,而数据文件都是存储在内存中,有利于对数据的快速处理,提高整个表的处理能力
默认使用hash索引,速度比B+树快,缺点就是对于范围查询不友好咯,这个下面会对数据结构分析一波,大家就会明白B+树索引和hash索引的区别
如果进程发生异常重启或者关闭机器,这些数据都会消失,所以该存储引擎中的表的数据的生命周期都很短,一般也只使用一次
ARCHIVE存储引擎
该存储引擎非常适合存储大量独立的、作为历史记录的数据。区别于InnoDB和MyISAM这两种引擎,ARCHIVE提供了压缩功能,拥有高效的插入速度,但是这种引擎不支持索引,所以查询性能较差一些
二叉树
N个有限元素的集合组成,集合为空的时候,则是一个空的二叉树
树中的节点的度不大于2的有序树,二叉树的每个节点最多有两颗字数,且有左右之分
左子树元素小于父节点元素,右子树节点元素大于父节点元素,次序不能颠倒
即使某个节点只有一个子树,也要区分左子树和右子树
优点:有序,可以更快的查询到相应元素
缺点:如果选取根节点不准确,则容易出现左右子树的高度偏差情况,极限情况下,可能会出现链式的结构,下面AVL树也是为了解决这个情况而出现的
AVL二叉平衡树
是一个空树或者左右子树的高度差的绝对值不超1,并且左右两个子树也都是一颗平衡二叉树,为的就是解决上述说的退化成链表的情况
插入、查找和删除的时间复杂度的最好情况和最坏情况都维持在O(logN),但是最好不要用于修改数据比较多的情况下,一般用于修改少查询多的场景
红黑树
它一种特殊的二叉查找树。
红黑树的每个节点上都有存储位表示节点的颜色,可以是红(Red)或黑(Black)。
相较于严格要求平衡的AVL树,它的旋转的保持平衡次数较少,适合查找少和修改次数较多的场景
红黑树的特性:
(1)每个节点或者是黑色,或者是红色。
(2)根节点是黑色。
(3)每个叶子节点(NIL)是黑色。这里叶子节点,是指为空(NIL或NULL)的叶子节点
(4)如果一个节点是红色的,则它的子节点必须是黑色的。
(5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
叶子节点,是只为空(NIL或null)的节点
确保没有一条路径会比其他路径长出俩倍,因而,红黑树是相对是接近平衡的二叉树
B树
上面说到的都是属于两个子节点,这种结构如果用于文件系统有一个很大的缺点,就是树的高度会比较高,会使文件系统多次的进行磁盘IO,效率极其低
多路查找树,体态矮胖,可以更少的进行磁盘IO,想象一下,树的每一层代表一次磁盘IO
描述一棵B树时需要指定它的阶数,阶数表示了一个节点最多有多少的孩子节点,一般使用字母m表示阶数。
当m取2时,就是我们常见的二叉搜索树。
一棵m阶的B数定义如下:
(1)每个节点最多有m-1个关键字
(2)根节点最少可以只有一个关键字
(3)非根节点至少有Math.ceil(m/2)-1个关键字
(4)每个节点的关键字都按照从小到大的顺序排列,每个关键字的左子树中的所有关键字都小于它,而右子树中的所有关键字都大于它
(5)所有叶子节点都位于同一层,或者说根节点到每个叶子节点的路径长度都相同
B+树
B+树是对B树的变形,最大的区别是非叶子节点不保存数据,而只用于存储索引,所有的数据都保存到叶子节点中
B树是所有节点(包含叶子节点)组成了所有的数据,而B+树是所有数据均存储到叶子节点上
同时B+树的所有叶子节点都有相邻叶子节点的指针,也就是所有叶子节点组成了一个链表
关于数据结构,这里我给大家推荐一个网站,可以学习下各种数据结构,观看数据组成原理:
https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
B树和B+树的对比
B+树的磁盘IO更低,查询效率更高
B+树的非叶子节点并不会存储整条数据,而是存储数据的索引,这句话是针对于MySQL表来说,因此非叶子节点可以用同样的存储空间,存储更多的索引数据,也就使得B+树更加的矮胖,可以一次性读入内存中的关键字也就越多,磁盘的IO次数也就降低了,查询效率也就更高
查询