Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >A little fun with InnoDB multi-versioning(14.有关InnoDB多版本中的一个小问题)

A little fun with InnoDB multi-versioning(14.有关InnoDB多版本中的一个小问题)

作者头像
冬天里的懒猫
发布于 2020-09-02 11:17:18
发布于 2020-09-02 11:17:18
42900
代码可运行
举报
运行总次数:0
代码可运行

执行以下命令,在MySQL CLI中,在一个新的连接上执行,不需要做特别的准备(并且要特别注意执行时间):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ysql> show create table t \G
*************************** 1. row ***************************
       Table: t
Create Table: CREATE TABLE `t` (
  `a` int(10) unsigned NOT NULL,
  `b` int(10) unsigned NOT NULL,
  PRIMARY KEY (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

mysql> select * from t;
Empty set (5.20 sec)

mysql> select count(*) from t;
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (5.22 sec)

mysql> select * from t where a = 10;
Empty set (0.00 sec)

mysql> select * from t where a < 10;
Empty set (5.35 sec)

mysql> select * from t where a > 10;
Empty set (5.41 sec)

mysql> select * from t where a in (10, 20, 30);
Empty set (0.00 sec)

mysql> select * from t where a > 1000000;
Empty set (0.00 sec)

mysql> select * from t where a > 500000;
Empty set (2.60 sec)

发生了什么?为什么这么慢?为什么有些东西慢而有些不慢?

寻找罪魁祸首

SHOW PROCESSLIST没有显示任何异常:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mysql> show processlist;
+----+------+-----------------+------+---------+------+-------+------------------+
| Id | User | Host            | db   | Command | Time | State | Info             |
+----+------+-----------------+------+---------+------+-------+------------------+
|  6 | root | localhost:34840 | test | Query   |    0 | init  | show processlist |
|  8 | root | localhost:34842 | test | Sleep   | 2116 |       | NULL             |
+----+------+-----------------+------+---------+------+-------+------------------+
2 rows in set (0.00 sec)

如果我们看一下显示引擎INNODB的状态,就会发现一条线索:一个忙于作恶的事务:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
---TRANSACTION 1481, ACTIVE 2183 sec
3487 lock struct(s), heap size 570920, 2001743 row lock(s), undo log entries 11000000
MySQL thread id 8, OS thread handle 0x7fca27ba2700, query id 5000144 localhost 127.0.0.1 root cleaning up 

它还显示在information_schema.innodb_trx:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mysql> select * from information_schema.innodb_trx \G
*************************** 1. row ***************************
                    trx_id: 1481
                 trx_state: RUNNING
               trx_started: 2014-04-17 01:38:27
     trx_requested_lock_id: NULL
          trx_wait_started: NULL
                trx_weight: 11003487
       trx_mysql_thread_id: 8
                 trx_query: NULL
       trx_operation_state: NULL
         trx_tables_in_use: 0
         trx_tables_locked: 0
          trx_lock_structs: 3487
     trx_lock_memory_bytes: 570920
           trx_rows_locked: 2001743
         trx_rows_modified: 11000000
   trx_concurrency_tickets: 0
       trx_isolation_level: REPEATABLE READ
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_adaptive_hash_latched: 0
 trx_adaptive_hash_timeout: 10000
          trx_is_read_only: 0
trx_autocommit_non_locking: 0
1 row in set (0.01 sec)

事务怎么会是邪恶的?

我使用下面的脚本插入一百万行,然后每一行更新十次,保持事务打开和未提交:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#!/usr/bin/env ruby

require "mysql"

m = Mysql.new("127.0.0.1", "root", "", "test", 13000)

m.query("DROP TABLE IF EXISTS t")
m.query("CREATE TABLE t (a INT UNSIGNED NOT NULL, b INT UNSIGNED NOT NULL, PRIMARY KEY (a)) ENGINE=InnoDB")

m.query("START TRANSACTION")

(1..1000000).each do |i|
  m.query("INSERT INTO t (a, b) VALUES (#{i}, 0)")
  puts "Inserted #{i} rows..." if i % 10000 == 0
end

(1..10).each do |i|
  m.query("UPDATE t SET b=#{i}")
  puts "Updated #{i} times..."
end

sleep 1000000

正如InnoDB撤销日志记录和历史系统的基础中所描述的,这些修改都是对数据库进行的,未提交的写事务和我的读事务都使用单一的索引结构。尽管我的读事务不能看到写入事务插入和随后修改的任何行,但为了弄清楚这一点,它需要将所有的undo记录应用到遇到的每一行(每行10条)。当然,这需要时间。

漏洞的可见性

您可以看到不同操作所花费的时间中,飞行中数据“泄漏”的一些隐藏可见性。例如,扫描所有行的时间超过5秒,但是使用条件a > 1000000可以立即计算。令人怀疑的是,> 500000的条件大约只需要扫描所有行的一半时间(因为它只需要做一半的工作)。当然,所有这些查询都返回一个空集。

对现实世界的适用性

虽然几乎没有人会故意做我的脚本所做的事情,但我以前在生产系统中确实看到过这样的结果:一个非常大的事务多次更新一行会导致试图访问该表的许多慢速查询。有些查询会很快,有些则很慢。

对系统管理员和dba有严重的影响

undo历史记录的形式对用户可以使用的空间没有限制。我已经提交了MySQL Bug #72362:“用户可以无限制地使用undo space”,建议添加配置选项来限制用户可能消耗的undo space。我写了以下内容: 由于InnoDB目前已经实现,用户可以通过以下任意一种方式使用无限的空间来撤消历史记录:

  • 1.创建一个或多个大型事务,多次写入一行,直接积累undo历史记录。
  • 2.使用read视图打开一个事务(同时最低限度地保持其活动),通过防止清除间接积累undo历史。 此外,用户可以将这两种方法结合使用,在打开事务的同时使用read视图同时生成大量的小事务,这些事务各自只有少量的undo历史记录。这样可以更好地防止对罪魁祸首的检测。 这两种情况都允许没有特殊权限的普通用户消耗system表空间中的大量磁盘空间,这可能会导致system表空间被扩展,消耗所有的文件系统空间,而系统管理员没有简单的资源。 我建议为以下内容添加新的配置选项:
  • 模拟单个事务消耗的撤销空间。
  • 限制给定用户使用的聚合undo空间。
  • 限制给定用户的事务读取视图的年龄。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/08/31 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
应用示例荟萃 | performance_schema全方位介绍(中)
表级锁对应的instruments(wait/lock/table/sql/handler)默认启用,对应的consumers表为performance_schema.table_handles在setup_consumers只受全局配置项global_instrumentation控制,默认启用。所以,默认情况下只需要设置系统配置参数performance_schema=ON即可,下面我们通过一个示例演示如何找出谁持有表级锁
老叶茶馆
2020/11/26
4210
MySQL 死锁的详细分析方法
用数据库的时候,偶尔会出现死锁,针对我们的业务系统,出现死锁的直接结果就是系统卡顿、客户找事儿,所以我们也在想尽全力的消除掉数据库的死锁。出现死锁的时候,如果只是想解锁,用show full processlist看下kill掉就好了,如果想查找到详细的问题,一个办法是用show engine innodb status来查看简略信息或者开死锁日志,后期在MySQL日志里面慢慢分析。以上这写方法我们都用过,最近在看Innodb的书的时候发现另一种实时的分析方法,能最大限度的分析死锁的原因。
星哥玩云
2022/08/17
5470
应用示例荟萃 | performance_schema全方位介绍(上)
经过前面6个篇幅的学习,相信大家对什么是performance_schema,已经初步形成了一个整体认识,但我想很多同行看完之前的文章之后可能还是一脸懵逼,今天就为大家带来performance_schema系列的最后一个篇章(全系共7个篇章),在这一期里,我们将为大家列举数十个performance_schema应用示例。下面,请跟随我们一起开始performance_schema系统的学习之旅吧。
沃趣科技
2018/07/02
1.3K0
应用示例荟萃 | performance_schema全方位介绍(上)
MySQL 5.6中如何定位DDL被阻塞的问题
在上一篇文章《MySQL 5.7中如何定位DDL被阻塞的问题》中,对于DDL被阻塞问题的定位,我们主要是基于MySQL 5.7新引入的performance_schema.metadata_locks表。提出的定位方法,颇有种"锦上添花"的意味,而且,也只适用于MySQL 5.7开始的版本。
星哥玩云
2022/08/17
4680
InnoDB数据锁–第2部分“锁”
在InnoDB Data Locking –第1部分“简介”中,我们通过同时编辑电子表格的比喻描述了锁能够解决的难题。虽然通过比喻可以获得直观的感觉,但是我们需要将解决方案与现实进行匹配。在这篇文章中,将讨论我们之前看到的语句如何映射到InnoDB的表,行,锁,锁队列等实际情况,例如“ Alice请求对文件A的读取访问,但必须等待Basil首先释放其写权限”。
MySQLSE
2020/10/29
1K0
MySQL SQL更新锁定
版权声明:本文为博主原创文章,欢迎扩散,扩散请务必注明出处。
Leshami
2018/12/19
2.7K0
为什么MySQL没有负载,但交易却跑不动?
在MySQL的数据库中,我们有时会发现MySQL数据库明明没有负载,CPU、硬盘、内存和网络等资源都很空闲,但很多SQL都pending在哪儿,MySQL数据库无法处理交易。这是怎么回事呢?
姚远OracleACE
2023/11/01
3390
为什么MySQL没有负载,但交易却跑不动?
Mysql 数据库 超时和锁定
昨天项目中遇到部分服务一直是pending状态,排查了代码和重启了服务都没能解决问题,于是从数据库开始排查。
chuchur
2022/10/25
5.2K0
MySQL8.0锁情况排查
在数据库中,除传统的计算资源(CPU、RAM、IO)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度来说,锁对教据库而言显得尤其重要,也更加复杂。
GreatSQL社区
2023/02/22
2.2K0
MySQL找出未提交事务的信息
我们经常会碰到这样的情况,某个事务执行完了未提交,后续再来一个DDL和DML操作,导致后面的session要么处于waiting for metadata lock,要么是锁等待超时。这时我们往往只能找到这个未提交的事务的事务id和session id,但是一般都处于sleep状态,不好分析事务内容到底是什么,所以通常都是粗鲁地kill这个session后解决问题,但是应用层的研发人员往往找不到到底是哪个事务引起的,后面再出现问题时还要重复kill。
用户1148526
2020/03/31
5.2K0
查看Mysql正在执行的事务、锁、等待
EXPLAIN命令,用于显示SQL语句的查询执行计划。EXPLAIN为用于SELECT语句中的每个表返回一行信息。
wuweixiang
2019/03/12
17.7K0
MySQL的innoDB锁机制以及死锁处理
InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION);二是采用了行级锁。行级锁与表级锁本来就有许多不同之处,innodb正常的select ID from table where id=1;不会上任何锁,接下来详细讨论InnoDB的锁问题;
星哥玩云
2022/08/16
9840
MySQL的innoDB锁机制以及死锁处理
应用示例荟萃 | performance_schema全方位介绍(上)
经过前面6个篇幅的学习,相信大家对什么是performance_schema,已经初步形成了一个整体认识,但我想很多同行看完之前的文章之后可能还是一脸懵逼,今天就为大家带来performance_schema系列的最后一个篇章(全系共7个篇章),在这一期里,我们将为大家列举数十个performance_schema应用示例。下面,请跟随我们一起开始performance_schema系统的学习之旅吧。
老叶茶馆
2020/11/26
5910
[转载]评估某个SQL回滚需要的耗时
原文地址  https://mydbops.wordpress.com/2022/02/07/estimating-time-for-rollback-operation/
保持热爱奔赴山海
2023/05/01
3700
innodb锁机制探究(一)
在之前的文章中,我们说过三次关于锁的文章,分别是去年的12月25号、12月26号以及今年的1月14号的文章,这3篇文章里面简单介绍过一些锁的知识点,后续我们将详细介绍MySQL里面的锁,但是不能保证每天更新,所以把题目做成一个系列标签,如果有时间我做下归类整理。
AsiaYe
2019/11/06
3600
应用示例荟萃 | performance_schema全方位介绍(下)
使用performance_schema中的语句当前事件记录表和语句事件历史记录表可以查询数据库中最近执行的一些SQL语句,以及语句相关的信息,这里我们以events_statements_history表为例,查询结果按照语句完成时间倒序排序,如下:
沃趣科技
2018/07/02
2.3K0
应用示例荟萃 | performance_schema全方位介绍(下)
浅析MySQL存储引擎序列属性
墨墨导读:为了达到标识的目的,许多应用程序需要生成唯一编号,比如:商品编号、交易流水号等。MySQL数据库同样能够支持这样的需求场景,AUTO_INCREMENT就是为MySQL实现序列的方式,它会自动生成序列编号。
数据和云
2020/09/14
1.6K0
MySQL底层概述—10.InnoDB锁机制
undo log版本链 + Read View机制实现的MVCC多版本并发控制,可以防止事务并发读写同一数据时出现的脏读+不可重复读+幻读问题。但除脏读+不可重复读+幻读问题外,并发读写同一数据还有脏写问题。就是当多个事务并发更新同一条数据时,此时就可能会出现脏写问题,如下图示:
东阳马生架构
2025/02/14
3030
[MYSQL] show engine innodb status中的死锁 分析
很久以前(也才2年)写过一个解析innodb_status的脚本. 看起来像那么回事, 其实就是做了个翻译和总结.
大大刺猬
2024/08/26
7990
[MYSQL] show engine innodb status中的死锁 分析
MySQL-长事务详解
『入门MySQL』系列文章已经完结,今后我的文章还是会以MySQL为主,主要记录下近期工作及学习遇到的场景或者自己的感悟想法,可能后续的文章不是那么连贯,但还是希望大家多多支持。言归正传,本篇文章主要介绍MySQL长事务相关内容,比如说我们开启的一个事务,一直没提交或回滚会怎样呢,出现事务等待情况应该如何处理,本篇文章将给你答案。
MySQL技术
2019/09/23
3.4K0
相关推荐
应用示例荟萃 | performance_schema全方位介绍(中)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档