《MySQL45讲》读书笔记

重建表

alter table t engine = InnoDB(也就是recreate),而optimize table t 等于recreate+analyze,让表大小变小

重建表的执行流程

  • 建立一个临时文件,扫描表 t 主键的所有数据页;
  • 用数据页中表 t 的记录生成 B+ 树,存储到临时文件中;
  • 生成临时文件的过程中,将所有对 t 的操作记录在一个日志文件(row log)中;
  • 临时文件生成后,将日志文件中的操作应用到临时文件,得到一个逻辑数据上与表 t相同的数据文件;
  • 用临时文件替换表 t 的数据文件。

注意:在重建表的时候, InnoDB不会把整张表占满, 每个页留了1/16给后续的更新用。 也就是说, 其实重建表之后不是“最”紧凑的。

Online DDL

ALTER TABLE tbl_name ADD COLUMN col_name col_type, ALGORITHM=INPLACE, LOCK=NONE;

LOCK选项

  • SHARE:共享锁,执行DDL的表可以读,但是不可以写。
  • NONE:没有任何限制,执行DDL的表可读可写。
  • EXCLUSIVE:排它锁,执行DDL的表不可以读,也不可以写。
  • DEFAULT:默认值,也就是在DDL语句中不指定LOCK子句的时候使用的默认值。如果指定LOCK的值为DEFAULT,那就是交给MySQL子句去觉得锁还是不锁表。不建议使用,如果你确定你的DDL语句不会锁表,你可以不指定lock或者指定它的值为default,否则建议指定它的锁类型。
准备:
1、对表加元数据共享升级锁,并升级为排他锁;(此时DML不能并行)
2、判断使用inplace算法
3、判断语句是“rebuild table” 还是 “no-rebuild”,rebuild 在原表所在的路径下创建.frm和.ibd临时中转文件;
【在引擎层克隆,而不是像copy那样,在server层创建(create like)】注意:加列的操作是需要rebuild table的
【rebuild table】---生成中转文件表++++
no-rebuild的情况:
除创建二级索引外只创建.frm文件,其中添加二级索引操作最为特殊,该操作属于no-rebuild不会生成.ibd,
但实际上对.ibd文件却做了修改,该操作会在参数tmpdir指定路径下生成临时文件,用于存储索引排序结果,然后再合并到.ibd文件中
++++
4、申请row log空间,用于存放DDL执行阶段产生的DML操作。(no-rebuild不需要)【在innodb_sort_buffer块中】执行:(online)
1、释放排他锁,保留元数据共享升级锁;(此时DML可以并行)
2、扫描原表主键以及二级索引的所有数据页,生成 B+ 树,存储到临时文件中;【在引擎层扫描,最耗时】
3、将所有对原表的DML操作记录在日志文件row log中,并回放部分row_log。提交阶段:
1、升级元数据共享升级锁,产生排他锁锁表;(此时DML不能并行了)
2、重做row log中的内容;(no-rebuild不需要)
3、重命名原表文件,将临时文件改名为原表文件名,删除原表文件;
4、提交事务,变更完成。


在 InnoDB 引擎中 count(*)、count(1)、count(主键)、count(字段) 哪个性能最高?

count(字段)<count(主键 id)<count(1)≈count(*) 题目解析:

  • 对于 count(主键 id) 来说,InnoDB 引擎会遍历整张表,把每一行的 id 值都取出来,返回给 server 层。server 层拿到 id 后,判断是不可能为空的,就按行累加。
  • 对于 count(1) 来说,InnoDB 引擎遍历整张表,但不取值。server 层对于返回的每一行,放一个数字“1”进去,判断是不可能为空的,按行累加。
  • 对于 count(字段) 来说,如果这个“字段”是定义为 not null 的话,一行行地从记录里面读出这个字段,判断不能为 null,按行累加;如果这个“字段”定义允许为 null,那么执行的时候,判断到有可能是 null,还要把值取出来再判断一下,不是 null 才累加。
  • 对于 count(*) 来说,并不会把全部字段取出来,而是专门做了优化,不取值,直接按行累加。

所以最后得出的结果是:count(字段)<count(主键 id)<count(1)≈count(*)。

–single-transaction逻辑备份

当mysqldump使用参数–single-transaction的时候, 导数据之前就会启动一个事务, 来确保拿到一致性视图。

single-transaction方法只适用于所有的表使用事务引擎的库。 如果有的表使用了不支持事务的引擎, 那么备份就只能通过FTWRL(全局锁)方法。

这往往是DBA要求业务开发人员使用InnoDB替代MyISAM的原因之一。

当备库用–single-transaction做逻辑备份的时候, 如果从主库的binlog传来一个DDL语句会怎么样?

Q1:SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Q2:START TRANSACTION WITH CONSISTENT SNAPSHOT;
/* other tables */
Q3:SAVEPOINT sp;
/* 时刻 1 */
Q4:show create table `t1`;
/* 时刻 2 */
Q5:SELECT * FROM `t1`;
/* 时刻 3 */
Q6:ROLLBACK TO SAVEPOINT sp;
/* 时刻 4 */
/* other tables */

1. 如果在Q4语句执行之前到达, 现象: 没有影响, 备份拿到的是DDL后的表结构。

2. 如果在“时刻 2”到达, 则表结构被改过, Q5执行的时候, 报 Table definition has changed,please retrytransaction, 现象: mysqldump终止;

3. 如果在“时刻2”和“时刻3”之间到达, mysqldump占着t1的MDL读锁, binlog被阻塞, 现象:主从延迟, 直到Q6执行完成。

4. 从“时刻4”开始, mysqldump释放了MDL读锁, 现象: 没有影响, 备份拿到的是DDL前的表结构。

删除一个表里面的前10000行数据

要删除一个表里面的前10000行数据, 有以下三种方法可以做到:

第一种, 直接执行delete from Tlimit 10000;

第二种, 在一个连接中循环执行20次 delete from Tlimit 500;

第三种, 在20个连接中同时执行delete from Tlimit 500。

分析:

第一种方式(即: 直接执行delete from Tlimit 10000) 里面, 单个语句占用时间长, 锁的时间也比较长; 而且大事务还会导致主从延迟。

第二种方式是相对较好的。

第三种方式(即: 在20个连接中同时执行delete from Tlimit 500) , 会人为造成锁冲突。

change buffer

当需要更新一个数据页时, 如果数据页在内存中就直接更新, 而如果这个数据页还没有在内存中的话, 在不影响数据一致性的前提下, InooDB会将这些更新操作缓存在change buffer中, 这样就不需要从磁盘中读入这个数据页了。 在下次查询需要访问这个数据页的时候, 将数据页读入内存, 然后执行change buffer中与这个页有关的操作。 通过这种方式就能保证这个数据逻辑的正确性。将change buffer中的操作应用到原数据页, 得到最新结果的过程称为merge。 除了访问这个数据页会触发merge外, 系统有后台线程会定期merge。 在数据库正常关闭(shutdown) 的过程中,也会执行merge操作。对于唯一索引来说, 所有的更新操作都要先判断这个操作是否违反唯一性约束。 比如, 要插入(4,400)这个记录, 就要先判断现在表中是否已经存在k=4的记录, 而这必须要将数据页读入内存才能判断。 如果都已经读入到内存了, 那直接更新内存会更快, 就没必要使用change buffer了。

因此, 唯一索引的更新就不能使用change buffer, 实际上也只有普通索引可以使用。change buffer用的是buffer pool里的内存, 因此不能无限增大。 change buffer的大小, 可以通

过参数innodb_change_buffer_max_size来动态设置。 这个参数设置为50的时候, 表示changebuffer的大小最多只能占用buffer pool的50%。将数据从磁盘读入内存涉及随机IO的访问, 是数据库里面成本最高的操作之一。 change buffer因为减少了随机磁盘访问, 所以对更新性能的提升是会很明显的。

merge的执行流程是这样的:

1. 从磁盘读入数据页到内存(老版本的数据页) ;

2. 从change buffer里找出这个数据页的change buffer 记录(可能有多个) , 依次应用, 得到新版数据页;

3. 写redo log。 这个redo log包含了数据的变更和change buffer的变更。

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

字符集不同连表查询用不上索引

performance_schema库优化

MySQL 5.6版本以后提供的performance_schema库, 就在file_summary_by_event_name

表里统计了每次IO请求的时间

Buffer Pool

Buffer Pool对查询的加速效果, 依赖于一个重要的指标, 即: 内存命中率。

你可以在show engine innodb status结果中, 查看一个系统当前的BP命中率。 一般情况下, 一个稳定服务的线上系统, 要保证响应时间符合要求的话, 内存命中率要在99%以上。

执行show engine innodb status , 可以看到“Buffer pool hit rate”字样, 显示的就是当前的命中率。

InnoDB Buffer Pool的大小是由参数 innodb_buffer_pool_size确定的, 一般建议设置成可用物理内存的60%~80%。

所以, innodb_buffer_pool_size小于磁盘的数据量是很常见的。 如果一个 Buffer Pool满了, 而又要从磁盘读入一个数据页, 那肯定是要淘汰一个旧数据页的。

InnoDB管理Buffer Pool的LRU算法, 是用链表来实现的。

1. 在图的状态1里, 链表头部是P1, 表示P1是最近刚刚被访问过的数据页; 假设内存里只能放下这么多数据页;

2. 这时候有一个读请求访问P3, 因此变成状态2, P3被移到最前面;

3. 状态3表示, 这次访问的数据页是不存在于链表中的, 所以需要在Buffer Pool中新申请一个

数据页Px, 加到链表头部。 但是由于内存已经满了, 不能申请新的内存。 于是, 会清空链表

末尾Pm这个数据页的内存, 存入Px的内容, 然后放到链表头部。

4. 从效果上看, 就是最久没有被访问的数据页Pm, 被淘汰了。

实际上, InnoDB对LRU算法做了改进

在InnoDB实现上, 按照5:3的比例把整个LRU链表分成了young区域和old区域。 图中LRU_old指向的就是old区域的第一个位置, 是整个链表的5/8处。 也就是说, 靠近链表头部的5/8是young区域, 靠近链表尾部的3/8是old区域。改进后的LRU算法执行流程变成了下面这样。

1. 图7中状态1, 要访问数据页P3, 由于P3在young区域, 因此和优化前的LRU算法一样, 将其移到链表头部, 变成状态2。

2. 之后要访问一个新的不存在于当前链表的数据页, 这时候依然是淘汰掉数据页Pm, 但是新插入的数据页Px, 是放在LRU_old处。

3. 处于old区域的数据页, 每次被访问的时候都要做下面这个判断:

若这个数据页在LRU链表中存在的时间超过了1秒, 就把它移动到链表头部;

如果这个数据页在LRU链表中存在的时间短于1秒, 位置保持不变。 1秒这个时间, 是由参数innodb_old_blocks_time控制的。 其默认值是1000, 单位毫秒。

MySQL采用的是边算边发的逻辑, 因此对于数据量很大的查询结果来说, 不会在server端保存完整的结果集。 所以, 如果客户端读结果不及时, 会堵住MySQL的查询过程, 但是不会把内

存打爆。而对于InnoDB引擎内部, 由于有淘汰策略, 大查询也不会导致内存暴涨。 并且, 由于InnoDB对LRU算法做了改进, 冷数据的全表扫描, 对Buffer Pool的影响也能做到可控。

InnoDB对Bufffer Pool的LRU算法做了优化,

即: 第一次从磁盘读入内存的数据页, 会先放在old区域。 如果1秒之后这个数据页不再被访问了, 就不会被移动到LRU链表头部, 这样对Buffer Pool的命中率影响就不大。

但是, 如果一个使用BNL算法的join语句(无索引join,参考https://www.cnblogs.com/booksea/p/17380941.html), 多次扫描一个冷表, 而且这个语句执行时间超过1秒,就会在再次扫描冷表的时候, 把冷表的数据页移到LRU链表头部。

这种情况对应的, 是冷表的数据量小于整个Buffer Pool的3/8, 能够完全放入old区域的情况。如果这个冷表很大, 就会出现另外一种情况: 业务正常访问的数据页, 没有机会进入young区

域。由于优化机制的存在, 一个正常访问的数据页, 要进入young区域, 需要隔1秒后再次被访问到。 但是, 由于我们的join语句在循环读磁盘和淘汰内存页, 进入old区域的数据页, 很可能在1秒之内就被淘汰了。 这样, 就会导致这个MySQL实例的Buffer Pool在这段时间内, young区域的数据页没有被合理地淘汰。也就是说, 这两种情况都会影响Buffer Pool的正常运作。

大表join操作虽然对IO有影响, 但是在语句执行结束后, 对IO的影响也就结束了。 但是,对Buffer Pool的影响就是持续性的, 需要依靠后续的查询请求慢慢恢复内存命中率。

判断要不要使用join语句时, 就是看explain结果里面, Extra字段里面有没有出现“BlockNested Loop”字样。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/6665.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mac通过termius连接Linux服务器

mac上安装 linux系统 如果有 linux服务器账号密码&#xff0c;那么上一步可忽略&#xff1b; 比如&#xff1a;直接连接阿里云或腾讯云账号 1. 安装termius 链接: https://pan.baidu.com/s/1iYsZPZThPizxqtkLPT89-Q?pwdbw6j 提取码: bw6j 官网 Termius - SSH platform for …

【C++】STL — vector的接口讲解 +详细模拟实现

前言: 本章我们将学习STL中另一个重要的类模板vector… vector是表示可变大小数组的序列容器。就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。但是又不像数组&#xff0c;它的大小是可以动态改变的本质讲&#xff0c;vector使用动态分配数组来存储它的元素v…

配电室智能巡检机器人

近年来&#xff0c;生产过程高度自动化&#xff0c;各工矿企业关键场所需定期巡检维护。但目前巡检主要靠人工&#xff0c;既耗时费力效率又低&#xff0c;且受环境等因素影响&#xff0c;巡检难以全面规范&#xff0c;隐患或问题易被忽视。在此情况下&#xff0c;如何利用现有…

ElasticSearch02(DSL查询文档,DSL处理结果,RestClient查询,旅游案例,数据聚合)【全详解】

目录 一、DSL查询文档 1. 说明 2. 文本检索 3. 精确查询 4. 地理坐标查询 5. 复合查询 6. 课堂演示 7. 小结 二、DSL处理结果 1. 排序 2. 分页 3. 高亮 4. 课堂演示 5. 小结 三、RestClient查询 1.快速入门 2.match查询 3.精确查询 4.布尔查询 5. 算分函数…

锁相环原理解析

在计算机和嵌入式系统中&#xff0c;常常要用锁相环来倍频&#xff0c;那么&#xff0c;锁相环是如何倍频的&#xff0c;其原理又是什么呢&#xff1f; 目录 1. 锁相环基本概念与构成1.1 鉴相器1.2 低通滤波器1.3 压控振荡器 2. 锁相环如何实现倍频3. 锁相环也会失效&#xff…

【前端学习——正则】

https://www.bilibili.com/video/BV1da4y1p7iZ/?spm_id_from333.337.search-card.all.click&vd_source5cef5968d539682b683e7d01b00ad01b 学习网站 https://github.com/ziishaned/learn-regex/blob/master/translations/README-cn.md

Bookends for Mac:文献管理工具

Bookends for Mac&#xff0c;一款专为学术、研究和写作领域设计的文献管理工具&#xff0c;以其强大而高效的功能深受用户喜爱。这款软件支持多种文件格式&#xff0c;如PDF、DOC、RTF等&#xff0c;能够自动提取文献的关键信息&#xff0c;如作者、标题、出版社等&#xff0c…

在M1芯片安装鸿蒙闪退解决方法

在M1芯片安装鸿蒙闪退解决方法 前言下载鸿蒙系统安装完成后&#xff0c;在M1 Macos14上打开闪退解决办法接下来就是按照提示一步一步安装。 前言 重新安装macos系统后&#xff0c;再次下载鸿蒙开发软件&#xff0c;竟然发现打不开。 下载鸿蒙系统 下载地址&#xff1a;http…

MATLAB实现遗传算法优化第三类生产线平衡问题

第三类生产线平衡问题的数学模型 假设&#xff1a; 工作站数量&#xff08;m&#xff09;和生产线节拍&#xff08;CT&#xff09;是预设并固定的。每个任务&#xff08;或作业元素&#xff09;只能分配到一个工作站中。任务的执行顺序是预先确定的&#xff0c;且不可更改。每…

PHP医疗不良事件上报系统源码 AEMS开发工具vscode+ laravel8 医院安全(不良)事件报告系统源码 可提供演示

PHP医疗不良事件上报系统源码 AEMS开发工具vscode laravel8 医院安全&#xff08;不良&#xff09;事件报告系统源码 可提供演示 医院安全不良事件报告系统&#xff08;AEMS&#xff09;&#xff1b;分为外部报告系统和内部报告系统两类。内部报告系统主要以个人为报告单位&…

Docker私有镜像仓库搭建 带图形化界面的

搭建镜像仓库可以基于Docker官方提供的DockerRegistry来实现。 官网地址&#xff1a;https://hub.docker.com/_/registry 先配置私服的信任地址: # 打开要修改的文件 vi /etc/docker/daemon.json # 添加内容&#xff1a; "insecure-registries":["http://192.…

暴力匹配字符串的升级版算法 —— Kmp算法

文章目录 一、Kmp算法是什么&#xff1f;二、算法分析1.构建next数组2.匹配主串 三、完整代码 一、Kmp算法是什么&#xff1f; 简单来说&#xff0c;KMP&#xff08;Knuth-Morris-Pratt&#xff09;算法主要用于解决字符串匹配问题。也就是当你有一个主串&#xff08;text&…

OceanBase 轻量级数仓关键技术解读

码到三十五 &#xff1a; 个人主页 为了更好地聚合和治理跨域数据&#xff0c;帮助企业用较低的成本快速聚合分析&#xff0c;快速决策&#xff0c;不断的让企业积累的数据产生价值&#xff0c;从全域海量数据抓取&#xff0c;高性能流批处理&#xff0c;元数据血缘治理等等方面…

AI-数学-高中52-离散型随机变量概念及其分布列、两点分布

原作者视频&#xff1a;【随机变量】【一数辞典】2离散型随机变量及其分布列_哔哩哔哩_bilibili 离散型随机变量分布列&#xff1a;X表示离散型随机变量可能在取值&#xff0c;P:对应分布在概率&#xff0c;P括号里X1表示事件的名称。 示例&#xff1a;

QT:QT窗口(一)

文章目录 菜单栏创建菜单栏在菜单栏中添加菜单创建菜单项添加分割线 工具栏创建工具栏设置停靠位置创建工具栏的同时指定停靠位置使用QToolBar类提供的setAllowedAreas函数来设置停靠位置 设置浮动属性设置移动属性 状态栏状态栏的创建在状态栏中显示实时消息在状态栏中显示永久…

AI人才争夺战,华尔街入局:豪掷百万美元年薪抢人

继硅谷之后&#xff0c;华尔街也入局**“AI人才争夺大战”**。 他们的目标非常明确——抢的就是高精尖的AI专家。 △图源&#xff1a;Business Insider 现在这条“街”上&#xff0c;不论是银行、对冲基金还是私募股权公司都已纷纷下场&#xff0c;可谓是豪掷千金&#xff0c…

选择深度学习框架:TensorFlow 2 vs PyTorch

TensorFlow 2 vs PyTorch 选择深度学习框架&#xff1a;TensorFlow 2 vs PyTorchTensorFlow 2概述TensorFlow 2的优点TensorFlow 2的缺点 PyTorch概述PyTorch的优点PyTorch的缺点 选择建议对于选择困难症的人&#xff0c;我给你们的答案——PyTorch选择理由&#xff1a;结论&am…

【LinuxC语言】setitimer与getitimer函数

文章目录 前言一、setitimer() 函数二、getitimer() 函数三、示例代码总结 前言 在Linux系统下&#xff0c;编写程序时经常需要使用定时器来实现一些定时任务、超时处理等功能。setitimer() 和 getitimer() 函数是两个用于操作定时器的重要函数。它们可以帮助我们设置定时器的…

[华为OD]C卷 给定一个数组,数组中的每个元素代表该位置的海拔高度 山脉的个数 200

题目&#xff1a; 给定一个数组&#xff0c;数组中的每个元素代表该位置的海拔高度。0表示平地&#xff0c;&#xff1e;1时表示属于某个 山峰&#xff0c;山峰的定义为当某个位置的左右海拔均小于自己的海拔时&#xff0c;该位置为山峰。数组起始位 置计算时可只满足一边…