news 2026/9/15 22:37:55

精通MySQL的Sql编写优化及索引优化,理解Sql执行流程,理解底层各类锁、索引和日志机制,MVCC与事务控制,可进行主备搭建,配置优化,异构数据同步。并熟悉ClickHouse和TDengine

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
精通MySQL的Sql编写优化及索引优化,理解Sql执行流程,理解底层各类锁、索引和日志机制,MVCC与事务控制,可进行主备搭建,配置优化,异构数据同步。并熟悉ClickHouse和TDengine

Sql执行流程


Server层
1.连接器,负责处理客户端的连接请求,分配一个线程来处理该连接,每个连接线程会创建一个会话(session),在这个会话中,客户端可以发送SQL语句进行增删改查等操作。
2.解析器,解析树,解析sql语法和含义
3.优化器,评估SQL语句不同的执行计划,并选择最优的执行计划,考虑哪些索引可用、哪种连接方法效率最高,以及如何最小化查询的成本。
4.执行器,调用存储引擎的API来操作数据,执行查询、更新、插入等操作。
存储层,存储引擎
1.InnoDB,acid事务
2.MyISAM,不支持事务和外键,但提供了表级锁定机制。存储空间效率高。
3.Memory,数据存储在内存中,读写速度极快。但数据会在服务器重启时丢失。
4.CSV,数据存储在CSV文件中,每个表对应一个CSV文件,数据交换方便(excel)

我拿最复杂的update举列,需要先查询到数据,在更新数据。
update table set name=A where id=1;
先到mysql的server层,过连接器,再过(查询缓存)若果开了的话,key/value类型的map,sql是key,更新表的某一行就会全清除。
再过词法分析器,分析sql语法,优化器选择索引,到执行器调用底层的存储引擎innodb。
所有的dml操作都是在bufferpool内存里面进行的。
1.先查询bufferpool内存里面是否存在id为1的记录,若无,则从磁盘根据索引查询,并且加载到内存。
2.若有则,记录这条记录原来的值,至undolog buffer 等待内核函数fsync调用,用于回滚。
3.更新内存的值,并且记录操作至redolog buffer,再将数据写入page cache,再调用内核函数fsync,顺序写入磁盘,标志为Prepare。
4.等待server引擎顺序写binlog,写完以后将redolog的Prepare改外commit,此时就可向客户端返回提交成功。
因为后台的io线程会以page页的方式,随机写入磁盘,也不怕mysql宕机,因为redolog可以重放,至于为什么需要预写redolog,因为mysql执行很多情况下操作了不同的表,都在不同的磁道上,而redolog顺序写非常快,等cpu不繁忙再进行处理,这和很多金融系统面对额外的突发流量,预写日志,后台处理策略一样。
此外这里还有一个redolog buffer写入磁盘的策略,默认是一条sql,写至page cache 再入磁盘,可以配置调整为一条sql写page cache,等待操作系统一秒一次的fsync函数,写入磁盘。这样只要操作系统不是突然没电,就算是数据库宕机了,也不会丢数据,压测update语句,可以提示10%的性能,有些评论,日志系统可以这么使用。
各类锁
锁都是逻辑上锁索引的,其次只要读读可以并行,写锁上了都不能读,mysql写锁上了可以读是因为有特别的mvcc机制。
1.全局锁
锁整个数据库,在数据库mysqldump备份的时候,所有写操作会阻塞,所以 mysqldump --singletransition 参数必加,会使用mvcc机制,保证读到数据快照,当然最好在备库进行数据备份。
2.表锁
锁住整张表,不能进行写操作,如update时候没有走索引,全表扫描,其他的写操作都进不来。
3.意向锁
某个表已经有行锁了,会在这个表上标一个标记,其他事务想要获取表锁就必须等待,用了这个标记就不用扫描全部记录判断是否有行锁了。
4.行锁
锁主了唯一索引,一行记录。
5.间隙锁、临键锁。
锁定一个范围,比如 update的时候 id>30,那就锁大于30的行,称为间隙锁,id>=30,30也会被包含进去,30这条记录就是临键锁。
这么多锁,实际在判断的时候,可以采用mysqlSHOW PROCESSLIST,查看,主要看Host看客户端连接的ip、State看sql执行的状态是否锁定、info就是具体的sql,就能排查是什么sql进行了长时间的占用操作,是否存在没走索引全表扫描的情况。
数据库只有两条记录,id=10,20,id自带主键索引。那么修改id=8的时候,此时这记录不存在,会锁定-无穷到存在的10这一区间无法新增或者修改,id=12,则会索引10-20这一区间,无法写。id>=10,则会把10带进去锁定10至正无穷。
日志机制
undolog,用于开启事务,没有提交的时候,直接回滚。
redo Log,用于数据库故障恢复,记录了数据文件物理级别的修改,那个page的地址的值修改了,顺序写。
binlog,记录了全部的sql执行日志,用于数据同步和恢复,有Statement,记录sql本身,存储比较小,但是类似now()函数在进行同步重放会不一致。
row(默认模式),记录数据行的变化,修改前后的值都会记录,存储比较大。
fixed,使用now()函数会记录成raw,否则记录Statement。要是接受日志格式不统一可以换成fixed。
slow query log,慢查询日志,分析慢查询。

事务传播行为
REQUIRED (默认): 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
REQUIRES_NEW:当你希望方法在一个全新的事务中运行时使用,即使它被另一个已经运行的事务方法调用。
spring 中采用TransactionManager实现,当开启事务时,将当前的连接信息放置Threadlocal,事务状态设置为new,调用数据库的begin,当遇到REQUIRES_NEW时,暂存当前的连接信息,后开启新事物防至Threadlocal,状态也设置为new,当代码结束遇到commit时,判断当前是否是new,new则提交,跳出当前事务,执行外层事务,同样也遇到new,执行提交,这样就分开进行事务控制了,要是require,则内部的状态为new 状态为false,内部的事务就和外部一起了。
隔离级别
读未提交:一个事务可以读取到另一个事务未提交的数据。脏读、不可重复读、幻读。
读已提交:一个事务只能读取到另一个事务已经提交的数据。.不可重复读、幻读。
可重复读:一个事务在执行期间读取到的数据始终保持一致。幻读。MySQL通过mvcc实现,默认。
串行化:所有事务必须按顺序依次执行。
脏读:事务A读取了事务B尚未提交的数据,如果事务B发生错误并执行了回滚操作,那么事务A读取到的数据就是脏数据。
不可重复读:在同一事务内,多次读取同一数据返回的结果有所不同。这通常是因为另一个并发事务在两次读取之间修改了该数据。一行数据。
幻读:当事务A按一定条件读取数据后,事务B在事务A再次读取之前插入了符合其查询条件的新数据,导致事务A再次读取时出现了“幻影”般的记录。结果集行数不同。
mysql通过了特别的mvcc机制,保证了事务开启后完全的读快照,直接解决了以上问题包括幻读,但是任就存在脏写的问题。
比如
原金额为0
A先到达、先开启,设置金额为20。
B后到达、后开启,查询原金额,在原金额的基础上,加2,后设置金额。
理论上应该是22。但是最终是2。因为mvcc机制,导致A事务设置的20还没提交,b事务就能读取到原来的0,之后A提交事务,设置为20,b也提交事务设置为2。
最终结果2
若串行化,则统一条数据连同时读写都会加锁,能解决。
但是一般在代码层面上加互斥锁,保证完全的先来先到,或者相加操作直接使用sql的set 去相加。
MVCC
简单说,使用undolog和readview,实现事务之间读读、写读并行,写写互斥。undolog版本控制,readview只能看到自己的事务版本数据。
id name txid unlogchain address
1 Y y1
begin
1 Y 1 y1
1 A 1 y1 a1
1 B 1 a1 a2
comit

begin
1 Y 2 y1
1 Y 2 y1
1 C 2 y1 c1
comit
Canal和DataX进行在线和离线场景异构数据迁移同步

业务场景,上线两个月,两亿条数据,平均查询分页查询一页记录需要6秒,太慢了,加上选的是机械硬盘。
mysql索引一二两层页表常驻内存。第三层叶子节点在硬盘。
字段类型用的long,8字节加上6字节的指针,每条记录按照0.5kb计算,三层b+树,
1200个叶子指针两层,16kb每页大小
最多存放1200120016*2就是4千4百万,两亿数据需要四层树。
二层到三层一次磁盘io,需要50ms,三层到四层又需要400ms,大打折扣。

1.上线一个jar,监听mysql的binlog发送至kafa,先不消费。
2.mysql分批次拉取历史数据发至mq。
3.下游消费者直接hash分区入库。两亿条数据跑了一天半。
4.等待一次性的任务处理完成后,打开binlog变化的消费者,做幂等性判断后入库。
5.k8s滚动升级,优雅停机,无缝切换,数据一条不丢,经过count查询。
6.若是更加关键业务,请二次对比log日志。

ClickHouse
v20.8
1.内存表,批量写入mergetree。
2.物化视图,聚合结果。
3.分区,多线程,分区并行查询结果。
4.列式存储,按照列存储,方便数据压缩和聚合查询。
同类型的有doris(多里斯)、startrocks。
TDengine
v2.8.1
1.类似ck,列式存储,按照tag可建立索引,进行分区,分区多线程并行查询。
2.按照时间时序把各个列分开存储。并且时间既有b+树索引,又有hash索引,范围和精确查找贼快。
3.结合其存储特性,不断地按照时序进行单列聚合运算效率很高。
我们的业务场景是根据应用id和apiid做tag进行分区,之后将所有的流量数据存入TDengine,设定好流式计算函数,按照一秒钟一次计算,自动将结果存入结果表。
如计算某一api,每秒钟的请求流量大小的和。
同类型的influxDB,因为集群收费,而且支持国产化。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 22:34:22

光伏电站泄流效应与配电网无功优化MATLAB实现

1. 项目背景与核心问题光伏电站并网运行时产生的泄流效应是影响配电网无功优化的关键因素之一。当光伏渗透率超过一定阈值时,传统以负荷为中心的无功补偿方案往往会导致节点电压越限、网损增加等问题。这个项目要解决的正是如何在IEEE 33节点系统中,建立…

作者头像 李华
网站建设 2026/9/15 22:32:24

Halcon芯片缺角检测:亚像素几何验证与产线稳定实践

1. 项目概述:为什么芯片缺角检测必须用 Halcon 而不是 OpenCV 或传统阈值法?在半导体封装产线的实际运行中,“检测、分选、固晶”这三个工序是环环相扣的硬性流水节拍。其中“缺角检测”看似只是图像识别中的一个子任务,但它的误判…

作者头像 李华
网站建设 2026/9/15 22:28:59

Open Agents 会话管理指南:如何创建、恢复与归档编码任务

Open Agents 会话管理指南:如何创建、恢复与归档编码任务 【免费下载链接】open-agents An open source template for building cloud agents. 项目地址: https://gitcode.com/GitHub_Trending/op/open-agents Open Agents 是一个开源的云编码智能体&#xf…

作者头像 李华