Fork me on GitHub

高性能mysql知识点

tim-van-der-kuip-1398896-unsplash

高性能mysql

事务相关

事务的含义

事务就是一组原子性的SQL查询。事务必须满足ACID特性。

  1. 原子性 atomicity
    事务全部提交成功,或者全部回滚 一个事务不能执行一部分
  2. 一致性 consistency
    数据库从一个状态转换到另一个状态,不会存在中间状态 在事务执行期间系统崩溃了,事务能回滚,数据不会丢失
  3. 隔离性 isolation
    一个事务所做的操作在没有提交之前对其他的事务都是不可见的。隔离性有4个等级。
  4. 持久性
    事务一旦提交,会永久保存在磁盘中,即使系统崩溃,修改的数据也不会丢失。

事务的隔离级别

  1. 未提交读 READ UNCOMMITTED
    事务中修改的内容在没有提交时其他事务就能看见,称为脏读。
  2. 提交读 READ COMMITTED
    事务在提交了才能被读取,其他的事务修改行会加锁。又称为不可重复读。
  3. 可重复读 REPEATABLE READ
    可重复读解决了脏读的问题,该级别保证了在一个事务中多次读取同样的记录结果是一致的。但是无法解决幻读的问题。
    幻读指的是事务在读取一个范围的记录时,另外的事务又在该范围内插入新的数据,之前的事务再次读取范围记录时,出现幻行。
    MYSQL采用了MVCC多版本控制和间隙锁解决了幻读的问题。在快照读时采用的是MVCC既可以解决幻读。在当前读时读取的是最新的数据,采用的是间隙锁来解决。
  4. 串行化
    多个事务串行运行 效率较低

MYSQL的加锁机制

InnoDB采用的是二阶段锁定协议 在事务的执行过程中,随之都会执行锁定记录。锁只有在提交事务或者回滚ROLLBACK才会释放。并且所有的锁都是同时释放的。

事务的死锁

多个事务在统一资源上相互占用,并请求对方的占用的资源,从而导致恶性循环的现象。多个事务采用不同的顺序锁定资源时就可能会产生死锁。

解决办法InnoDB的方法是将持有最少行级锁的事务进行回滚。 事务在update,insert,delete时候会加锁。

事务日志

采用事务日志可以提高效率。在使用事务日志,修改表时先修改内存中的数据(加锁),再将该修改行为记录到持久在硬盘中的事务日志中。而不用每次都修改磁盘中的数据,提高速度。 事务日志采用追加的方式,(因为写日志只要修改某个文件,而修改mysql记录需要寻找每条记录的位置,效率低),事务持久化后再将内存的数据慢慢同步到磁盘中。如果数据没有写回到磁盘,那系统奔溃,重启后自动恢复这部分的修改。

redo日志和undo日志

事务日志包括重做日志redo日志和回滚undo日志, redo日志存储最新的值,undo日志存储的是老的值,是数据的快照。
undo指的是已经全部完成的事务,就是commit的事务。redo记录的是完成并且部分写入磁盘的已经提交的事务,记录在共享表空间中。
一般情况下,mysql奔溃后重启服务,InnoDB通过回滚日志undo将所有已经写入磁盘的未完成的日志回滚,并重新执行redo日志的事务即可恢复数据。但是如果redo的量增加,全部执行redo需要很多时间,则引入了checkpoint机制。
即先将数据回滚到undo里面的初始值,如果redo事务提交了,就重新执行redo的日志,否则执行到事务提交之前
undo+redo事务的简化过程

1
2
3
4
5
6
7
8
9
10
假设有A、B两个数据,值分别为1,2.
A.事务开始.
B.记录A=1到undo log.
C.修改A=3.
D.记录A=3到redo log.
E.记录B=2到undo log.
F.修改B=4.
G.记录B=4到redo log.
H.将redo log写入磁盘。
I.事务提交

事务管理机制

  • 脏页
    当业务需要对某张表格的数据修改时候,innodb会先将数据从磁盘中读取到内存中,然后在缓存中修改数据,这时候缓存中的数据就称为dirty数据,要将脏页统一刷新到磁盘中。
    checkpoint 在某个时间点,将脏页的数据刷新到磁盘中,系统将这个刷新的时间点记录到redo log的结尾位置,进行数据恢复时候,checkpoint之前的数据不需要进行恢复
  • 管理机制
    事务会先修改内存中的数据,InnoDB事务日志有4个步骤
    创建阶段
    事务先创建一条日志
    日志刷盘:日志将会写入磁盘中的日志文件
    数据刷盘:将脏页的数据写入到磁盘中数据文件
    写checkpoint:将数据刷盘的点的信息记录到redo日志中,下次从这里开始恢复
    D92E74CF-1BB8-4370-B18A-4E15262128EB

    多版本并发控制(MVCC)

MVCC在很多时候避免了加锁,主要是实现了非阻塞的读操作,写操作也只是锁定必要的行。MVCC和concurrentHashMap有些类似,采用非阻塞的读取操作,写操作只是锁定必要的行。InnoDB是加行级锁。

InnoDB的MVCC通过在每个行后面记录两个隐藏的列来实现 不是存储实际的时间至

  1. 保存行的创建时间(系统版本号)
  2. 行的过期时间(系统版本号)

如何实现MVCC

SELECT操作

  • 行的系统版号小于等于当前的系统版本号,保证数据行是系统事务开始前存在或者是当前事务修改或者插入的
  • 行的删除版本未定义,或者大于当前版本号的数据行。因为之后的事务删除的行记录也要被选到。保证读取到的行在事务开始前未被删除。

INSERT操作
当前的的事务版本号最为新插入行的行版本号。

DELETE操作
保存当前的事务版本号作为被删除行的行删除版本号。

UPDATE操作
插入一行新数据,当前的事务版本号作为行版本号,并将原来的行的删除版本号设为当前的系统版本号。使原来的行无法被select到,而新插入的行能被选到。

MVCC加锁机制

在MVCC并发控制中,读操作可以分成2类,

  • 快照读
    快照读是读取记录的可见版本(就是事务开始前的快照,后面的事务的操作不会影响),不用加锁。
    简单的select操作,属于快照读,不加锁。 select * from table where ?
  • 当前读
    读取的是记录的最新版本,并且当前读返回的记录,都会加上锁,保证其他事务不会并发的修改这个记录。
    特殊的读操作,INSERT/UPDATE/DELETE都是当前读,要加锁。
1
2
3
4
5
select * from table where ? lock in share mode;
select * from table where ? for update;
insert into table values (…);
update table set ? where ?;
delete from table where ?;

这些都是当前读,第一个加的是共享锁,其他的都是加排他锁。

MYSQL的加锁分析

1
2
SQL1:select * from t1 where id = 10;   
SQL2:delete from t1 where id = 10;

分析MYSQL的加锁情况时需要考虑前提条件

  • id是不是主键
  • 系统的隔离级别
  • id不是主键, 是否存在索引
  • id列上存在二级索引,那这个索引是唯一索引么
  • SQL的执行计划,索引扫描和全表扫描

select * from t1 where id = 10; 这句话都是走的MVCC机制,均不加锁

delete from t1 where id = 10;

  • 情况1 id是主键,RC(提交读) 加独占锁
    11BA25A7-BA7C-4D6F-BB0C-9C286ADBCA06
  • 情况2 id唯一索引+RC
    id是二级索引,主键是name。首先是在id上加X锁,然后在主键上也要加锁。因为是根据主键来更新的索引的。全表扫描也是走主键索引的。
    AE15D3A1-010A-4013-83D8-3DE2218B5D61
  • 情况3 id非唯一索引+RC
    在id = 10全部加上X锁,在主键上将对应的列都加锁。(InnoDB是行锁,指每次只加锁一行数据)
    1D526228-694F-40CA-AD27-5E9AEA2EA635
  • 情况4 id无索引+RC
    没有索引,只能走主键索引,则将主键上的索引都加上X锁
    57BD5A59-9BF7-4D97-A5B2-AD6CE6CC8874
  • 情况5 id非唯一索引+RR
    因为RR是可重复读,则要解决幻读的问题。所以要加上GAP锁。间隙锁不是加在主键索引上
    953A9AEF-0889-48BE-860F-132202AED40D
  • 情况6 id无索引+RR
    走主键索引,全部加上间隙锁
    DB6D4FE2-BB7C-48AF-96F8-F3F2EAE8D81F

MYSQL的死锁分析

757536C9-DFFD-46DF-8608-20258198265F
这个比较好理解。在事务开始后,每个事务都会持有修改数据的行锁。直到事务结束后才会释放锁。那么两个事务分别持有id=1和id=5的锁,再去求对方的锁造成死锁

F4145C94-E52D-4FC5-A6F6-C834CA2E26F8
第一句话走name的索引,是先锁1,再锁2. 第二句话走pubtime的索引,根据pubtime的排序加锁。则可能语句1和语句2的加锁顺序会相反造成死锁。两次查询都会走主键索引。

乐观锁和悲观锁

数据库的并发控制主要解决多个事务同时读取数据库中的数据要解决的问题。
乐观锁并发控制和悲观锁并发控制是并发控制的主要手段

悲观锁

在对任意记录进行修改前,先尝试为该记录加上排他锁(exclusive locking)。
如果加锁失败,说明该记录正在被修改,那么当前查询可能要等待或者抛出异常。具体响应方式由开发者根据实际需要决定。
如果成功加锁,那么就可以对记录做修改,事务完成后就会解锁了。其间如果有其他对该记录做修改或加排他锁的操作,都会等待我们解锁或直接抛出异常。

1
2
3
4
5
6
7
8
9
10
//0.开始事务
begin;/begin work;/start transaction; (三者选一就可以)
//1.查询出商品信息
select status from t_goods where id=1 for update;
//2.根据商品信息生成订单
insert into t_orders (id,goods_id) values (null,1);
//3.修改商品status为2
update t_goods set status=2;
//4.提交事务
commit;/commit work;

在上面的语句中,我们使用了select for update 实现了悲观锁。t_goods的id=1的行的数据被锁定了。其他的事务要等这个事务提交完了才能执行。可以保证数据不会被其他事务修改。

乐观锁

乐观并发控制假设多个事务的处理不会彼此造成影响。各事务在不加锁的情况下能处理各自部分的数据。在提交数据更新之前,每个事务都会检查在改事务读取数据后有没有其他事务又修改了这部分的数据。如果其他事务也有更新的话,就回滚重试。

1
2
3
4
5
6
7
1.查询出商品信息
select (status,status,version) from t_goods where id=#{id}
2.根据商品信息生成订单
3.修改商品status为2
update t_goods
set status=2,version=version+1
where id=#{id} and version=#{version}; //在修改的这段时间内没有其他的事务修改这条数据

乐观并发控制是相信事务之间的数据竞争的概率比较小,因此尽可能直接做下去,直到提交的时候才去锁定,所以不会出现锁和死锁。但是如果两个事务同时读取了数据库的某一行,经过修改后在写回数据库,就会造成问题。

InnoDB和MyISAM的区别

InnoDB和MyISAM在并发性上有点类似于ConcurrentHashMap和HashTable的区别。

InnoDB的特性

  • 采用MVCC(多版本并发控制)实现高并发,实现了4个隔离级别,默认为可重复读(加间隙锁来避免幻读)
  • 采用了簇族索引,对主键查询有很好的性能。二级索引必须包含主键
  • 采用行级锁
  • 事务管理,支持崩溃后的安全恢复

MyISAM

  • 不支持事务和行级锁,在数据库奔溃后无法安全恢复
  • 保存了表的行数
  • 加锁和并发 加的是表锁,在读取时会对所有的表加共享锁,写入时加入拍他锁。但是在表有插入时,也可以往表中插入记录。
  • 索引特性 支持全文索引,或者对TEXT前500个词加索引
  • 可以压缩表

MySQL的基准测试

基准测试是唯一方便有效的测试系统在给定的工作负载下的性能,评估系统的容量等。

基准测试指标

  • 吞吐量
    单位时间内的事务处理量
  • 响应时间
    测试任务的整体时间 可以做多次任务,取百分比
  • 并发性
    测试的同时工作的线程数或者连接数,当并发性增加时,系统的吞吐量是否会下降。
  • 可扩展性
    给系统增加一倍的工作量,理想的情况下吞吐量变成2倍。或者给系统增加一倍的资源,可以获得两倍的结果。

设计基准测试

首先要获得生产数据的快照,并且该快照容易还原。
建立一个单元测试集,并运行多遍,每次运行完后要还原数据。
基准测试要运行时间时间为读IO操作要3个小时,写IO要8个小时才区域稳定,之前是系统预热时间。

服务器性能查询优化

服务器性能优化主要有

  1. 如何确认服务器达到了性能最佳的状态
  2. 如何查出某条语句为啥执行不够快
  3. 诊断被用户描述成“停顿”、“卡死”等状态。

MySQl中的慢查询日志和查询日志

  1. 慢查询日志是记录每个查询语句的执行时间
  2. 查询日志是记录每个语句请求到服务器的时间

使用慢查询日志来优化那些效率低下的查询语句

MYSQL的数据类型和范式

数据类型

  • 整数类型
    TINYINT,SMALLINT,等等 8位,16位,4位
  • 实数类型
    DECIMAL 是带有小数部分的数字
  • 字符串
    CHAR(定长)和VARCHAR(不定长)
    CHAR根据定义的字符串长度来分配空间,VARCHAR是可以存储变长度的字符串,末尾要记录字符串长度。多申请空间末尾补空格更加节省空间,根据字符串长度使用必要的空间 末尾要多两个字节保存长度。varchar(1000) 要1002个字节长度

三大范式

  • 第一范式
    数据库的字段都是单一属性,不能再分
  • 第二范式
    非主键列的字段必须完全依赖于主键列,
  • 第三范式
    字段属性不依赖于非主键列的其他列

使用数据库表设计的三大范式可以消除数据冗余、删除异常等问题。

创建高性能的索引

创建索引是查询优化性能的最有效的手段。在一次查询中,无论你创建了多少索引,最终只会使用其中的一个索引。其他的是走内存筛选或者文件排序

使用索引的优点

  1. 索引可以减少服务器扫描数据行的数量
  2. 索引可以避免排序和创建临时表
  3. 索引将随机IO变成了顺序IO

mysql存储的基础知识

页的概念

数据库文件以页为存储单位,一个页(8K)可以存放N行数据。常用的页类型为索引页和数据页。一个页中存放数据外还要存放页的信息和偏移量等
531AC4FB-7FA8-4FB6-A881-FC73600F0DA9

树的概念

二叉树

这个就是二叉搜索树,树的深度太深,需要多次IO操作
FA4F7643-CC7D-4D7E-A98D-0DB16D1C1EAD

B-树

B-树是一个m阶的多叉搜索树

  • 阶数(M)大于2,孩子个数大于2
  • 每个节点存放[M/2 -1] 到M-1个关键字
  • 非叶子节点的关键字是按顺序排列的 K[1],K[2],…K[n],其中K[i]<K[i+1]
  • 叶子节点都在同一层,所以叶子节点的深度相同
  • 非叶子节点的关键字的个数=指向儿子的指针个数-1
  • 非叶子节点的指针P[1],P[2],P[3],P[M]其中P[1]为关键字小于K[1]的子树,P[M]为大于K[M-1]的子树,其他P[i]为K[I-beam]到K[i]

-c

B+树

非叶子节点的子节点和关键字相同,即节点有三个元素。叶子节点有一个指向相邻叶节点的指针。
-c

聚簇索引和非聚簇索引

聚簇索引指的是数据行存放在索引的叶子页。索引列中包含了聚簇索引列。当表中有聚簇索引时,数据行是按照顺序排列的,否则数据行是存放在无序堆结构中。
9A4054E7-390E-487F-B6BD-45EC4B20C5EC

  • 聚族索引和查询操作
    在查询时,会先对索引表查询,如果索引在缓存表中可以找到,那么可以避免IO查询。在索引中找到索引值,就可以找到数据行
  • 聚族索引和删除操作
    插入数据时,会先根据索引找到对应的数据页,再挪动已有的数据 所以最好是按照主键自增来增加数据,避免不必要的移动。并且主键列不要修改,修改会造成大量的数据移动。
  • 删除数据会将下面的数据往上移动
  • 聚族索引会降低数据的插入和删除效果,在update其他非主键列没有影响

辅助索引

InnoDB的辅助索引的叶子结点都是保存主键索引的值。所以在查找的时候需要2次查找。如果主键索引定义的比较大,其他索引也会非常的大。所以要在表上定义很多的索引,要争取把主键定义的小一点。
6942E016-E022-4E57-B821-2995DDF38A32
聚簇索引对主键的查询非常高效,但是使用辅助索引必须检索2遍的索引。

非聚簇索引

非聚族索引不是物理上排列顺序,而是通过指针来定位数据
非聚族索引数据存储没有顺序,则指针包含的是数据页+偏移量 这里需要访问一次随机IO

2787163F-9D09-4065-BFAE-F1054393AF0B

B-Tree树索引

B-Tree索引是用多叉树的原理来存储索引,叶子结点存的是数据行所在页和在页中的偏移 使用多插树可以减少IO访问的次数。提高速度 logm(n)的时间复杂度吧。
B-Tree索引的叶子结点到根结点的距离都是相同的,使用索引能提高数据的查询速度。因为不需要全表查询所需要的数据

F29C5F88-7A25-44B2-9ABC-17648FD6CC8A

B-Tree树索引的查找过程

如果要查找数据项29,那么先把磁盘块1加载到内存中,此时发生一次IO读取,然后在内存中二分查找确定在17和35之间,锁定了磁盘快3,然后加载磁盘块3发生第二次IO读取,在找到磁盘块8,第三次IO。结束查询。

B-Tree树的性质

树的高度计算
二插树为h = log(2)N 以2为底。如果是m叉树,就是h = log(m)N m为数据页里面的key的个数。
假设当前的数据表的数据为N,每个磁盘块的数据项的数目为m,则有h = log(m)N。则m越大,N越小。
m = 磁盘块的大小/数据项的大小。 所以索引要小一些,这样子树的高度就会小一些。
当B-Tree树的数据项是复合的数据结构,比如(name, age,sex)的时候,b+树按照从左到右的顺序建立搜索树。则B-Tree树会先按照左边的来查找。即索引的最左匹配原则。

使用多级索引

在多个列上建单独的索引在大部分的情况下并不能提高MYSQL的查询能力。在早期的MYSQL中,只能使用单独的一列索引。现在的MYSQL可以采用索引合并的策略,不过还是复合索引效果更好。

使用多级索引注意

  1. 全值匹配 匹配索引的全部列
  2. 匹配最左前缀 索引是从左往右开始存储

使用多级索引的限制

  1. 不是按照索引的最左列开始查找,无法使用索引。 因为多级索引是先按照最左边的索引开始排序,对于第一个索引相同的按照第二个索引开始排序,以此类推
  2. 不能跳过索引的列 有3个索引,不能只使用1,3索引,2不使用 那么系统只使用1索引,3不使用
  3. 使用某个列的范围查询 该范围的右边的索引不再使用

索引失效

  1. where条件出来的数据很多,大于15% 。导致索引实效
  2. 索引本身实效,索引参与计算了,SELECT * FROM t_user where id-1=9 比如like %_ like函数%在前面 和not in not exist

使用索引扫描来排序

在explain时,可以看到extra列中有使用using index和using filesort,即索引排序和文件排序

文件排序

文件排序是通过相应的排序算法,将取出的数据在内存中进行排序。使用的内存区域是sort_buffer_size的排序区域。这部分是thread独享的。所以在同一时间,mysql可以存在多个sort buffer在内存中。

只有当索引的的列顺序和order by子列的顺序完全一致,并且所有列的排序方向一样(正序或者倒序),mysql才会使用索引扫描对结果排序。即order by字句必须满足索引的最左前缀原则,如果前缀列是常数,则可以按照下一列排序。

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
create table test(
a int,
b int,
c int,
KEY a(a,b,c)
);

//这个语句可以走索引,因为在a固定时b和c时按照顺序排列的
select * from test where a = 10 order by b, c

// 可以走索引排序
select * from test where a = 10 order by a, b

// 不能走索引排序,
select * from test where a = 10 order by b desc , c asc

//文件排序,不能构成最左前缀原则
select * from test where a = 10 order by c

// 下面都不能使用索引排序,因为a是范围值时,b和c的顺序是打乱的,必须全表扫描,索引会走文件排序
select * from test where a > 10 and b = 3 and c = 4
select * from test where a > 10 order by b, c

慢查询优化

MySQL的执行计划是专门针对SELECT语句设计的,因为使用UPDATE,DELETE也是要先用SELECT读取当前的数据行。
MYSQL提供了EXPLAIN语法来进行查询分析,在SQL语句前加“EXPLAIN”就可以了。
A6721BF7-E89C-4256-BB4E-CEEA6719533E

  • id是数字越大越先执行,针对存在子查询的情况
  • select_type 查询的类型
  • table 查询的表 如果是别名,就显示别名
  • type
    查询中使用的模式 all是走全表,在缓存中过滤出符合的行 index是走索引查询
  • key
    查询中走的索引名字
  • row 在查询中一共走了多少行数据
  • extra order by 字句是走文件排序还是索引排序

Mysql复制原理

主从库的逻辑。读写分离,写在主库,读分到其他裤。 每次写主库,要都写到其他的备库中才算完成写操作。
123
备库不应该有主动的写操作,因为备库无法通知主库去进行数据同步,会造成数据不一致。
MySQL的内置复制功能是构建基于MySQL的大规模、高性能应用的基础。可以为服务器配置多个备库的方式来数据同步
主从复制是基于binlog(二进制文件)来实现的。在执行过程中会出现复制数据不一致的情况。需要定期开展复制数据一致性的检验和修复工作。

主从数据检查

  1. 数据一致性检验
    使用的是pt-table-checksum工具,用来实现主从数据一致性的校验工作。
    原理:通过SQL在主库中执行数据库的校验,然后再将SQL语句传输到从库中,并在从库中计算校验块的检验,然后比对主库和从库的结果。
  2. 主从数据一致性修复
    使用的是pt-table-sync工具,用来修复主从复制数据不一致,最终修复到一致。其中,在sync工具中还有checksum,可以一边修复一边校验数据一致性。

主从复制原理

  1. 主库把数据更改记录到二进制日志中
  2. 备库将主库中的日志复制到中继日志(relay log)中 开启IO线程
  3. 备库读取中继日志的时间,将其重放到备库数据中 开启SQL线程
    47C27702-7B6F-421C-B263-350FA97515BE

master将事务串行写到binlog中。日志写入完成后,master通知存储引擎提交事务。在slave中的IO线程将收取binlog,写到自己的relay log中,最后slave中的SQL线程执行binlog,从而使主从数据一致。

复制的原理

基于语句的复制

在早期的mysql版本中只支持语句的复制(逻辑复制)。主库会记录造成语句修改的查询,当备库读取并重放时是重新执行了一遍SQL语句。
实现简单,主库的修改好几十w条数据的语句在二进制文件中可能只是几条语句。但是因为主库和从库的时间戳不一样,导致一些操作出现问题。并且更新必须串行化,需要更多的锁。

基于行的复制

将实际的数据记录到二进制日志中,再跟其他的数据库比较
优点:减少锁的使用,基于行的复制可以解决数据不一致的问题。比如备库更新不存在的记录不会报错,但是基于行的复制模式就会报错。
缺点:全表修改会造成二进制日志过大

SQL可以在这两个之间切换,先使用语句复制,无法实现使用基于行的复制

复制拓扑

  1. 一主库多备库
    少量写和大量读时候,可以将读操作分摊到多个备用服务器中(只读)
  2. 主动-主动模式下的主主复制
    两台服务器均配置成主库和对方的备库
    优点:两台服务器均可写
    缺点:很有可能在同步时候发生冲突
  3. 主动-被动模式下的主-主复制
    反复切换主动和被动服务器很方便
    当一台服务器要修改数据,可以先停止主库中的复制线程,在被动服务器中执行修改数据库操作,交换主库和备库的角色,最后在先前的主库中启动复制线程。

常见的问题

  1. 测量备库延迟
    普遍的问题是测量备库落后主库的延迟有多大
    使用heartbeat record。主库中每秒更新一次时间戳,从库中用当前时间减去传过来的时间戳就是延时的时间。 pt-heartbeat脚本可以检测。
  2. 确定主备库是否一致
    理想情况下,主备库的数据应该一致。但是可能备库的数据库崩溃等问题导致数据不一致。
    pt-table-checksum方法可以解决这个问题
    在主库中执行INSERT—SELECT查询,这些查询对数据校验并将结果插入到一个表中。然后将语句和表复制到备库中。在备库中也执行一样的操作,看结果是否一致。
    将会检查所有的表,在备库中执行完毕后就可以得到答案。
  3. 主从延时过大怎么办
    首先,先使用pt-heartbeat来检测主从延时究竟有多大。
    然后再查看是因为主库中的事务过大提交慢还是因为从库SQL线程的复制慢。使用show slave status看binlog apply position是不是不动
    1.不断增大,那么说明是主库中提交的事务过多,主库是并发的,从库是串行化的,需要时间同步。
    2.不动, 说明是主库提交了一个大事务,找到这个事务将事务改小。
  4. 主从延迟导致数据延迟问题解决
    在主库写操作的同时,可以先在redis等里面写缓存,在读取的时候先读取缓存内的数据,缓存内的数据没有再去从库中读取。
0%