Mysql学习笔记归档

40 阅读6分钟

知识点总结

索引

MVCC机制

日志

sql优化经验

场景1:慢sql报警

场景1:按更新时间查询公司数据的一个业务,然后下游有一个服务,定时任务每天中午十二点调这个接口刷全量的数据,然后这个服务每天12点半就开始报警,开始爆大量的慢sql,这个慢sql多到一定程度之后会影响到数据库的性能。

解决:本质上是一个深分页的问题,越往后面查询越慢,mysql还会从第一页一直扫到这一页。这个问题没办法去建立索引或者改索引去解决。我们本身更新时间上也会有索引。我是这样解决的,本身下游服务的目的去刷全量的数据,我改了一下,让它去传一个id过来,id是公司的主键,而且这个主键是自增的,你第一次传的时候就传0,然后第二次传的时候就传我返回给你的最大的id。然后我每次给你查询返回500条数据。只不过我有一个逻辑判断,我只会返回大于你传过来id的500条数据。我把分页查询转换为范围查询,解决了慢sql的问题

场景2:大数据量查询

场景2:还有特别大的数据量的时候,查询特别慢,而且当时这个特别老的服务,我们就想以最小的改动获取最大的收益。

解决:我们知道mysql的10亿条数据,一定是一个四层的B+树,相比于三层B+树只多了一次随机IO读取。我做个实验多一次随机IO其实不会对查询时间造成多大影响,所以这个问题主要不是这个造成的,后面我想当mysql不是有一层缓冲区嘛,缓存着上一次读取的页在内存中,第一次查询的数据会放到bufferPool中,第二次查询如果缓存命中就直接取出,所以当时是把缓冲区几百个兆的改为几个g的就解决了

优化思路

插入优化:批量插入,手动提交事务,load指令将文件一次性插入到mysql

update优化: update后面where的条件字段+索引,否则会从行锁升级为表锁

主键优化: 顺序插入,否则页分裂,减少主键长度,因为二级索引存放主键

order by和group by优化: 将要排序的字段+索引

Limit深分页优化: 覆盖索引+子查询优化

count用法: count(*)底层优化了,服务器直接累加

联表优化: 小表驱动大表

死锁排查

场景:莫名随机死锁

场景1:下游消费的服务调用组内一个数据接口服务频繁报SQL死锁异常,导致功能修改丢失,造成规模范围内数据异常。

根据日志信息关键词定位为一条sql的死锁问题

我们有一个业务,无法判断它是插入还是更新,所以我们这边的实现是使用insertorupdate来交给数据库来判断执行,然后在高并发情况下会出现死锁的问题

排查:我当时是在服务器上登录mysql,手动提交事务去复现了一下场景,发现事务3自动释放显示发生了死锁。所以我当时去查看这个第一个事务加了什么锁。

自己的建表图:

添加模拟数据:

表锁(意向锁):这个很好理解,我们在插入或者更新的时候肯定是不希望这种DDL语句来影响的,因为这个操作很可以影响事务的执行,所以这把锁的目的是为了阻塞DDL的那些操作

间隙锁:我看它加了两把,这个主要是为了维护索引的那一段范围,是为了防止同时有其他的在这一段间隙里面去插入的事务操作

然后去看第二个事务为什么死锁:去查看这条语句加了什么锁:

间隙锁:它是加了间隙锁,但是这个间隙锁有一个类型,很有意思,是插入意向锁,是和第一个事务的插入的间隙锁有冲突了,事务2加了间隙锁想要插入但是事务1已经加了间隙锁了,所以这个插入意向锁是告诉事务2不要进行插入,要等着事务1完成

然后我去看第三个事务,和事务2一样,也是插入意向锁

现在捋一下,就是事务2等事务1,然后事务3等事务2或者事务1,没有形成闭环

然后我把事务1提交之后,事务2按说就可以执行了,但我们知道在每次insert之前都会去检测有没有其他事务插入的锁,事务2发现事务3也在gap,也就是加了间隙锁,所以事务2的一把间隙锁又被waitting掉了,就是去等待事务3完成,然后事务三没有加锁,也就是事务3也在等事务2的gap,所以形成了死锁

事务1:

事务2:

事务3:

事务1提交,死锁出现:

解决:异常判断

直接insert然后去try catch一下,如果异常是dumplicatekey(唯一性约束)就是update,然后执行update操作

场景2:死锁

集群实现

读写分离模式

原有的基础上增加中间层,与后端数据集构成读写分离的集群。

整体基础结构:原有的主库派生出字库1,字库2, 利用mysql原有的主从同步机制(即为:binlog日志同步),将主库的数据变化在从库中复现,保证数据同步。

主库一般用于写入处理, 从库负责读取。

细节:如果直接面对主库进行操作无法完成读写分离,需要在前端分配分片中间件(阿里mycat,京东ShardingSphere), 该中间件通过curd请求,来决定由哪个库处理。MHA中间件实现高可用(即:主服务器坏了,MHA中间件可以将某个从表提升为主服务器)。 所有节点数据均保持同步。适用于读多写少,单表不过千万的互联网应用。

分库分表(分片)集群模式

一个mysql数据库撑不住的情况下。将数据库的数据分到不同的节点数据库(即:节点数据库的数据合起来为完整的数据体)。 需要用到中间件进行路由。(对sql进行解析,将请求发到对应的数据库,分发请求的过程叫路由)。不具备高可用性。

主流模式:读写分离和分片的组合运用

分片算法: 1.范围法,对主键(即为分片键进行划分。如id),mysql默认提供的特性(分区表为典型的范围法),易扩展,适用范围检索,但数据不均匀,局部负载大,适用流水账应用。 2.HASH法,对id取模。取模和一致性Hash(独特的环形算法)。数据分布均匀。扩展复杂,数据迁移大。建议提前部署。