一个慢日志问题引出的 MySQL 半一致性读的应用场景

MySQL半致性读的应用场景:从慢日志问题探讨到编程实现 随着数据库应用的不断发展,对数据读取的一致性要求也日益增加。MySQL数据库作为广泛应用的关系型数据库管理系统,提供了多种读取一致性级别。其中,半致性读(semi-consistent read)是一种折中方案,既满足了部分一致性的要求,又能在性能上有所提升。本文将通过分析慢日志问题,探讨MySQL半致性读的应用场景,并给出相应的编程实现。 阅读详情

作者通过一个慢日志问题,引出 MySQL 半一致性读的概念及实际应用场景。

作者:龚唐杰

爱可生 DBA 团队成员,主要负责 MySQL 技术支持,擅长 MySQL、PG、国产数据库。

本文来源:原创投稿

  • 爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

背景

某系统执行更新操作发现很慢,发现有大量慢日志,其中 Lock time 时间占比很高,MySQL 版本为 5.7.25,隔离级别为 RR。

分析

查看表结构以及 UPDATE 语句的执行计划:

mysql> show create table test;

+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| test | CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(30) COLLATE utf8mb4_bin DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2621401 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> explain update test set name ='test' where name='a';
+----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+
| 1  | UPDATE      | test  | NULL       | index | NULL   | PRIMARY | 4 | NULL | 2355988 | 100.00 | Using where |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+
1 row in set (0.00 sec)

通过执行计划发现,该 SQL 是走的主键全索引扫描,并且对于 name 列未加索引,当多个事务同时执行时,就会观察到有阻塞出现。

事务1事务2
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update test set name =‘test’ where name=‘a’;
Query OK, 262144 rows affected (4.67 sec)
Rows matched: 262144 Changed: 262144 Warnings: 0
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update test set name =‘test1’ where name=‘b’;

若 name 列的重复值不多,那么可以对 name 列添加索引即可解决该问题。因为 InnoDB 的行锁机制是基于索引列来实现的,如果 UPDATE 语句能使用到 name 列的索引,那么就不会产生阻塞,导致业务卡顿。

但若是 name 列的值的区分度很低,就会导致 SQL 不会走 name 列的索引,示例如下:

先添加索引

mysql> alter table test add index tt(name);
Query OK, 0 rows affected (2.74 sec)
Records: 0 Duplicates: 0 Warnings: 0

然后查看执行计划,发现可能用到的索引有 tt,但是实际情况依然走的主键全索引扫描。

mysql> explain update test set name ='test' where name='a';
+----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+
| 1 | UPDATE | test | NULL | index | tt | PRIMARY | 4 | NULL | 2355988 | 100.00 | Using where |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+
1 row in set (0.00 sec)

因为 MySQL 的优化器是基于代价来评估的,我们可以通过 optimizer trace 来观察。

mysql> show variables like 'optimizer_trace';
+-----------------+--------------------------+
| Variable_name | Value |
+-----------------+--------------------------+
| optimizer_trace | enabled=off,one_line=off |
+-----------------+--------------------------+
1 row in set (0.01 sec)

可以看到值为 enabled=off,表明这个功能默认是关闭的。

如果想打开这个功能,必须⾸先把 enabled 的值改为 on。

mysql> set optimizer_trace="enabled=on";
Query OK, 0 rows affected (0.00 sec)

然后执行该 SQL,查看详细的信息,这里我们主要关注的是 PREPARE 阶段的成本计算。

mysql> update test set name ='test' where name='a';
Query OK, 262144 rows affected (5.97 sec)
Rows matched: 262144 Changed: 262144 Warnings: 0

mysql> SELECT * FROM information_schema.OPTIMIZER_TRACE\G 

详细结果如下。

mysql> SELECT * FROM information_schema.OPTIMIZER_TRACE\G
*************************** 1. row ***************************
QUERY: update test set name ='test' where name='a'
TRACE: {
"steps": [
{
"substitute_generated_columns": {
}
},
{
"condition_processing": {
"condition": "WHERE",
"original_condition": "(`test`.`name` = 'a')",
"steps": [
{
"transformation": "equality_propagation",
"resulting_condition": "multiple equal('a', `test`.`name`)"
},
{
"transformation": "constant_propagation",
"resulting_condition": "multiple equal('a', `test`.`name`)"
},
{
"transformation": "trivial_condition_removal",
"resulting_condition": "multiple equal('a', `test`.`name`)"
}
]
}
},
{
"table": "`test`",
"range_analysis": {
"table_scan": {
"rows": 2355988,
"cost": 475206
},
"potential_range_indexes": [
{
"index": "PRIMARY",
"usable": true,
"key_parts": [
"id"
]
},
{
"index": "tt",
"usable": true,
"key_parts": [
"name",
"id"
]
}
],
"setup_range_conditions": [
],
"group_index_range": {
"chosen": false,
"cause": "no_join"
},
"analyzing_range_alternatives": {
"range_scan_alternatives": [
{
"index": "tt",
"ranges": [
"0x0100610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 <= name <= 0x0100610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
],
"index_dives_for_eq_ranges": true,
"rowid_ordered": true,
"using_mrr": false,
"index_only": false,
"rows": 553720,
"cost": 664465,
"chosen": false,
"cause": "cost"
}
],
"analyzing_roworder_intersect": {
"usable": false,
"cause": "too_few_roworder_scans"
}
}
}
}
]
}
MISSING_BYTES_BEYOND_MAX_MEM_SIZE: 0
INSUFFICIENT_PRIVILEGES: 0
1 row in set (0.00 sec)

可以发现执行全表扫描的成本为 475206,走索引 tt 的成本为 664465,所以 MySQL 选择了全表扫描。

那么如果是这种情况改怎么处理呢?

如果 InnoDB 隔离级别是 RR,数据库层面没有太好的方式,推荐应用端进行改造。

如果数据库隔离级别可以更改,那么可以改为 RC 来解决阻塞的问题。因为 RC 模式下支持半一致性读。

什么是半一致性读呢?

简单来说就是当要对行进行加锁时,会多一步判断该行是不是真的需要上锁。比如全表扫描更新的时候,我们只需要更新 WHERE 匹配到的行,如果是没有半一致性读就会把所有数据进行加锁,但是有了半一致性读,那么会判断是否满足 WHERE 条件,若不满足则不会加锁(提前释放锁)。

那么对于区分度低的字段就可以使用半一致性读特性来优化,这样更新不同的值就不会互相等待,导致业务卡顿。

事务1事务2
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update test set name =‘test’ where name=‘a’;
Query OK, 262144 rows affected (9.30 sec)
Rows matched: 262144 Changed: 262144 Warnings: 0
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update test set name =‘test1’ where name=‘b’;
Query OK, 262144 rows affected (8.46 sec)
Rows matched: 262144 Changed: 262144 Warnings: 0

结论

  1. 行锁机制是基于索引列实现的,若没有使用到索引,则会进行全表扫描。
  2. 半一致性读是基于 RC 隔离级别的优化,可以减少锁冲突以及锁等待,提升并发。

关于 SQLE

爱可生开源社区的 SQLE 是一款面向数据库使用者和管理者,支持多场景审核,支持标准化上线流程,原生支持 MySQL 审核且数据库类型可扩展的 SQL 审核工具。

SQLE 获取

类型地址
版本库https://github.com/actiontech/sqle
文档https://actiontech.github.io/sqle-docs/
发布信息https://github.com/actiontech/sqle/releases
数据审核插件开发文档https://actiontech.github.io/sqle-docs-cn/3.modules/3.7_auditplugin/auditplugin_development.html
MySQL半一致性读原理解析-从源码角度解析 1、什么是半一致性读A type of read operation used for UPDATE statements, that is a combination of read committed and consistent read. When an UPDATE statement examines a row that is already locked, InnoDB retur... 阅读详情

相关推荐

【Ambari-Metrics监控】Grafana+Infinity快速构建DEMO-实战教学

摘要:本文介绍了如何通过Infinity插件在Grafana中监控Ambari-Metrics(AMS)的CPU核数指标。内容包括配置AMS REST API数据源、创建Dashboard面板、设置JSON解析规则,将时间戳和数值映射为时序数据。最终实现单个节点CPU核数曲线的可视化展示,该方法可扩展至其他AMS指标监控。文章提供了完整的配置示例和API调用验证方法,适用于Grafana 9.x及以上版本对接Ambari集群监控场景。

TTBIGDATA的博客 1351

MySQL的半一执行读

MySQL的半一致性读

雪辉博客 1154

从UE4到Unity:双叶高光技术在角色皮肤渲染中的移植全流程

本文详细解析了将UE4中的双叶高光技术移植到Unity引擎的全流程。该技术通过模拟皮肤油脂层和真皮层的不同反射特性,能显著提升角色皮肤渲染的真实感。文章从核心原理、贴图资产处理、Shader代码重构到参数调校,提供了完整的跨引擎移植实战指南,帮助开发者实现高质量的皮肤质感还原。

alice7model的博客 477

mysql 半一致性读_MySQL半一致性读原理解析-从源码角度解析

1、什么是半一致性读A type of read operation used for UPDATE statements, that is a combination of read committed and consistent read. When an UPDATE statement examines a row that is already locked, InnoDB retur...

weixin_33548183的博客 750

电化学阻抗谱(EIS)在锂离子电池中的应用

摘要电化学阻抗谱(electrochemical impedance spectroscopy, EIS)是一种重要的电化学测试方法,在锂离子电池动力学反应机理研究及动力学参数测量等方面具有广泛的应用。在锂离子电池运行过程中,各反应步骤的动力学参数及时间常数不同,而EIS可以在较宽的频率范围内对体系施加小幅正弦激励信号,使得在特定频率下突出特定时间常数的电极过程,从而将复杂的电极过程分离,实现单一电极过程动力学的分析。通过对交流阻抗信息的研究,也可以为锂离子电池及其他电池的应用与管理、电化学过程设计及电极材

qiushireader的博客 2649

SAP S4 HANA 新资产会计中的平行分类账估值

在资产会计中,我们可以设置使用折旧区域的平行分类账会计 我们需要根据涉及的会计原则定义折旧区域,在我们的方案中,公司 FR01 是一家国际集团的当地分支机构,公司 FR01 需要按照集团会计准则 IFRS 和当地 GAAP 会计准则报告财务报表。过账到 LG 会计原则(分类帐 2L)-->分类账 2L的 150 欧元损失 -->在 IFRS 折旧区域,我们有 100 欧元的收益,在 LG 折旧区域,我们有 150 欧元的损失,使用平行分类账 0L 和 2L,我们能够根据不同的会计原则进行平行估值。

yanzibing99的博客 1328

mysql 半一致性读_mysql半一致性读案例分析

一.基本信息版本:mysql 5.6.29事务隔离级别(TR_ISOLATION): READ COMMITED建表:CREATETABLE`test_locks`(`id`int(11)DEFAULTNULL,`name`varchar(20)DEFAULTNULL,`age`INT(11))ENGINE=InnoDB插入数据:INSERTINTOtest_locks(...

weixin_29007135的博客 829

10-142 6-4 查询厂商“D“生产的PC和便携式电脑的平均价格

分数 10全屏浏览题目切换布局作者 lhm单位 河北农业大学本题目要求编写SQL语句,查询厂商D生产的PC和便携式电脑的平均价格。

dqd66的博客 2748

mysql 半一致性读_MySQL什么是半一致性读-爱可生

作者:赵黎明爱可生 MySQL DBA 团队成员,Oracle 10g OCM,MySQL 5.7 OCP,擅长数据库性能问题诊断、事务与锁问题的分析等,负责处理客户 MySQL 及我司自研 DMP 平台日常运维中的问题,对开源数据库相关技术非常感兴趣。本文来源:原创投稿 *爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。什么是半一致性读?先看下官方的描述:是一种用在 ...

weixin_42635064的博客 878

基于STM32F103C8T6的智能蓝牙手环系统设计与实现

摘要:本文设计并实现了一款基于STM32F103C8T6单片机的智能蓝牙手环系统。该系统集成了ADXL345加速度计、DS18B20温度传感器、plusesennor心率模块和BT06蓝牙模块,实现了心率(±2bpm)、体温(±0.5℃)、步数(±3%)等健康数据的实时监测与显示。通过OLED屏提供人机交互界面,支持蓝牙APP远程控制,具备自动步数清零、异常提醒等功能。测试表明系统各项功能均达到设计要求,响应时间0.1-0.5秒,心率检测准确率98%,体温检测准确率99%,功耗50mA(工作)/10mA(待

3254968421的博客 205

Android 15.0 添加自定义服务,并生成jar给第三方app调用

在15.0系统ROM产品定制化开发中,由于需要新增加自定义的功能,所以要增加自定义服务,而app上层通过调用自定义服务,来调用相应的功能,所以系统需要先生成jar,然后生成jar 给上层app调用,接下来就来分析实现的步骤,然后来实现相关的功能 从而来实现所需要的功能

安卓兼职framework和app工程师的博客 668

MySQL怎么运行的系列(十一)快照读、锁定读、半一致性读 和 加锁语句分析

实际上,在 读已提交/读未提交 级别下,如果事务A的update语句要修改的记录已经被其他事务加了X锁,事务A就会读取该记录版本链的最新已提交版本,并判断该版本是否与update语句中的搜索条件相匹配,如果不匹配则不对其加锁(不对其修改,跳到下一条记录),匹配则对其加锁(然后陷入阻塞,待其他事务解锁后对该记录进行修改),这就是半一致性读。回表,在主键索引记录上记录锁,判断其他条件,发现不满足所有其他条件,因此释放主键索引和二级索引对应的记录的锁。如果使用自动事务提交,则select会通过MVCC快照读。

jqsfjqsf的博客 1132

2. 第一个 SAP CDS View 源代码的详细解析:CDS View 和底层自动生成 SQL View 的关系讲解

笔者前一篇教程文章,带着大家在 ABAP 系统创建了一个最简单的基于sflight数据库表的 CDS View:本文对这简单的 14 行源代码背后的知识点进行详细讲解。CDS 全称是 Core Data Services,它是一种数据建模技术,帮助开发者以更直观和高层的方式去描述数据库中所需的数据结构。在一个典型的 SAP ABAP 开发场景里,CDS 经常被用来编写各种用于报表、接口或业务逻辑的数据视图。通常,这些视图包含一系列注解。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1021

MySQL 事务管理

重点:begin/start transaction 命令并不是一个事务的起点,在执行到它们之后的第一个操作 InnoDB 表的语句,事务才真正启动。如果想要马上启动一个事务,可以使用 start transaction with consistent snapshot 这个命令。 事务隔离级别 根据读和提交的关系来分类的 读未提交:一个事务还没提交时,它做的变更就能被别的事务看到; 读提交:一个事务提交之后,能被其他事务看到; 可重复读:一个事务执行过程中看到的数据,总是根这个事务在启动时看到的数据一致

Panda的学习日常 550

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

mysql半一致性_MySQL半一致性读原理解析-从源码角度解析

1、什么是半一致性读A type of read operation used forUPDATEstatements, that is a combination ofread committedandconsistent read. When anUPDATEstatement examines a row that is already locked, InnoDB retur...

weixin_35742845的博客 349

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

生产环境的 MySQL事务隔离级别

在执行 update 的时候,扫描发现当前行已经被锁定了,它就会执行半一致性读的操作,得到当前数据的最新版本(上述中 SQL-A 锁定的行最新版本的已提交数据,b都为5 ),来判断是否和当前的(SQL-B)update 的 where 条件匹配。x-lock(1,2)、x-lock(3,2) 和 x-lock(5,2) -- 这些行虽然不符合更新条件,但由于间隙锁的存在,它们也会被锁定以防止其他事务插入新的行。x-lock(2,3) 和 x-lock(4,3) -- 这两行会被更新并保留X锁。

欢迎来到空说的博客 596

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

mysql 一致性读_MySQL 一致性读 深入研究

MySQL一致性读,又称为快照读。使用的是MVCC机制读取undo中的已经提交的数据。所以它的读取是非阻塞的。相关文档:http://dev.mysql.com/doc/refman/5.6/en/innodb-consistent-read.htmlA consistent read means that InnoDB uses multi-versioning to present to a ...

weixin_42364681的博客 292

mysql 半一致性读_关于MySQL的半一致性读-爱可生

原标题:关于MySQL的半一致性读-爱可生作者:赵黎明爱可生 MySQL DBA 团队成员,Oracle 10g OCM,MySQL 5.7 OCP,擅长数据库性能问题诊断、事务与锁问题的分析等,负责处理客户 MySQL 及我司自研 DMP 平台日常运维中的问题,对开源数据库相关技术非常感兴趣。本文来源:原创投稿 *爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。什么是...

weixin_39860732的博客 198

事务隔离级别&传播行为

事务 事务(Transaction)是由一系列对系统中数据进行访问与更新的操作所组成的一个程序 执行逻辑单元(Unit)。 ACID ACID分别是Atomic(原子性)、Consistency(一致性)、Isolation(隔离性)、Durability(持久性)。 Atomic:在事务内,所有sql要不就一起成功,要不就一起失败,不存在一条成功一条失败。 Consistency:事务的一致性是指事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处于一致性状态。也就

qq_27185561的博客 492

MySQL 中隔离级别 RC 与 RR 的区别

1. 数据库事务ACID特性 数据库事务的4个特性: 原子性(Atomic):事务中的多个操作,不可分割,要么都成功,要么都失败; All or Nothing.一致性(Consistency):事务操作之后, 数据库所处的状态和业务规则是一致的; 比如a,b账户相互转账之后,总金额不变;隔离性(Isolation):多个事务之间就像是串行执行一样,不相互影响;持久性(Durability):事务提交后被持久化到永久存储. 2. 隔离性 其中隔离性分为了四种: READ UNCOMMIT...

lgxzzz的博客 647

mysql半一致性_MySQL什么是半一致性读-爱可生

作者:赵黎明爱可生 MySQL DBA 团队成员,Oracle 10g OCM,MySQL 5.7 OCP,擅长数据库性能问题诊断、事务与锁问题的分析等,负责处理客户 MySQL 及我司自研 DMP 平台日常运维中的问题,对开源数据库相关技术非常感兴趣。本文来源:原创投稿 *爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。什么是半一致性读?先看下官方的描述:是一种用在 ...

weixin_39873356的博客 243

mysql binlog出错_MySQL半一致性读导致语句级Binlog复制错误

MySQL事务的隔离级别为read committed(或以下),或者设置了innodb_locks_unsafe_for_binlog参数会启用半一致性读特性。MySQL官方文档refman-5.6-en.a4.pdf 1833页 关于innodb_locks_unsafe_for_binlog参数对于半一致性读,我感觉一个是违反两阶段锁,将不符合条件记录的行级锁提前释放。另一个是Update的...

weixin_42634811的博客 238

MySQL 默认隔离级别是RR,为什么阿里等大厂会改成RC?(1)

一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取![外链图片转存中…(img-YIzEIzFy-1714519203717)]《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!

2401_83916204的博客 879

MySQL默认隔离级别是RR,但是为什么一些大厂会改成RC?

为什么默认隔离级别是RR? 可能大部分人都只知道MySQL的隔离级别有4个,分别是RU读未提交、RC读已提交、RR可重复读和Serializable可串行化,很少有人知道MySQL默认的隔离级别是RR,Oracle默认的隔离级别是RC。那就更少有人知道为什么MySQL默认的隔离级别是RR了。我也是刚刚工作之余看到了一篇文章,里面简单提了一下这个问题,我就四处找寻了一下答案,将自己所理解的记录下来,希望对大家有帮助。 理解脏读、不可重复读、幻读 脏读:某个事务对一份数据执行了更新操作,另一个事务在此时读

NoviceZ的博客 2731
上一篇: 一文弄懂 OceanBase 用户管理和访问控制
下一篇: 使用 OAT 工具替换 OceanBase 云平台节点
爱可生开源社区
博客等级 码龄8年 1936粉丝 1004原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值