22后悔了怎么办 —— undo 日志
undo 日志标签: MySQL 是怎样运行的
事务回滚的需求我们说过事务需要保证原子性,也就是事务中的操作要么全部完成,要么什么也不做。但是偏偏有些时候做到一半的时候会出一些情况,比如:
情况一:事务执行过程中可能遇到各种错误,比如服务器本身的错误,操作系统错误,甚至是突然断电导致的错误。
情况二:程序员可以在事务执行过程中手动输入ROLLBACK语句结束当前的事务的执行。
这两种情况都会导致事务执行到一半就结束,但是事务执行过程中可能已经修改了很多东西,为了保证事务的原子性,我们需要把东西改回原先的样子,这个过程就称之为回滚(英文名:rollback),这样就可以造成一个假象:这个事务看起来什么都没做,所以符合原子性要求。
小时候我非常痴迷于象棋,总是想找厉害的大人下棋,赢棋是不可能赢棋的,这辈子都不可能赢棋的,又不想认输,只能偷偷的悔棋才能勉强玩的下去。悔棋就是一种非常典型的回滚操作,比如棋子往前走两步,悔棋对应的操作就是向后走两步;比如棋子往左走一步,悔棋对应的操作就是向右走一步。数据库中的回滚跟悔棋差不多,你插入了一条记录,回滚操作对应的就是把这条记录删除掉;你更新 ...
21说过的话就一定要办到 —— redo 日志(下)
redo 日志(下)标签: MySQL 是怎样运行的
redo日志文件redo日志刷盘时机我们前边说mtr运行过程中产生的一组redo日志在mtr结束时会被复制到log buffer中,可是这些日志总在内存里呆着也不是个办法,在一些情况下它们会被刷新到磁盘里,比如:
log buffer空间不足时
log buffer的大小是有限的(通过系统变量innodb_log_buffer_size指定),如果不停的往这个有限大小的log buffer里塞入日志,很快它就会被填满。设计InnoDB的大叔认为如果当前写入log buffer的redo日志量已经占满了log buffer总容量的大约一半左右,就需要把这些日志刷新到磁盘上。
事务提交时
我们前边说过之所以使用redo日志主要是因为它占用的空间少,还是顺序写,在事务提交时可以不把修改过的Buffer Pool页面刷新到磁盘,但是为了保证持久性,必须要把修改这些页面对应的redo日志刷新到磁盘。
Force Log at Commit
后台线程不停的刷刷刷
后台有一个线程,大约每秒都会刷新一次log buf ...
20说过的话就一定要办到 —— redo 日志(上)
redo日志(上)标签: MySQL是怎样运行的
事先说明本文以及接下来的几篇文章将会频繁的使用到我们前边唠叨的InnoDB记录行格式、页面格式、索引原理、表空间的组成等各种基础知识,如果大家对这些东西理解的不透彻,那么阅读下边的文字可能会有些吃力,为保证您的阅读体验,请确保自己已经掌握了我前边唠叨的这些知识。
redo日志是个啥我们知道InnoDB存储引擎是以页为单位来管理存储空间的,我们进行的增删改查操作其实本质上都是在访问页面(包括读页面、写页面、创建新页面等操作)。我们前边唠叨Buffer Pool的时候说过,在真正访问页面之前,需要把在磁盘上的页缓存到内存中的Buffer Pool之后才可以访问。但是在唠叨事务的时候又强调过一个称之为持久性的特性,就是说对于一个已经提交的事务,在事务提交后即使系统发生了崩溃,这个事务对数据库中所做的更改也不能丢失。但是如果我们只在内存的Buffer Pool中修改了页面,假设在事务提交后突然发生了某个故障,导致内存中的数据都失效了,那么这个已经提交了的事务对数据库中所做的更改也就跟着丢失了,这是我们所不能忍受的(想想ATM机已经提示狗哥转账 ...
19从猫爷被杀说起 —— 事务简介
事务简介标签: MySQL 是怎样运行的
事务的起源对于大部分程序员来说,他们的任务就是把现实世界的业务场景映射到数据库世界。比如银行为了存储人们的账户信息会建立一个account表:
123456CREATE TABLE account ( id INT NOT NULL AUTO_INCREMENT COMMENT '自增id', name VARCHAR(100) COMMENT '客户名称', balance INT COMMENT '余额', PRIMARY KEY (id)) Engine=InnoDB CHARSET=utf8;
狗哥和猫爷是一对好基友,他们都到银行开一个账户,他们在现实世界中拥有的资产就会体现在数据库世界的account表中。比如现在狗哥有11元,猫爷只有2元,那么现实中的这个情况映射到数据库的account表就是这样:
123456+----+--------+---------+| id | name | balance |+----+--------+---- ...
18调节磁盘和CPU的矛盾 —— InnoDB 的 Buffer Pool
InnoDB 的 Buffer Pool标签: MySQL 是怎样运行的
缓存的重要性通过前边的唠叨我们知道,对于使用InnoDB作为存储引擎的表来说,不管是用于存储用户数据的索引(包括聚簇索引和二级索引),还是各种系统数据,都是以页的形式存放在表空间中的,而所谓的表空间只不过是InnoDB对文件系统上一个或几个实际文件的抽象,也就是说我们的数据说到底还是存储在磁盘上的。但是各位也都知道,磁盘的速度慢的跟乌龟一样,怎么能配得上“快如风,疾如电”的CPU呢?所以InnoDB存储引擎在处理客户端的请求时,当需要访问某个页的数据时,就会把完整的页的数据全部加载到内存中,也就是说即使我们只需要访问一个页的一条记录,那也需要先把整个页的数据加载到内存中。将整个页加载到内存中后就可以进行读写访问了,在进行完读写访问之后并不着急把该页对应的内存空间释放掉,而是将其缓存起来,这样将来有请求再次访问该页面时,就可以省去磁盘IO的开销了。
InnoDB的Buffer Pool啥是个Buffer Pool设计InnoDB的大叔为了缓存磁盘中的页,在MySQL服务器启动的时候就向操作系统申请了一片连续的内存 ...
17神兵利器 —— optimizer trace 的神器功效
otpimizer trace 表的神奇功效标签: MySQL 是怎样运行的
对于MySQL 5.6以及之前的版本来说,查询优化器就像是一个黑盒子一样,你只能通过EXPLAIN语句查看到最后优化器决定使用的执行计划,却无法知道它为什么做这个决策。这对于一部分喜欢刨根问底的小伙伴来说简直是灾难:“我就觉得使用其他的执行方案比EXPLAIN输出的这种方案强,凭什么优化器做的决定和我想的不一样呢?”
在MySQL 5.6以及之后的版本中,设计MySQL的大叔贴心的为这部分小伙伴提出了一个optimizer trace的功能,这个功能可以让我们方便的查看优化器生成执行计划的整个过程,这个功能的开启与关闭由系统变量optimizer_trace决定,我们看一下:
1234567mysql> SHOW VARIABLES LIKE 'optimizer_trace';+-----------------+--------------------------+| Variable_name | Value |+---------- ...
16查询优化的百科全书 —— Explain 详解(下)
Explain 详解(下)标签: MySQL 是怎样运行的
执行计划输出中各列详解本章紧接着上一节的内容,继续唠叨EXPLAIN语句输出的各个列的意思。
Extra顾名思义,Extra列是用来说明一些额外信息的,我们可以通过这些额外信息来更准确的理解MySQL到底将如何执行给定的查询语句。MySQL提供的额外信息有好几十个,我们就不一个一个介绍了(都介绍了感觉我们的文章就跟文档差不多了~),所以我们只挑一些平时常见的或者比较重要的额外信息介绍给大家哈。
No tables used
当查询语句的没有FROM子句时将会提示该额外信息,比如:
1234567mysql> EXPLAIN SELECT 1;+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+| id | select_type | table | partitions | type | possible_keys | ...
15查询优化的百科全书 —— Explain 详解(上)
Explain 详解(上)标签: MySQL 是怎样运行的
一条查询语句在经过MySQL查询优化器的各种基于成本和规则的优化会后生成一个所谓的执行计划,这个执行计划展示了接下来具体执行查询的方式,比如多表连接的顺序是什么,对于每个表采用什么访问方法来具体执行查询等等。设计MySQL的大叔贴心的为我们提供了EXPLAIN语句来帮助我们查看某个查询语句的具体执行计划,本章的内容就是为了帮助大家看懂EXPLAIN语句的各个输出项都是干嘛使的,从而可以有针对性的提升我们查询语句的性能。
如果我们想看看某个查询的执行计划的话,可以在具体的查询语句前边加一个EXPLAIN,就像这样:
1234567mysql> EXPLAIN SELECT 1;+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+| id | select_type | table | partitions | type | pos ...
14不好看就要多整容 —— MySQL 基于规则的优化(内含关于子查询优化二三事儿)
基于规则的优化标签: MySQL 是怎样运行的
大家别忘了MySQL本质上是一个软件,设计MySQL的大叔并不能要求使用这个软件的人个个都是数据库高高手,就像我写这本书的时候并不能要求各位在学之前就会了里边儿的知识。
1吐槽一下:都会了的人谁还看呢,难道是为了精神上受感化?
也就是说我们无法避免某些同学写一些执行起来十分耗费性能的语句。即使是这样,设计MySQL的大叔还是依据一些规则,竭尽全力的把这个很糟糕的语句转换成某种可以比较高效执行的形式,这个过程也可以被称作查询重写(就是人家觉得你写的语句不好,自己再重写一遍)。本章详细唠叨一下一些比较重要的重写规则。
条件化简我们编写的查询语句的搜索条件本质上是一个表达式,这些表达式可能比较繁杂,或者不能高效的执行,MySQL的查询优化器会为我们简化这些表达式。为了方便大家理解,我们后边举例子的时候都使用诸如a、b、c之类的简单字母代表某个表的列名。
移除不必要的括号有时候表达式里有许多无用的括号,比如这样:
1((a = 5 AND b = c) OR ((a > c) AND (c < 5)))
看着就很烦,优化器会把那些用 ...
13兵马未动,粮草先行 —— InnoDB 统计数据是如何收集的
InnoDB 统计数据是如何收集的标签: MySQL 是怎样运行的
我们前边唠叨查询成本的时候经常用到一些统计数据,比如通过SHOW TABLE STATUS可以看到关于表的统计数据,通过SHOW INDEX可以看到关于索引的统计数据,那么这些统计数据是怎么来的呢?它们是以什么方式收集的呢?本章将聚焦于InnoDB存储引擎的统计数据收集策略,看完本章大家就会明白为啥前边老说InnoDB的统计信息是不精确的估计值了(言下之意就是我们不打算介绍MyISAM存储引擎统计数据的收集和存储方式,有想了解的同学自己个儿看看文档哈)。
两种不同的统计数据存储方式InnoDB提供了两种存储统计数据的方式:
永久性的统计数据
这种统计数据存储在磁盘上,也就是服务器重启之后这些统计数据还在。
非永久性的统计数据
这种统计数据存储在内存中,当服务器关闭时这些这些统计数据就都被清除掉了,等到服务器重启之后,在某些适当的场景下才会重新收集这些统计数据。
设计MySQL的大叔们给我们提供了系统变量innodb_stats_persistent来控制到底采用哪种方式去存储统计数据。在MySQL 5 ...
