【无标题】

本文详细阐述了MySQL数据库中的关键概念,包括redo_log和binlog的区别,事务隔离级别、MVCC机制,索引优化策略,以及InnoDB引擎的特性如行锁、死锁处理和OnlineDDL技术。
摘要由CSDN通过智能技术生成

更新语句, 记录redolog 和binlog, redo_log采用两阶段提交,

redo_log:固定大小,写指针write_pos和检查点checkPoint, 写满刷盘

bin_log:是追加写, 没有大小限制,写满一个再写一个bin_log文件

undo_log: 记录每个操作的回滚操作,配合实现事务的一致性视图和事务回滚

slow_query_log: 记录慢sql日志, 通过配置超时时间

general_log: 记录所有日志,同步用于测试开发阶段, 不建议生产开启

mvcc 多版本并发控制(一条记录在系统存在多个版本,实际通过undolog回滚得到) 解决读提交和可重复读的视图问题

start transantion/begin 并不是事务的起点, 是在执行第一个操作innodb表的时候才真正启动

读提交,每次读都会生成一个新得视图,

可重复读:事务启动时保存一个活跃事务数组,通过数组和高水位(当前系统的最大事务maxId)组成一个视图 保证一致性读

可重复读的核心:  就是一致性读(consistent read);而事务更新数据的时候,只能用当前读。如果当前的记录的行锁被其他事务占用的话,就需要进入锁等待。

读未提交:直接返回记录上的最新值, 没有视图概念

串行化:直接用加锁的方式来避免并行访问

show variables like 'transaction_isolation' 查询事务隔离级别

show variables like '%binlog_format%' 查询binlog日志模式

start transaction with consistent snapshot 启动事务并创建视图

select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60 还未提交的长事务

更新语句和for update(悲观写锁) lock in share mode(乐观读锁) 都是读当前数据最新版本(当前读)

mysql> select k from t where id=1 lock in share mode;
mysql> select k from t where id=1 for update;

索引部分:

索引覆盖:建立联合索引,包含结果数据集,减少回表次数

最左原则:联合索引n个字段,或者字符串索引最左n个字符

索引下推:根据联合索引其他字段再次过滤,减少回表次数,5.6版本引入

索引的选择:优化器通过一些策略选择合适的索引

基于扫描行:show index from 某表 的区分基数cardinality(随机取n个数据页不同值的平均值x页数得出大概索引行数)

而数据表是会持续更新的,索引统计信息也不会固定不变。所以,当变更的数据行数超过 1/M 的时候,会自动触发重新做一次索引统计。如果在实践中,如果你发现 explain 的结果预估的 rows 值跟实际情况差距比较大, analyze table 某表 可以重置索引统计信息

在 MySQL 中,有两种存储索引统计的方式,可以通过设置参数 innodb_stats_persistent 的值来选择:

  1. 设置为 on 的时候,表示统计信息会持久化存储。这时,默认的 N 是 20,M 是 10。
  2. 设置为 off 的时候,表示统计信息只存储在内存中。这时,默认的 N 是 8,M 是 16

在考虑索引扫描行的时候,还要考虑普通索引的回表成本,排序成本等,如果索引选择错误时,可以考虑force index(indexName) 强制告诉优化器走这个索引,或者在语句上变化一些引导优化器走某个索引

字符串索引

  1. 直接创建完整索引,这样可能比较占用空间;
  2. 创建前缀索引,节省空间,但会增加查询扫描次数,并且不能使用覆盖索引;
  3. 倒序存储,再创建前缀索引,用于绕过字符串本身前缀的区分度不够的问题;
  4. 创建 hash 字段索引,查询性能稳定,有额外的存储和计算消耗,跟第三种方式一样,都不支持范围扫描。

锁:

全局锁:对整个数据库实例加锁, 

   Flush tables with read lock (FTWRL)全局读锁, 让整个库处于只读状态,阻塞所有dml和ddl,主要用于全局逻辑备份,主要用作不支持一致性读的存储引擎,而innodb备份时,会在可重复读的级别下,开启一个事务一致性视图,不需要FTWRL

为什么不用set global readonly=true 的方式 让全库处于只读状态?
  1.  一些系统会用readonly值来判断一个库是主库还是从库,修改该变量的影响面比较大
  2. 客户端发生异常断开之后,FTWRL方式会释放全局锁, 而将整个库设置为readonly会一直保持只读状态

表级锁:一种是表锁,一直是元数据锁(meta data lock MDL)

表锁:lock tables ... read/write , 需要主动释放锁unlock tables 通FTWR一样
MDL(metadata lock元数据锁,默认开启 5.5版本引入):

       为保证读写的正确性, 当对一个表做增删改查操作的时候,加 MDL 读锁;当要对表做结构变更操作的时候,加 MDL 写锁。读锁跟写锁互斥,不管是dml语句还是dql语句都会跟ddl语句冲突,

所以尽量选择访问低峰期做ddl操作,如果当前存在长事务可以先暂停ddl,或者kill掉这长事务
ddl需要扫描全表, 特别是大表耗时比较长,小表如果是热点数据,查询频繁且带有重试机制容易造成线程打满,获取MDL写锁耗时比较长,同时会阻塞后面的所有MDL读锁,

比较理想的机制是alter table 语句里面设置等待时间

ALTER TABLE tbl_name NOWAIT add column ...
ALTER TABLE tbl_name WAIT N add column ... 

mysql可以使用 innodb_lock_wait_timeout参数来设置ddl语句的等待时间

了解下online ddl 5.6版本支持 MySQL :: MySQL 8.0 Reference Manual :: 15.12.1 Online DDL Operations

行锁:存储引擎层实现,innodb支持

两阶段锁协议: 在Innodb事务中,行锁是在需要的时候才加上的, 但不是不需要就立即释放,需要提交这个事务时才释放

将可能造成锁冲突,影响并发度操作放到事务的最后面执行

死锁:多个线程持在持有对方等待资源同时也在等待对方资源释放,出现循环资源依赖导致线程进入无线等待

出现死锁后可以采取的策略:

  1.  通过超时时间:innodb_lock_wait_timeout(默认50s) 超时则不再等待资源,退出
  2.  死锁检测 innodb_deadlock_detect=on 表示开启,发现死锁后主动回滚其中的一个事务,正常情况采用这个策略,缺点是每个新来被堵的线程都需要判断自己的加入会不会导致死锁,这是需要消耗cpu的, 如果是热点数据,死锁检查会导致性能问题

最好能通过业务层面减少死锁的冲突,

   1.控制相同资源的并发量(主要方向)

    2.比如可以将一行变成多行减少锁冲突的概率

 change_buffer: 记录更新操作,等下次访问该数据页的是再合并操作,对更新操作起加速作用,适合于写多读少,读操作不频繁的场景, 仅限对普通索引,唯一索引因为需要判重,所以io具体的数据页, 所以建议使用普通索引

redo log 主要节省的是随机写磁盘的 IO 消耗(转成顺序写),而 change buffer 主要节省的则是随机读磁盘的 IO 消耗。

db卡住的瞬间:需要将数据写入磁盘

当内存数据页跟磁盘数据页内容不一致的时候,我们称这个内存页为“脏页”。内存数据写入到磁盘后,内存和磁盘上的数据页的内容就一致了,称为“干净页”。

  1. redo_log写满了
  2. 缓存buffer_pool不够用了,需要lru淘汰最近最少使用的缓存数据页
  3. mysql正常关闭
  4. 服务空闲的时候

表空间:

重建表:alter table A engine=InnoDB 命令可以用来重建表空间

显然,花时间最多的步骤是往临时表插入数据的过程,如果在这个过程中,有新的数据要写入到表 A 的话,就会造成数据丢失。因此,在整个 DDL 过程中,表 A 中不能有更新。也就是说,这个 DDL 不是 Online 的。

而在 MySQL 5.6 版本开始引入的 Online DDL,对这个操作流程做了优化。我给你简单描述一下引入了 Online DDL 之后,重建表的流程:

  1. 建立一个临时文件,扫描表 A 主键的所有数据页;
  2. 用数据页中表 A 的记录生成 B+ 树,存储到临时文件中;
  3. 生成临时文件的过程中,将所有对 A 的操作记录在一个日志文件(row log)中,对应的是图中 state2 的状态;
  4. 临时文件生成后,将日志文件中的操作应用到临时文件,得到一个逻辑数据上与表 A 相同的数据文件,对应的就是图中 state3 的状态;
  5. 用临时文件替换表 A 的数据文件。


    Online DDL的过程是这样的:
    1. 拿MDL写锁
    2. 降级成MDL读锁
    3. 真正做DDL
    4. 升级成MDL写锁
    5. 释放MDL锁
    1、2、4、5如果没有锁冲突,执行时间非常短。第3步占用了DDL绝大部分时间,这期间这个表可以正常读写数据,是因此称为“online ”
  • 24
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值