慢 SQL 定位:
可以在测试环境使用,生产环境不要用!!!生产环境可以用 Shywalking
开启慢 SQL 执行日志 ,在Mysql 配置文件(etc/my.cnf)设置语句
slow_query_log = 1; -- 开启慢 SQL 日志
long_query_time = 2; -- 设置慢 SQL 执行时间 单位:秒
例如一个 SQL 执行超过 2 秒,就会记录到日志文件(localhost-show.log)
慢 SQL 分析:
使用分析指令 explain 会输出当前 sql 执行信息
主要注意一下信息:
possible_keys:可能使用到的索引
key:实际使用的索引
ken_len: 索引占用的大小
Extra: 额外的建议优化 ,如 Using where;Using index; 使用索引查找且需要的数据在索引中可以找到,不需要回表查询 ; Using index condition;使用索引但需要回表查询;(回表查询会多做一次数据查询)
type:sql 的链接类型,可以通过它来判断 sql 性能的好坏,常见类型有 Null , System , const , eq_ref ,ref, range, inde , all ,从左到右性能越来越差
Null 与 System 不常用到 , const:主键索引查询,eq_ref:主键索引或唯一索引,ref:
索引查询 与 eq_ref 不同的是,ref 查询可能有多条数据,range: 走索引但是为范围查询,index:
全索引树扫描查询, all: 全表查询
还有一些其它参数,有兴趣的小伙伴自己查一下!
Mysql 索引基础知识:
索引是帮助提高查找效率的一种数据结构
在介绍Mysql索引数据结构之前,先补充一些其它数据结构知识:
1. 二叉查找树
特点:左子树的节点值小于根节点,根节点小于右子树节点值,适合数据查找,如果出现退化或数据量大树的层级(高度)多查询效率变低
2. B 树
特点:左子树的节点值小于根节点,根节点小于右子树的节点值,一个节点可以存放多个子节点,子节点中存储key、key 对应的数据、下一个节点的地址值,存多个子节点可以减少树的层级提高查询效率
3. B+树
特点:B+ 树在 B 树结构做了修改,每个树节点中只存储key 和下一个节点的地址值,不存放数据释放空间,用于存放更多的子节点减少树的层级提高查询效率,所有的数据只存放在叶子节点并且所有的叶子节点组成一个有序的链表
在大数据环境下,以上三种树在查询效率上B+ 树的效率是最高
Mysql 索引数据结构介绍:
目前 Mysql innodb 引擎使用 B+ 树 实现索引,每个树节点可以保存多个索引信息以及索引信息对应的下一个树节点地址值,叶子节点保存索引信息以及索引对应的数据并组成一个有序链表
聚集索引与非聚集索引介绍:
补充:使用 innodb 引擎如果没有指定主键索引,会使用唯一字段做主键索引,如果也没有唯一索引 innodb 引擎会自己维护一个rowid 做主键索引,一般在使用 innodb 引擎都会手动指定一个主键索引
聚集索引 和 非聚集索引 区别,虽然两者都使用B+树数据结构,但是聚集索引叶子节点存放的是完整数据,非聚集索引叶子节点存放指向存放完成数据对应的主键索引值,聚集索引一般指主键索引,普通索引一般都是非聚集索引,因为非聚集数据叶子节点没有完成数据,在非聚集索引查数据时可能会出现回表查询影响查询效率
Mysql 事务四大特性与隔离级别:
一个事务由一条或多条执行语句组成遵循四个特性,原子性、一致性、隔离性、持久性。
1. 原子性:一个事务内的所有执行语句,要么全部执行成功,要么全部执行失败
2. 一致性:事务执行前后数据一致
3. 隔离性:多个事务之间互不干扰
4. 持久性: 事务执行后数据交接后对数据改变是永久的
事务隔离级别介绍:
Mysql 事务有四种隔离级别 读未提交 、读已提交、可重复读、序列化 :
读未提交:会出现脏读问题,一个事务会读取到另一个事务修改但没有提交的脏数据
读已提交:解决了脏读问题,一个事务处理的数据没有提交之前,数据不会被其它事务读取到,但是事务提交后肯能会导致另一个事务执行内两次读取同一个数据,两次读取到的值不一致,出现了数据不可重复读问题
可重复读:一个事务在执行语句过程中,无法读取其它事务在当前事务数据提交前修改的数据 ,解决了数据不可重复读问题,但是会出现幻读问题,例如两个事务同时插入主键为1的数据 ,事务1已经提交数据,但是事务2无法获取事务1提交的数据,事务2插入数据多次插入数据失败像幻觉一样
序列化:在操作数据时会将数据存储到磁盘中,虽然可以解决 脏读、幻读、不可重复读所有问题,但是效率低
Mysql undo log 与 redo log 介绍:
在介绍 undo log 与 redo log 前先介绍一下 缓存池(buffer pool、数据页 (data page)
缓存池:在执行语句时,会先去寻找当前要操作的数据是否在缓存池中,如果缓存池中没有,先将磁盘中的数据加载到缓存池中,然后在操作缓存池中的数据
数据页: innodb 存储引擎在磁盘中管理数据最小单位,数据一行一行的保存在数据页中
redo log:数据恢复日志,执行语句操作数据在缓存池中进行,但是缓存池是内存空间,如果服务宕机内存中的数据会丢失不符合事务持久性, 使用 redo log 日志做数据恢复,在事务提交数据时先将信息记录到 redo log 日志中,即使服务宕机也可以根据 redo log 重新将数据恢复到磁盘中
undo log:数据回滚日志,在事务执行前会记录未操作的数据,如果事务执行失败根据 undo log 恢复之前的数据,undo log 保证事务的原子性和一致性
Mysql MVCC 实现原理:
MVCC (Multi-Version Concurrency Control ) 多版本并发控制,用于解决多事务读写冲突问题
MVCC 实现原理:MVCC 解决多事务读写冲突问题,主要依赖数据库记录中三个信息 隐藏字段、undo log 日志、readView(读视图).。
隐藏字段:数据表除了我们创建的字段还有隐藏字段 DB_TRX_ID 事务ID、DB_ROLL_PTR 数据回滚指针,(DB_ROW_ID row id 没有指定主键时 innodb 引擎使用它做主键 MVCC 用不到)
undo log 日志:记录执行操作前的数据日志
readView(读视图):读视图分为 当前读 与 快照读 两种方式
当前读:每次获取数据都要获取数据表中最新的数据,为了防止其它事务修改数据,获取数据时会加上锁,只有当前事务结束释放锁,其它事务才能获取修改数据
快照读:读取的是某一时刻的快照数据,获取数据时不关心其它事务是否修改数据
undo log 日志链知识补充:增删改操作数据修改之前,先创建 undo log 记录保存未修改的数据,将数据表隐藏字段的回滚指针(DB_ROLL_PTR)指向刚刚创建的 undo log 记录,如果数据提交失败根据回滚指针恢复原来的数据,多个事务修改同一个数据会创建多条 undo log 记录信息,并根据回滚指针字段(DB_ROLL_PTR)形成一个undo log 链表
了解上面的基础信息后一起看一下MVCC的工作原理:
这里我们用上面图中案例讲解一下,途中有四个线程同时开启,事务2将数据库中的age字段改为3,生成一个 undo log 记录表中回滚指针隐藏字段(DB_ROLL_PTR)指向 undo log 位置,随后事务3 和 事务4也都修改同一条数据,同时都会生成 undo log 日志,那我们看一下生成 undo log 日志链,如下
我们现在思考事务5两次数据查询查出来的数据都是什么样?回过来再说一下,MVCC 解决多事务读写冲突,依靠三个数据库记录信息,隐藏字段 undo log记录 readView读视,现在我们看一下读视图是怎么做控制事务读数据的
readView 中有以下几个属性以及获取数据的规则,m_ids:所有活动事务的 ID 集合,min_trx_id :最小活动事务 ID ,max_trx_id:最大活动事务 ID 加 1,creator_trx_id:当前获取数据的事务 id
获取数据规则:
undo log 记录中的隐藏字段 DB_TRX_ID
1. DB_TRX_ID == creator_trx_id 表示为同一个事务中修改的数据可以获取
2.DB_TRX_ID < min_trx_id 表示数据已经提交事务已经结束,undo log 数据可以获取
3.DB_TRX_ID > max_trx_id 表示事务在当前视图之后开启的,数据不能被获取
4.min_trx_id ≤ DB_TRX_ID ≤ max_trx_id 且 DB_TRX_ID 不在 m_ids 活动事务集合中,表示当前事务已经提交了,还在活动的事务数据都为脏数据不能获取
由上图 readView 读视图规则与 undo log 日志中的 DB_TRX_ID 对比,可以看出事务5第一次获取的是事务2已提交数据,第二次获取的数据是事务3提交的数据
以上是在事务隔离级别为 读已提交 环境下
如果是 可重复读 事务隔离级别,readView 只会在第一个获取数据位置生成,两次获取数据使用一个readView 视图所以,两次获取的数据都是事务2提交的数据