InnoDB

一条简单的更新语句,MySQL是如何加锁的?

和自甴很熟 提交于 2020-12-16 01:55:02
看如下一条sql语句: # table T (id int, name varchar(20)) delete from T where id = 10 ; MySQL在执行的过程中,是如何加锁呢? 再看下面这条语句: select * from T where id = 10 ; 那这条语句呢?其实这其中包含太多知识点了。要回答这两个问题,首先需要了解一些知识。 相关知识介绍 多版本并发控制 在MySQL默认存储引擎InnoDB中,实现的是基于多版本的并发控制协议——MVCC(Multi-Version Concurrency Control)(注:与MVVC相对的,是基于锁的并发控制,Lock-Based Concurrency Control)。其中MVCC最大的好处是:读不加锁,读写不冲突。 在读多写少的OLTP应用中,读写不冲突是非常重要的,极大的提高了系统的并发性能,在现阶段,几乎所有的RDBMS,都支持MVCC。其实,MVCC就一句话总结:同一份数据临时保存多个版本的一种方式,进而实现并发控制。 当前读和快照读 在MVCC并发控制中,读操作可以分为两类:快照读与当前读。 快照读(简单的select操作):读取的是记录中的可见版本(可能是历史版本),不用加锁。这你就知道第二个问题的答案了吧。 当前读(特殊的select操作、insert、delete和update)

「MySQL系列」存储引擎InnoDB结构和原理深入刨析

天涯浪子 提交于 2020-12-14 17:19:54
参考黑马架构课程。从InnoDB体系结构、逻辑存储结构、chekpoint、插入缓存、两次写、自适应hash索引、异步IO、刷新临时页、 InnoDB事务隔离级别、隔离级别实现对InnoDB刨析。 一 存储引擎体系 1.1 MySQL体系架构 上图描述 Connection Pool : 连接池组件 Management Services & Utilities : 管理服务和工具组件 SQL Interface : SQL接口组件 Parser : 查询分析器组件 Optimizer : 优化器组件 Caches & Buffers : 缓冲池组件 Pluggable Storage Engines : 存储引擎 File System : 文件系统 1. 连接层 最上层是一些客户端和链接服务,包含本地sock 通信和大多数基于客户端/服务端工具实现的类似于TCP/IP的通信。主要完成 一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程池的概念,为通过认证安全接入的客户端提供线程。 同样在该层上可以实现基于SSL的安全链接。服务器也会为安全接入的每个客户端验证它所具有的操作权限。 2. 服务层 第二层架构主要完成大多数的核心服务功能,如SQL接口,并完成缓存的查询,SQL的分析和优化,部分内置函数的执行。所有 跨存储引擎的功能也在这一层实现,如 过程、函数等

MySQL插入大批量数据时报错“The total number of locks exceeds the lock table size”的解决办法

末鹿安然 提交于 2020-12-14 07:33:13
事情的原因是:我执行了一个 load into 语句的SQL将一个很大的文件导入到我的MySQL数据库中,执行了一段时间后报错“The total number of locks exceeds the lock table size”。 首先使用命令 show variables like '%storage_engine%' 查看MySQL的存储引擎: mysql> show variables like '%storage_engine%'; +----------------------------------+--------+ | Variable_name | Value | +----------------------------------+--------+ | default_storage_engine | InnoDB | | default_tmp_storage_engine | InnoDB | | disabled_storage_engines | | | internal_tmp_disk_storage_engine | InnoDB | +----------------------------------+--------+ 4 rows in set, 1 warning (0.00 sec)

MySQL实战45讲学习笔记:第十二讲

馋奶兔 提交于 2020-12-14 01:22:49
一、引子 平时的工作中,不知道你有没有遇到过这样的场景,一条 SQL 语句,正常执行的时候特别快,但是有时也不知道怎么回事,它就会变得特别慢,并且这样的场景很难复现,它不只 随机,而且持续时间还很短。 看上去,这就像是数据库“抖”了一下。今天,我们就一起来看一看这是什么原因。 二、你的 SQL 语句为什么变“慢”了 在前面第 2 篇文章《日志系统:一条 SQL 更新语句是如何执行的?》中,我为你介绍了WAL 机制。现在你知道了,InnoDB 在处理更新语句的时候,只做了写日志这一个磁盘操 作。这个日志叫作 redo log(重做日志),也就是《孔乙己》里咸亨酒店掌柜用来记账的粉板,在更新内存写完 redo log 后,就返回给客户端,本次更新成功。 1、类比 1、类比 2、flush 3、脏页&干净页 不论是脏页还是干净页,都在内存中。在这个例子里,内存对应的就是掌柜的记忆。 2、孔乙己赊账的整个操作过程 接下来,我们用一个示意图来展示一下“孔乙己赊账”的整个操作过程。假设原来孔乙己欠账 10 文,这次又要赊 9 文。 图 1 “孔乙己赊账”更新和 flush 过程 回到文章开头的问题,你不难想象,平时执行很快的更新操作,其实就是在写内存和日志,而 MySQL 偶尔“抖”一下的那个瞬间,可能就是在刷脏页(flush)。 三、什么情况会引发数据库的 flush 过程呢? 那么

MySQL之索引--读书笔记

人走茶凉 提交于 2020-12-13 19:35:41
简单来说,索引的出现就是为了提高数据的查询效率,就像书的目录一样。 索引模型 哈希表:是一种以键值对存储数据的结构,只要输入待查找的值即key,就可以找到对应的值value。哈希表的思路是,把值放在数组里,用一个哈希函数把key换算成一个确定的位置,然后拉出一一个链表。有一个需要注意的是,哈希冲突的时候就拉出一个链表 好处是:新增数据非常快;缺点是:由于不是有序的,区间查询的速度是很慢的。 有序数组:有序数组在等职查询和范围查询的性能都非常优秀。但是在更新数据的时候就需要挪动数据,成本很高。 搜索树: 二叉搜索树:特点是每个节点的左儿子小于父节点,父节点又小于右儿子。 多叉树:每个节点有多个儿子,儿子之间的大小保证从左到右递增。 InnoDB的索引模型 在InnoDB中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称作索引组织表。 回表: 回到主键索引树的过程叫做回表。 覆盖索引: 在一个查询里面,索引k已经“覆盖了”我们的查询需求,我们称了“索引覆盖”。 最左前缀原则: 因为索引项是按照索引定义里面出现的字段顺序排序的 索引下推 : 5.6版本之后,可以在遍历过程中,对索引包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。 普通索引和唯一索引的选择: 查询的时候的性能差距是微乎其微的。 更新的时候,如果数据页在内存中就直接更新

MySQL之更新是如何执行的--读书笔记

不想你离开。 提交于 2020-12-13 19:35:29
通过上一篇文章,对MySQL的内部结构以及一条查询语句是如何执行的有了一个大概的认识。下面对MySQL的更新以及两个日志文件进行总结。 如图: 以上是一张MySQL更新的执行示意图。这张图较好地解释了一条sql是如何执行的。下面先对图中比较陌生的元素 redo log 和 binlog 进行介绍。 redo log: 翻译过来就是重做日志,是Innodb存储引擎特有的(Innodb原先是另外一家公司以插件形式加入到MySQL中),它是物理日志,只有Indobd能使用,记录的是“在某个数据页上做了什么修改”。它是一个环形,说明它是有固定大小的,从头写到末尾就要擦出一部分之后才能继续写。这边有一个 WAL 技术,后面再做详情介绍。 binlog: 翻译过来就是归档日志,在MySQL的server层,所以是所有存储引擎都共有的,它是逻辑日志,可以给别的数据库,引擎使用,记录的是这个语句的原始逻辑,如“给id=1的这一行的某个字段+1”。它不是环形,它是一直追加写入的,不会覆盖以前的日志。 WAL 技术: Wirte-Ahead logging,直译就是“先写日志”。为什么要先写日志呢?在MySQL中,我们的数据页有可能在内存中,也有可能在磁盘中,如果我们每次更新都去写磁盘,那么MySQL的更新操作的效率会很低。并且写日志时按照顺序写,可以以组的方式提交

【MySQL 读书笔记】当我们在使用索引的时候我们在做什么

微笑、不失礼 提交于 2020-12-13 19:35:10
我记得之前博客我也写过关于索引使用的文章,但是并不全面,这次尽量针对重点铺全面一点。 因为索引是数据引擎层的结构我们只针对最常见使用的 Innodb 使用的 B+Tree 搜索树结构进行介绍。 每一个在 InnoDB 的中的索引都对应一颗 B+Tree。举个栗子: 创建这样一个表,并且在字段 k 上创建索引 mysql> create table T( id int primary key, k int not null, name varchar( 16 ), index (k))engine =InnoDB; 这个时候我们插入值 (100,1)、(200,2)、(300,3)、(500,5) 和 (600,6) 这个时候主键的聚簇索引对应一颗树,然后 k 索引值对应一棵树。 基于 Innodb 引擎的特性,一个表只能有一个聚簇索引,聚簇索引上面会记录所有表字段的有序的信息。普通二级索引上面只有该索引字段和主键索引字段的对应信息。(如果可以看得比较明确)。当我们使用语句 select * from xxx where k = x 的时候,我们使用了二级索引。并且由于在二级索引上面没有索引覆盖到 name 字段,所以我们需要在二级索引里面拿到 id = x 的值然后再去聚簇索引树中搜索对应的 name 记录。这个过程被称作回表。 在频繁查询大表特别是字段非常多的表的时候

【MySQL 读书笔记】当我们在执行更新语句的时候我们在做什么

感情迁移 提交于 2020-12-13 16:35:50
该篇其实重点涉及两个日志的使用和处理。 一个是 server 层的 binlog 一个是服务器层的 redolog。 首先还是根据主线来介绍当我们在执行更新语句的时候我们在做什么 Redo Log MySQL 使用一种叫 WAL(Write-Ahead Logging) 的技术,它达到的效果是,先写日志后写磁盘。 在计算机科学中,预写式日志( Write - ahead logging ,縮寫 WAL )是关系数据库系统中用于提供原子性和持久性(ACID属性中的两个)的一系列技术。 在使用 WAL 的系统中,所有的修改在提交之前都要先写入 log 文件中。 在 MySQL 中,我们在执行一条更新语句的时候会先将记录写到 redo log 里面并更新内存,这个时候更新就算完成了。之后 InnoDB 会在适当的时候把这个操作记录更新到磁盘里面。(多提一嘴,后面会介绍,其实在更新之前还写了 undo log)redo log 在刷新之前会被记录到 buffer 中,这个 buffer 大小由 MySQL 参数 Innodb_log_buffer 控制,默认大小是 8M。 之后会通过三种方式刷新到磁盘: 1,Master Thread 每秒一次执行刷新Innodb_log_buffer到重做日志文件。 2,每个事务提交时会将重做日志刷新到重做日志文件。 3,当重做日志缓存可用空间少于一半时

MySQL Memory--内存分配相关参数

限于喜欢 提交于 2020-12-13 14:42:30
Seesion级的内存分配: max_threads(当前活跃连接数) * ( read_buffer_size(顺序读缓冲,提高顺序读效率) + read_rnd_buffer_size(随机读缓冲,提高随机读效率) + sort_buffer_size(排序缓冲,提高排序效率) + join_buffer_size(表连接缓冲,提高表连接效率) + binlog_cache_size(二进制日志缓冲,提高二进制日志写入效率) + tmp_table_size(内存临时表,提高临时表存储效率) + thread_stack(线程堆栈,暂时寄存SQL语句 / 存储过程) + thread_cache_size(线程缓存,降低多次反复打开线程开销) + net_buffer_length(线程持连接缓冲以及读取结果缓冲) + bulk_insert_buffer_size(MyISAM表批量写入数据缓冲) ) global级的内存分配: global buffer(全局内存分配总和) = innodb_buffer_pool_size(InnoDB高速缓冲,行数据、索引缓冲,以及事务锁、自适应哈希等) +   innodb_additional_mem_pool_size(InnoDB数据字典额外内存,缓存所有表数据字典) +   innodb_log_buffer_size

MySQL解决[Err] 1206

蹲街弑〆低调 提交于 2020-12-13 02:56:08
MySQL解决[Err] 1206 - The total number of locks exceeds the lock table size问题 查看MySQL版本:mysql>show version(); 解决标题中的问题:修改innodb_buffer_pool_size的大小。 1、查看当前innodb_buffer_pool_size的大小:mysql>show variables like '%innodb_buffer_pool_size%'; 一般默认为134217728,即128MB。 2、修改innodb_buffer_pool_size,尝试:mysql>set innodb_buffer_pool_size=2,147,483,648; 尝试修改为2GB,失败,提示:ERROR 1238 (HY000): Variable 'innodb_buffer_pool_size' is a read only variable 3、换一种方式,修改my.cnf (1)查找my.cnf位置:tom@ubuntu: sudo find / -name 'my.cnf' 2>1 2>1.附:ls a.txt b.txt 1>file.out 2>file.out 这样写的话你没考虑stdout和stderr的缓冲。 stdout是行缓冲的