数据库
1.索引的本质解析
二叉树
数据结构:
https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
元数有序时二叉树会退变成链表
https://www.cs.usfca.edu/~galles/visualization/BST.html
红黑树(平衡二叉树)
数据量特别大时,红黑树的高度会变的特别高,查找速度变低。
https://www.cs.usfca.edu/~galles/visualization/RedBlack.html
b-树
b+树
原始b+树
b+树从左到右是排好序的
mysq对B+树做了优化,节点之间是双向指向的及双向列表,原始的b+树树单向的
存储引擎索
聚集(聚簇)索引
InnoDB属于聚集索引:索引和数据存储在一起
MyLsam属于非聚集索引:索引和数据不存储在一起
聚集索引的查找数据打快于非聚集索引,聚集索引索引和数据在一起,找到索引及找到数据,而非聚集索引需要跨文件查找,找到索引后还要到另一个文件找数据
存储引擎是针对表来说的
innodb存储引擎索引实现解析
InnoDB存储引擎的实现(生产中绝大多数使用)
问题
1.为什么建议InnoDB表必须建主键
如果我们不指定主键,InnoDB是从所有列中找出此列每行数据都不同的一列作为主键,如果不存在这样的列InnoDB会帮我们创建一个隐藏列作为主键。所以尽量我们自己来指定主键而不是让数据库帮我开指定。
2.使用整型的自增主键
- 主键比大小整型速度最快,整形比字符串(UUID)会快很多
- B+树每个叶子节点是从左到右自增的
hash对于B+数的缺点
1.哈希冲突
2.哈希不支持范围查找
3.为什么非主键索引结构叶子节点存储的是主键值?
一致性和节省存储空间
InnoDB存储引擎表对应的文件
myisam存储引擎索引实现解析
myLSAM存储引擎的实现
myLSAM存储引擎表对应的文件
索引是怎么支撑千万级表的快速查找
mysql的底层索引有B+Tree和hash
一般都使用的是B+Tree
hash也可以做到很快的查找速度,但是不支持范围查找,B-Tree也不很好的支持范围查找
联合索引底层结构
索引最左前缀原理
2.Explain详解与索引最佳实践
Explain主要用来分析sql语句
在日常工作中,我们会有时会开慢查询去记录一些执行时间比较久的SQL语句,找出这些SQL语句并不意味着完事了,些时我们常常用到explain这个命令来查看一个这些SQL语句的执行计划,查看该SQL语句有没有使用上了索引,有没有做全表扫描,这都可以通过explain命令来查看。所以我们深入了解MySQL的基于开销的优化器,还可以获得很多可能被优化器考虑到的访问策略的细节,以及当运行SQL语句时哪种策略预计会被优化器采用。
Explain工具介绍 使用EXPLAIN关键字可以模拟优化器执行SQL语句,分析你的查询语句或是结构的性能瓶颈 在 select 语句之前增加 explain 关键字,MySQL 会在查询上设置一个标记,执行查询会返回执行计划的信息,而不是 执行这条SQL 注意:如果 from 中包含子查询,仍会执行该子查询,将结果放入临时表中
3.一条SQL在MySQL中是如何执行的
MySQL的内部组件结构
Server层 主要包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数 (如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。
Store层存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持 InnoDB、MyISAM、Memory 等多个存储引擎。现在 最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开始成为了默认存储引擎。也就是说如果我们在create table时不指定 表的存储引擎类型,默认会给你设置存储引擎为InnoDB。
连接器我们知道由于MySQL是开源的,他有非常多种类的客户端:navicat,mysql front,jdbc,SQLyog等非常丰富的客户端,这些 客户端要向mysql发起通信都必须先跟Server端建立通信连接,而建立连接的工作就是有连接器完成的。
第一步,你会先连接到这个数据库上,这时候接待你的就是连接器。连接器负责跟客户端建立连接、获取权限、维持和管 理连接。连接命令一般是这么写的:
[root@192 ~]# mysql ‐h host[数据库地址] ‐u root[用户] ‐p root[密码] ‐P 3306
连接命令中的 mysql 是客户端工具,用来跟服务端建立连接。在完成经典的 TCP 握手后,连接器就要开始认证你的身份, 这个时候用的就是你输入的用户名和密码。
1、如果用户名或密码不对,你就会收到一个"Access denied for user"的错误,然后客户端程序结束执行。
2、如果用户名密码认证通过,连接器会到权限表里面查出你拥有的权限。之后,这个连接里面的权限判断逻辑,都将依赖于此时读到的权 限。
这就意味着,一个用户成功建立连接后,即使你用管理员账号对这个用户的权限做了修改,也不会影响已经存在连接的权 限。修改完成后,只有再新建的连接才会使用新的权限设置。用户的权限表在系统表空间的mysql的user表中。
4.Mysql索引优化实战一
优化准则:
sql查询尽量单表操作,避免复杂操作,复杂的多表通过java代码实现
构建复合索引优化
避免查询索引失效
文档:04-VIP-Mysql索引优化实战一.note
链接:http://note.youdao.com/noteshare?id=0727c1f390616bb11986a975986093b3&sub=CEEC9C46957244058F7ADD6394E68E2D
联合索引优化
in 和or数据量小的时候不走索引,数据量大的时候都会走索引。
通过联合索引优化sql
一张表建的联合索引尽量不要超过3个,联合索引太多的还影响表中数据的插入和删除的效率。
如果是读多写少的场景可以多建些联合索引(3-4个),如果是写多的场景联合索引不要查过三个。
一张表的数据行数一般不超过千万。
5.Mysql索引优化实战二
文档:05-VIP-Mysql索引优化实战二.note
链接:http://note.youdao.com/noteshare?id=bd9b3d9a9e5764f6b63eb915b106dd39&sub=B5147BE69CBC46108B6DB24F9C055365
分页查询优化
很多时候我们业务系统实现分页功能可能会用如下sql实现
mysql> select * from employees limit 10000,10;
表示从表 employees 中取出从 10001 行开始的 10 行记录。看似只查询了 10 条记录,实际这条 SQL 是先读取 10010
条记录,然后抛弃前 10000 条记录,然后读到后面 10 条想要的数据。因此要查询一张大表比较靠后的数据,执行效率
是非常低的。
优化:
6.Mysql锁与事务隔离级别
事务及其ACID属性
事务是由一组SQL语句组成的逻辑处理单元,事务具有以下4个属性,通常简称为事务的ACID属性。
原子性(Atomicity) :事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。
一致性(Consistent) :在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性。
隔离性(Isolation) :数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。
持久性(Durable) :事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。
并发事务处理带来的问题
更新丢失(Lost Update)或脏写
当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题–最后的更新覆盖了由其他事务所做的更新。
脏读(Dirty Reads)
一个事务正在对一条记录做修改,在这个事务完成并提交前,这条记录的数据就处于不一致的状态;这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”数据,并据此作进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象的叫做“脏读”。
一句话:事务A读取到了事务B已经修改但尚未提交的数据,还在这个数据基础上做了操作。此时,如果B事务回滚,A读取的数据无效,不符合一致性要求。
不可重读(Non-Repeatable Reads)
一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了改变、或某些记录已经被删除了!这种现象就叫做“不可重复读”。
一句话:事务A内部的相同查询语句在不同时刻读出的结果不一致,不符合隔离性
幻读(Phantom Reads)
一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”。
一句话:事务A读取到了事务B提交的新增数据,不符合隔离性
Mysql默认的事务隔离级别是可重复读,用Spring开发程序时,如果不设置隔离级别默认用Mysql设置的隔离级别,如果Spring设置了就用已经设置的隔离级别
锁详解
乐观锁
总是认为不会产生并发问题,每次去取数据的时候总认为不会有其他线程对数据进行修改,因此不会上锁,但是在更新时会判断其他线程在这之前有没有对数据进行修改,一般会使用版本号机制或CAS操作实现。
version方式:一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。
核心SQL代码:
update table set x=x+1, version=version+1 where id=#{id} and version=#{version};
CAS操作方式:即compare and swap 或者 compare and set,涉及到三个操作数,数据所在的内存值,预期值,新值。当需要更新时,判断当前内存值与之前取到的值是否相等,若相等,则用新值更新,若失败则重试,一般情况下是一个自旋操作,即不断的重试。
悲观锁
总是假设最坏的情况,每次取数据时都认为其他线程会修改,所以都会加锁(读锁、写锁、行锁等),当其他线程想要访问数据时,都需要阻塞挂起。可以依靠数据库实现,如行锁、读锁和写锁等,都是在操作之前加锁,在Java中,synchronized的思想也是悲观锁。
表锁
每次操作锁住整张表。开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;一般用在整表数据迁
行锁
每次操作锁住一行数据。开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度最高。
MYISAM不支持事务,只支持表锁
InnoDB与MYISAM的最大不同有两点:
- InnoDB支持事务(TRANSACTION)
- InnoDB支持行级锁
可重复读
(1)打开一个客户端A,并设置当前事务模式为repeatable read,查询表account的所有记录
set tx_isolation=‘repeatable-read’;
(2)在客户端A的事务提交之前,打开另一个客户端B,更新表account并提交
(3)在客户端A查询表account的所有记录,与步骤(1)查询结果一致,没有出现不可重复读的问题
(4)更新数据时不要查出来再做逻辑让后更新数据库数据,而是直接使用 upate语句实时更新数据,这样balance才是数据库真实的值。在客户端A,接着执行update account set balance = balance - 50 where id = 1,balance没有变成400-50=350,lilei的balance值用的是步骤2中的350来算的,所以是300,数据的一致性倒是没有被破坏。可重复读的隔离级别下使用了MVCC(multi-version concurrency control)机制,select操作不会更新版本号,是快照读(历史版本);insert、update和delete会更新版本号,是当前读(当前版本)。
(5)重新打开客户端B,插入一条新数据后提交
(6)在客户端A查询表account的所有记录,没有查出新增数据,所以没有出现幻读
索引失效的弊端:
结论
Innodb存储引擎由于实现了行级锁定,虽然在锁定机制的实现方面所带来的性能损耗可能比表级锁定会要更高一下,但是在整体并发处理能力方面要远远优于MYISAM的表级锁定的。当系统并发量高的时候,Innodb的整体性能和MYISAM相比就会有比较明显的优势了。
但是,Innodb的行级锁定同样也有其脆弱的一面,当我们使用不当的时候,可能会让Innodb的整体性能表现不仅不能比MYISAM高,甚至可能会更差。
7. MVCC与BufferPool缓存机制
MVCC
MVCC机制:所有数据在mysql内部有一个undo.log日志,及und日志版本链,在事务中第一次执行查询语句的时候会生成read view 一致性试图,这个事务中所有的查询语句,根据read view去undo日志中比对找到对应的数据。select操作不会更新read view版本号,是快照读(历史版本);insert、update和delete会更新版本号,是当前读(当前版本)。
每个事务里面都有自己的rea-view。
buffer pool 是为了提高效率。
2.java虚拟机JVM
P8
jdk体系和jvm架构讲解
JDK体系结构
JVM整体结构
04:44
P9
运行时数据区-帧栈详解
14:09
P10
局部变量表、操作数栈详解
18:52
P11
方法区、本地方法栈详解
14:29
P12
堆内存详细解析
13:49
P13
垃圾收集机制解析
19:03
P14
线上系统jvm调优实战案例
年轻代尽量大一些,可以让朝生夕死的对应在伊甸园区GC的时候处理掉,避免放到老年代
23:22
P15
jvm性能调优与底层原理综合分析
55:20
P16
3.java内存模型JMM
多核并发缓存架构
jmm模型讲解
jmm数据原子操作
jmm缓存不一致性问题
volatile可见性底层实现原理
volatile可见性、原子性和有序性讲解
理论生是101000, 实际小于等于101000
volatile不保证原子性体现就在这
26:24
P22
深入理解java内存模型jmm与volatile关键字
1:11:59
P23
servlet3.x新规范解读
14:27
P24
java spi 动态服务扩展机制讲解
14:44
P25
启动流程分析
08:39
P26
springioc父容器启动源码剖析
springBeen生命周期
21:14
P27
springioc子容器启动源码剖析
21:25
P28
dispatcherservlet源码深度剖析
13:09
P41
springboot零配置实现原理剖析
20:23
P42
springboot启动流程综合讲解
35:04
P43
springboot自动装配原理解析
10:33
P44
bean自定义对象生命周期讲解
16:41
P45
bean定义解析
15:27
P46
@import注解剖析
17:54
P47
springboot自动装配源码深度剖析
31:35
P48
优雅的手写springboot自定义启动器