一、为什么MySQL不建议使用NULL作为默认值
Preference:
NULL是对列的特殊约束,它与 “” (空)不一样,NULL并不意味着什么都没有,mysql中对于null的操作有三个:
IS NULL && IS NOT NULL
<=>
,select NULL<=>NULL
可以返回true
,但是select NULL=NULL
返回false
.
IFNULL
一个函数,判断第一个表达式是否为 NULL,如果为 NULL 则返回第二个参数的值,如果不为 NULL 则返回第一个参数的值。
Context:
NULL
通过任一操作符与其它值比较都会得到NULL
,除了<=>
- NULL代表一个不确定的值,就算是两个NULL,它俩也不一定相等
- 使用
count(*)
或者count(null column)
结果不同,count(null column)
<=count(*)
.,也就是说单独count某一列的时候,值为null的行是不会被计数的- 虽然
select NULL=NULL
的结果为false
,但是在我们使用distinct
,group by
,order by
时,NULL
又被认为是相同值
.
MySQL中支持在含有NULL
值的列上使用索引,但是Oracle
不支持.这就是我们平时所说的如果列上含有NULL
那么将会使索引失效。但是这也不是十分准确的结论。
Summary:
- 对含有NULL值的列进行统计计算,eg.
count()
,max()
,min()
,结果并不符合我们的期望值.- 干扰排序,分组,去重结果
- 有的时候为了消除
NULL
带来的技术债务,我们需要在SQL中使用IFNULL()
来确保结果可控,但是这使程序变得复杂NULL
值并不是占用原有的字段空间存储,而是额外申请一个字节去标注,这个字段添加了NULL
约束.(就像额外的标志位一样)
二、MySQL事务
1、什么是事务
事务(Transaction)是一个操作序列,不可分割的工作单位,以BEGIN TRANSACTION开始,以ROLLBACK/COMMIT结束
比如银行转账操作,就必须是一个事务,将扣钱加钱和其中的计算过程囊括成一个整体,要么全部成功,要么全部失败。
在MySQL中,事务支持是在引擎层实现的。MySQL是一个支持多引擎的系统,但并不是所有的引擎都支持事务。
比如MySQL原生的MyISAM
引擎就不支持事务,这也是MyISAM被InnoDB
取代的重要原因之一。
2、隔离性与隔离级别
事务4要素:ACID
- 原子性 Atomicity:
逻辑上是不可分割的操作单元,事务的所有操作要么全部提交成功,要么全部失败回滚(用回滚日志实现,反向执行日志中的操作);
- 一致性 Consistency:
事务的执行必须使数据库保持一致性状态。在一致性状态下,所有事务对一个数据的读取结果都是相同的;
- 隔离性 Isolation:
一个事务所做的修改在最终提交以前,对其它事务是不可见的(并发执行的事务之间不能相互影响);
- 持久性 Durability:
一旦事务提交成功,对数据的修改是永久性的
会出现的并发性问题:
当多个事务一起执行时,就有可能出现
- 丢失修改:
一个事务对数据进行了修改,在事务提交之前,另一个事务对同一个数据进行了修改,覆盖了之前的修改;
- 脏读(dirty read)
一个事务读到另一个事务没有提交(进行了回滚)的数据。事务A修改了一个数据,但未提交,事务B读到了事务A未提交的更新结果,事务B读到的就是脏数据
- 不可重复读(non-repeatable read)
在同一个事务中,某查询操作在一个时间读取某一行数据和之后一个时间读取该行数据,发现数据已经发生修改(针对update delete操作)这种情况归为 不可重复读;
- 幻读(phantom read)
当同一查询多次执行时,由于其它事务在这个数据范围内执行了插入操作,会导致每次返回不同的结果集(和不可重复读的区别:针对的是一个数据整体/范围;并且针对insert操作)
隔离级别
为了解决这些问题就有了隔离级别的概念
隔离级别越高,效率就越低,因此很多情况下需要在二者之间找到一个平衡点。
SQL标准的隔离级别有:
未提交读:在一个事务提交之前,它的执行结果对其它事务也是可见的。会导致脏读、不可重复读、幻读;
读已提交:一个事务只能看见已经提交的事务所作的改变。可避免脏读问题
可重复读:同个事务中多次查询结果是一致的,可以确保同一个事务在多次读取同样的数据时得到相同的结果。(MySQL的默认隔离级别)。可避免不可重复读;可重复读的核心就是一致性读;
串行化:顾名思义是对于同一行记录,
写
会加写锁
,读
会加读锁
。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。强制事务串行执行,使之不可能相互冲突,从而解决幻读问题。
在实现上,数据库里面会创建一个视图,访问的时候以视图的逻辑结果为准。在可重复读隔离级别下,这个视图是在事务启动时创建的,整个事务存在期间都用这个视图。
在读提交隔离级别下,这个视图是在每个SQL语句开始执行的时候创建的。这里需要注意的是,读未提交隔离级别下直接返回记录上的最新值,没有视图概念;而串行化隔离级别下直接用加锁的方式来避免并行访问。
3、事务隔离的实现
在MySQL中,实际上每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值,通过回滚操作,都可以得到前一个状态的值。
假设一个值从1被按顺序改成了2、3、4,在回滚日志里面就会有类似下面的记录。
可以看到当前值是4,从图中可以看到在查询的时候,不同时刻启动的事务会有不同的read-view
。如图中看到的,在视图A
、B
、C
里面,这一个记录的值分别是1、2、4,同一条记录在系统中可以存在多个版本,就是数据库的多版本并发控制(MVCC)。
对于read-view A,要得到1,就必须将当前值依次执行图中所有的回滚操作得到。同时你会发现,即使现在有另外一个事务正在将4改成5,这个事务跟read-view A、B、C对应的事务是不会冲突的。
回滚日志在不需要的时候才删除。系统会判断,当没有事务再需要用到这些回滚日志时,回滚日志会被删除。
那么什么时候才不需要了呢?就是当系统里没有比这个回滚日志更早的read-view
的时候。
所以为什么尽量不要使用长事务?
长事务意味着系统里面会存在很老的事务视图。由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就会导致大量占用存储空间。
在MySQL 5.5
及以前的版本,回滚日志是跟数据字典一起放在ibdata
文件里的,即使长事务最终提交,回滚段被清理,文件也不会变小
除了对回滚段的影响,长事务还占用锁资源,也可能拖垮整个库
4、启动事务
-
显式启动事务语句(推荐),
begin
或start transaction
。配套的提交语句是commit
,回滚语句是rollback
。 -
set autocommit=0
,这个命令会将这个线程的自动提交关掉。意味着如果你只执行一个select
语句,这个事务就启动了,而且并不会自动提交。这个事务持续存在直到你主动执行commit
或rollback
语句,或者断开连接
在显示启动事务的情况下,可以用commit work and chain 来提交事务并自动开启下一个事务。
可以在
information_schema
库的innodb_trx
这个表中查询长事务,比如下面这个语句,用于查找持续时间超过60s
的事务。
5、MVCC工作原理
可重复读隔离级别下,事务在启动的时候就“拍了个快照”,但是它与实际的拷贝并不相同
这个“快照”如何实现?
在innodb里,每个事务都有一个一个id,叫 transaction id,它是在事务开始时向innodb事务系统申请的,是按申请顺序严格递增的。
每次事务更新数据的时候,都会生成一个新的数据版本,并且把transaction id
赋值给这个数据版本的事务ID
,记为row trx_id
。同时,旧的数据版本要保留,并且在新的数据版本中,能够有信息可以直接拿到它。这也说明了,数据表中的一行记录,可能存在多个版本(row
),每个版本有自己的row_trx_id
.
如下图所示
图中V4是最新版本,它被事务id为25的事务更新,所以V4的 row_trx_id 也是25
那么 undo.log 在哪呢?
图中V1、V2、V3,V4就是undo.log,V4、V3、V2都是在需要被调用时根据当前版本和undo log计算出来的
明白了多版本和row trx_id的概念后,我们再来想一下,InnoDB是怎么定义那个快照的。
按照可重复读的定义,一个事务启动的时候,能够看到所有已经提交的事务结果。但是之后,这个事务执行期间,其他事务的更新对它不可见。
因此,一个事务只需要在启动的时候声明说,以我启动的时刻为准,如果一个数据版本是在我启动之前生成的,就认;如果是我启动以后才生成的,我就不认,我必须要找到它的上一个版本。
当然,如果“上一个版本”也不可见,那就得继续往前找。还有,如果是这个事务自己更新的数据,它自己还是要认的。在实现上, InnoDB为每个事务构造了一个数组,用来保存这个事务启动瞬间,当前正在“活跃”的所有事务ID。“活跃”指的就是:启动了但还没提交。
数组里面事务ID的最小值记为低水位,当前系统里面已经创建过的事务ID的最大值加1记为高水位。
这个视图数组和高水位,就组成了当前事务的一致性视图(read-view)。而数据版本的可见性规则,就是基于数据的row trx_id和这个一致性视图的对比结果得到的。这个视图数组把所有的row trx_id 分成了几种不同的情况。如下图所示
对于当前事务的启动瞬间来说,一个数据版本的row trx_id,有以下几种可能:
-
如果落在绿色部分,表示这个版本是已提交的事务或者是当前事务自己生成的,这个数据是可见的;
-
如果落在灰色部分,表示这个版本是由将来启动的事务生成的,是肯定不可见的;
-
如果落在粉色部分,那就包括两种情况
-
(a) 若 row trx_id在数组中,表示这个版本是由还没提交的事务生成的,不可见;
-
(b) 若 row trx_id不在数组中,表示这个版本是已经提交了的事务生成的,可见。
-
后面针对例子具体分析请看原文:
三、Waking-Up/Database.md at master · wolverinn/Waking-Up (github.com)
什么是乐观锁、悲观锁?
- 悲观锁:认为数据随时会被修改,因此每次读取数据之前都会上锁,防止其它事务读取或修改数据;应用于数据更新比较频繁的场景;
- 乐观锁:操作数据时不会上锁,但是更新时会判断在此期间有没有别的事务更新这个数据,若被更新过,则失败重试;适用于读多写少的场景。乐观锁的实现方式有:
- 加一个版本号或者时间戳字段,每次数据更新时同时更新这个字段;
- 先读取想要更新的字段或者所有字段,更新的时候比较一下,只有字段没有变化才进行更新
常见的封锁类型?
意向锁是 InnoDB 自动加的, 不需用户干预。 对于 UPDATE、 DELETE 和 INSERT 语句, InnoDB 会自动给涉及数据集加排他锁(X); 对于普通 SELECT 语句,InnoDB 不会加任何锁; 事务可以通过以下语句显式给记录集加共享锁或排他锁: 共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE。 其他 session 仍然可以查询记录,并也可以对该记录加 share mode 的共享锁。但是如果当前事务需要对该记录进行更新操作,则很有可能造成死锁。 排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE。其他 session 可以查询该记录,但是不能对该记录加共享锁或排他锁,而是等待获得锁
- 排它锁(Exclusive Lock)/ X锁:事务对数据加上X锁时,只允许此事务读取和修改此数据,并且其它事务不能对该数据加任何锁;
- 共享锁(Shared Lock)/ S锁:加了S锁后,该事务只能对数据进行读取而不能修改,并且其它事务只能加S锁,不能加X锁
- 意向锁(Intention Locks):
- 一个事务在获得某个数据行对象的 S 锁之前,必须先获得整个表的 IS 锁或更强的锁;
- 一个事务在获得某个数据行对象的 X 锁之前,必须先获得整个表的 IX 锁;
- IS/IX 锁之间都是兼容的;
- 好处:如果一个事务想要对整个表加X锁,就需要先检测是否有其它事务对该表或者该表中的某一行加了锁,这种检测非常耗时。有了意向锁之后,只需要检测整个表是否存在IX/IS/X/S锁就行了
锁的作用:用于管理对共享资源的并发访问,保证数据库的完整性和一致性
封锁粒度的概念
MySQL 中提供了两种封锁粒度:行级锁以及表级锁。
封锁粒度小:
- 好处:锁定的数据量越少,发生锁争用的可能就越小,系统的并发程度就越高;
- 坏处:系统开销大(加锁、释放锁、检查锁的状态都需要消耗资源)
什么是三级封锁协议?
- 一级封锁协议:事务在修改数据之前必须先对其加X锁,直到事务结束才释放。可以解决丢失修改问题(两个事务不能同时对一个数据加X锁,避免了修改被覆盖);
- 二级封锁协议:在一级的基础上,事务在读取数据之前必须先加S锁,读完后释放。可以解决脏读问题(如果已经有事务在修改数据,就意味着已经加了X锁,此时想要读取数据的事务并不能加S锁,也就无法进行读取,避免了读取脏数据);
- 三级封锁协议:在二级的基础上,事务在读取数据之前必须先加S锁,直到事务结束才能释放。可以解决不可重复读问题(避免了在事务结束前其它事务对数据加X锁进行修改,保证了事务期间数据不会被其它事务更新)
什么是两段锁协议?
事务必须严格分为两个阶段对数据进行加锁和解锁的操作,第一阶段加锁,第二阶段解锁。也就是说一个事务中一旦释放了锁,就不能再申请新锁了。
可串行化调度是指,通过并发控制,使得并发执行的事务结果与某个串行执行的事务结果相同。事务遵循两段锁协议是保证可串行化调度的充分条件。
什么是 MVCC?
多版本并发控制(Multi-Version Concurrency Control, MVCC),MVCC在每行记录后面都保存有两个隐藏的列,用来存储创建版本号和删除版本号。
- 创建版本号:创建一个数据行时的事务版本号(事务版本号:事务开始时的系统版本号;系统版本号:每开始一个新的事务,系统版本号就会自动递增);
- 删除版本号:删除操作时的事务版本号;
- 各种操作:
- 插入操作时,记录创建版本号;
- 删除操作时,记录删除版本号;
- 更新操作时,先记录删除版本号,再新增一行记录创建版本号;
- 查询操作时,要符合以下条件才能被查询出来:删除版本号未定义或大于当前事务版本号(删除操作是在当前事务启动之后做的);创建版本号小于或等于当前事务版本号(创建操作是事务完成或者在事务启动之前完成)
通过版本号减少了锁的争用,提高了系统性能;可以实现提交读和可重复读两种隔离级别,未提交读无需使用MVCC
数据库的范式?
- 第一范式(1NF,Normal Form):属性不应该是可分的。举例:如果将“电话”作为一个属性(一列),是不符合1NF的,因为电话这个属性可以分解为家庭电话和移动电话...如果将“移动电话”作为一个属性,就符合1NF;
- 第二范式 2NF:每个非主属性完全依赖于主属性集(候选键集);
- B完全依赖于A,就是说A中的所有属性唯一决定B,属性少了就不能唯一决定,属性多了则有冗余(叫依赖不叫完全依赖)。举例:(学号,课程名)这个主属性集可以唯一决定成绩,但是对于学生姓名这个属性,(学号,课程名)这个属性集就是冗余的,所以学生姓名不完全依赖于(学号,课程名)这一属性集;
- 主属性集/候选码集:某一组属性能够唯一确定其它的属性(主键就是从候选键集中选的一个键),而其子集不能,这样的属性组中的属性就是主属性;不在候选码集中的属性成为非主属性;
- 可以通过分解来满足 2NF:将(学号,课程名,成绩)做成一张表;(学号,学生姓名)做成另一张表,避免大量的数据冗余; 满足1NF后,要求表中的所有列,都必须依赖于主键,而不能有任何一列与主键没有关系,也就是说一个表只描述一件事情;
- 第三范式 3NF:在 2NF 的基础上,非主属性不传递依赖于主属性
- 传递依赖:如果C依赖于B,B依赖于A,那么C传递依赖于A;
- 3NF在2NF的基础上,消除了非主属性之间的依赖;比如一个表中,主属性有(学号),非主属性有(姓名,院系,院长名),可以看到院长名这个非主属性依赖于院系,传递依赖于学号。消除的办法是分解。 必须先满足第二范式(2NF),要求:表中的每一列只与主键直接相关而不是间接相关,(表中的每一列只能依赖于主键);
不符合范式会出现哪些异常?
- 冗余数据:某些同样的数据多次出现(如学生姓名);
- 修改异常:修改了一个记录中的信息,另一个记录中相同的信息却没有修改;
- 删除异常:删除一个信息,那么也会丢失其它信息(删除一个课程,丢失了一个学生的信息);
- 插入异常:无法插入(插入一个还没有课程信息的学生)
列举几种表连接方式?
- 内连接(Inner Join):仅将两个表中满足连接条件的行组合起来作为结果集
- 自然连接:只考虑属性相同的元组对;
- 等值连接:给定条件进行查询
- 外连接(Outer Join)
- 左连接:左边表的所有数据都有显示出来,右边的表数据只显示共同有的那部分,没有对应的部分补NULL;
- 右连接:和左连接相反;
- 全外连接(Full Outer Join):查询出左表和右表所有数据,但是去除两表的重复数据
- 交叉连接(Cross Join):返回两表的笛卡尔积(对于所含数据分别为m、n的表,返回m*n的结果)
什么是存储过程?有哪些优缺点?
存储过程是事先经过编译并存储在数据库中的一段SQL语句的集合。想要实现相应的功能时,只需要调用这个存储过程就行了(类似于函数,输入具有输出参数)。
优点:
- 预先编译,而不需要每次运行时编译,提高了数据库执行效率;
- 封装了一系列操作,对于一些数据交互比较多的操作,相比于单独执行SQL语句,可以减少网络通信量;
- 具有可复用性,减少了数据库开发的工作量;
- 安全性高,可以让没有权限的用户通过存储过程间接操作数据库;
- 更易于维护
缺点:
- 可移植性差,存储过程将应用程序绑定到了数据库上;
- 开发调试复杂:没有好的IDE;
- 修改复杂,需要重新编译,有时还需要更新程序中的代码以更新调用
Drop/Delete/Truncate的区别?
- Delete用来删除表的全部或者部分数据,执行delete之后,用户需要提交之后才会执行,会触发表上的DELETE触发器(包含一个OLD的虚拟表,可以只读访问被删除的数据),DELETE之后表结构还在,删除很慢,一行一行地删,因为会记录日志,可以利用日志还原数据;
- Truncate删除表中的所有数据,这个操作不能回滚,也不会触发这个表上的触发器。操作比DELETE快很多(直接把表drop掉,再创建一个新表,删除的数据不能找回)。如果表中有自增(AUTO_INCREMENT)列,则重置为1;
- Drop命令从数据库中删除表,所有的数据行,索引和约束都会被删除;不能回滚,不会触发触发器;
什么是视图?什么是游标?
- 视图:从数据库的基本表中通过查询选取出来的数据组成的虚拟表(数据库中存放视图的定义)。可以对其进行增/删/改/查等操作。视图是对若干张基本表的引用,一张虚表,查询语句执行的结果,不存储具体的数据(基本表数据发生了改变,视图也会跟着改变);可以跟基本表一样,进行增删改查操作(ps:增删改操作有条件限制);如连表查询产生的视图无法进行,对视图的增删改会影响原表的数据。好处:
- 通过只给用户访问视图的权限,保证数据的安全性;
- 简化复杂的SQL操作,隐藏数据的复杂性(比如复杂的连接);
- 游标(Cursor):用于定位在查询返回的结果集的特定行,以对特定行进行操作。使用游标可以方便地对结果集进行移动遍历,根据需要滚动或对浏览/修改任意行中的数据。主要用于交互式应用。
数据库索引的实现原理(B+树)
使用B树和B+树的比较
InnoDB的索引使用的是B+树实现,B+树对比B树的好处:
- IO次数少:B+树的中间结点只存放索引,数据都存在叶结点中,因此中间结点可以存更多的数据,让索引树更加矮胖;
- 范围查询效率更高:B树需要中序遍历整个树,只B+树需要遍历叶结点中的链表;
- 查询效率更加稳定:每次查询都需要从根结点到叶结点,路径长度相同,所以每次查询的效率都差不多
使用B树索引和哈希索引的比较
哈希索引能以 O(1) 时间进行查找,但是只支持精确查找,无法用于部分查找和范围查找,无法用于排序与分组;B树索引支持大于小于等于查找,范围查找。哈希索引遇到大量哈希值相等的情况后查找效率会降低。哈希索引不支持数据的排序。
使用索引的优点
- 大大加快了数据的检索速度;
- 可以显著减少查询中分组和排序的时间;
- 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性;
- 将随机 I/O 变为顺序 I/O(B+Tree 索引是有序的,会将相邻的数据都存储在一起)
缺点:建立和维护索引耗费时间空间,更新索引很慢。
哪些情况下索引会失效?
- 以“%(表示任意0个或多个字符)”开头的LIKE语句;
- OR语句前后没有同时使用索引;
- 数据类型出现隐式转化(如varchar不加单引号的话可能会自动转换为int型);
- 对于多列索引,必须满足 最左匹配原则/最左前缀原则 (最左优先,eg:多列索引col1、col2和col3,则 索引生效的情形包括 col1或col1,col2或col1,col2,col3);
- 如果MySQL估计全表扫描比索引快,则不使用索引(比如非常小的表)
在哪些地方适合创建索引?
- 某列经常作为最大最小值;
- 经常被查询的字段;
- 经常用作表连接的字段;
- 经常出现在ORDER BY/GROUP BY/DISDINCT后面的字段
创建索引时需要注意什么
- 只应建立在小字段上,而不要对大文本或图片建立索引(一页存储的数据越多一次IO操作获取的数据越大效率越高);
- 建立索引的字段应该非空,在MySQL中,含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较运算更加复杂。应该用0、一个特殊的值或者一个空串代替NULL;
- 选择数据密度大(唯一值占总数的百分比很大)的字段作索引
索引的分类?
- 普通索引
- 唯一索引 UNIQUE:索引列的值必须唯一,但允许有空值;
- 主键索引 PRIMARY KEY:必须唯一,不允许空值(是一种特殊的唯一索引;MySQL创建主键时默认为聚集索引,但主键也可以是非聚集索引);
- 单列索引和多列索引/复合索引(Composite):索引的列数;
- 覆盖(Covering)索引:索引包含了所有满足查询所需要的数据,查询的时候只需要读取索引而不需要回表读取数据;
- 聚集(Clustered)索引/非聚集索引:对磁盘上存放数据的物理地址重新组织以使这些数据按照指定规则排序的一种索引(数据的物理排列顺序和索引排列顺序一致)。因此每张表只能创建一个聚集索引(因为要改变物理存储顺序)。优点是查询速度快,因为可以直接按照顺序得到需要数据的物理地址。缺点是进行修改的速度较慢。对于需要经常搜索范围的值很有效。非聚集索引只记录逻辑顺序,并不改变物理顺序;
- 分区索引(?)
- 虚拟索引(Virtual):模拟索引的存在而不用真正创建一个索引,用于快速测试创建索引对执行计划的影响。没有相关的索引段,不增加存储空间的使用
MySQL的两种存储引擎 InnoDB 和 MyISAM 的区别?
- InnoDB支持事务,可以进行Commit和Rollback;
- MyISAM 只支持表级锁,而 InnoDB 还支持行级锁,提高了并发操作的性能;
- InnoDB 支持外键;
- MyISAM 崩溃后发生损坏的概率比 InnoDB 高很多,而且恢复的速度也更慢;
- MyISAM 支持压缩表和空间数据索引,InnoDB需要更多的内存和存储;
- InnoDB 支持在线热备份
- MyISAM 管理非事务表。它提供高速存储和检索(MyISAM强调的是性能,每次查询具有原子性,其执行速度比InnoDB更快),以及全文搜索能力。如果表比较小,或者是只读数据(有大量的SELECT),还是可以使用MyISAM;
- InnoDB 支持事务,并发情况下有很好的性能,基本可以替代MyISAM
热备份和冷备份
- 热备份:在数据库运行的情况下备份的方法。优点:可按表或用户备份,备份时数据库仍可使用,可恢复至任一时间点。但是不能出错
- 冷备份:数据库正常关闭后,将关键性文件复制到另一位置的备份方式。优点:操作简单快速,恢复简单
更详细的可以参考:MySQL 数据库的存储引擎与适用场景 - Images
如何优化数据库?
Waking-Up/Database.md at master · wolverinn/Waking-Up · GitHub
什么是主从复制?实现原理是什么?
主从复制(Replication)是指数据可以从一个MySQL数据库主服务器复制到一个或多个从服务器,从服务器可以复制主服务器中的所有数据库或者特定的数据库,或者特定的表。默认采用异步模式。
实现原理:
- 主服务器 binary log dump 线程:将主服务器中的数据更改(增删改)日志写入 Binary log 中;
- 从服务器 I/O 线程:负责从主服务器读取binary log,并写入本地的 Relay log;
- 从服务器 SQL 线程:负责读取 Relay log,解析出主服务器已经执行的数据更改,并在从服务器中重新执行(Replay),保证主从数据的一致性