MySQL服务端采用线程池维护客户端链接mysql
分析查询语句,生成解析树,并将解析结果放入缓存中sql
优化包括选择合适的索引,数据的读取方式,分析语句执行的开销以及统计信息,优化器能够和存储引擎直接交互,尽管看起来彷佛没必要要。数据库
执行查询语句,返回结果缓存
缓存SQL解析器解析后的结果bash
粒度服务器
死锁的简单例子:两个transaction同时开始执行,它们分别开始执行第一条update的语句时,便锁住了对方的资源,你拿着个人资源不放,我拿着你的资源不放,最后二人都僵持着,当事人事不关己高高挂起,旁观者疾呼:死锁!微信
# transaction 1 START TRANSACTION; UPDATE USER SET NAME='Bob' WHERE ID=1; # sleep for some time; UPDATE USER SET NAME='Jack' WHERE ID=2; COMMIT;
# transaction 2 START TRANSACTION; UPDATE USER SET NAME='Bob' WHERE ID=2; # sleep for some time UPDATE USER SET NAME='Jack' WHERE ID=1; COMMIT;
隐式锁定就是系统自动加锁而不是人为的添加锁,显示锁定就是人为的添加锁,好比lock tables或者unlock tables。架构
事务的特色由存储引擎决定,是MySQL与其它数据库的不一样。
不支持事务的存储引擎有:并发
MySQL中的表按是否支持事务,分为:事务型表和非事务型表。
非事务型表没有commit或者rollback的概念。dom
SET AUTOCOMMIT=OFF;
或者
SET AUTOCOMMIT=0;
能设置当前链接是不是自动提交的。不过对非事务型表没有做用。
ACID属性
隔离级别
查询和设置隔离级别:
# 查询系统默认隔离级别,当前会话隔离级别 select @@global.tx_isolation,@@tx_isolation; # 设置系统隔离级别: SET global transaction isolation level read committed; # 设置会话隔离级别: SET SESSION transaction isolation LEVEL read committed;
复制意味着一份数据能够有多个副本,一个数据库中的数据,能够复制至另外一个数据库。
复制在咱们的生活中无处不在,同一份数据,有可能在你我的的电脑上有一份,U盘上有一份,云端的网盘上也可能会有一份。甚至在我的电脑里,一样一份数据也会有多个副本。
这里,咱们之因此会将数据复制出多份,目的是显而易见的:备份。
当你抱着本身的电脑准备接上投影仪,准备向老板展现你苦战数个通宵后的PPT时,硬盘忽然坏了,或者文件误删,莫名其妙的找不到了,不要紧,你的U盘还有一份。什么!U盘忘了带了?不要紧,你的网盘里还有一个。
复制与备份的是两件不一样的事情,能够经过复制来实现备份的目的。可是,复制的却不仅是能提供备份而已。
在MySQL中,复制能够解决几个问题:
若是大家公司的数据中心位于全国各地,经过复制,能够实现异地备份,但异地的数据同步会有较大的时间延迟。
同时,若是主数据库的数据都同步复制至从库,那么当须要更新数据时,只须要更新主库便可,新更新的数据将会经过主库同步至从库,在这个基础上,即可以实现读写分离,即DML语句在主库上执行,而查询类SQL语句则在从库上执行,因为主从的同步有时延,所以这里的数据一致性模型并不知足强一致性,是最终一致性模型。
由于有了主从副本,因此当主库不可用(宕机,崩溃等缘由),从库能够临危受命,升级为主库,保证数据库服务的高可用性。
分为3个步骤
主库在每次事务准备提交前,按照事务的提交顺序,将更新事件记录到binary log中,并通知存储引擎提交事务。而后,从库会主动启动一个线程与主库创建链接,与此对应,主库会启动一个二进制转储(binlog dump)线程与之合做,将binary log发送给从库,从库接收并产生relay log,而后由从库的一个SQL线程负责将relay log还原为数据。
须要注意的是,从库在relay时,是单线程执行,换言之,串行执行的。
经过在my.cnf中添加一个配置项log-bin,来起用master的二进制日志记录功能,若是没有配置log-bin,那么master的二进制记录功能并不会起用,log-bin在这里有两个做用
另外,须要在my.cnf中添加一个server-id配置项,用来指定master的惟一ID,范围能够是1到2^32-1。
[mysqld] # Replication Configurations(by beanlam) server-id=1 log-bin=bin-log
配置完成后须要重启mysql server。
一样,slave也须要配置一个惟一的server-id,不容许跟master的server-id冲突,若是有多个slave,各个slave与master的server-id都应该是不一样的。
slave也能够配置log-bin,配置了之后slave也能够和master同样,记录binary log。slave记录binary log有其用武之地的,好比数据备份和崩溃恢复,若当前的replication环境拓扑结构比较复杂,slave须要做为其它mysql server的master时,那么这个slave也必须启用binary log的功能。
[mysqld] # Replication Configurations(by beanlam) server-id=2
slave获取master的binary log时,经过用户名和密码与master创建链接,能够建立一个专用于复制的帐号,并只赋予这个帐号与复制有关的权限。
mysql> CREATE USER 'repl'@'%.mydomain.com' IDENTIFIED BY 'slavepass'; mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%.mydomain.com';
除了REPLICATION SLAVE权限,还能够给用户受权REPLICATION CLIENT权限,这样用户就能够用来监控和管理复制。
slave必须事先了解从master的二进制文件的哪一个位置开始复制,所以须要先记录master当前二进制日志的坐标,坐标由文件名和偏移量决定。
得到master的二进制日志坐标,须要先保证没有写操做在进行。在master上执行如下语句:
mysql> FLUSH TABLES WITH READ LOCK;
这个语句能为表得到读锁,阻止其它写入操做。须要注意,执行这个语句的会话若是关闭,那么这个锁将会被释放,若是会话没有关闭,那么锁会一直持有。
在另外一个会话里,用如下语句来查看master的二进制日志坐标
mysql> show master status; +----------------+----------+-------------------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +----------------+----------+-------------------------+------------------+-------------------+ | bin-log.000005 | 1264 | beanlam_db1,beanlam_db2 | | | +----------------+----------+-------------------------+------------------+-------------------+ 1 row in set (0.00 sec)
File和Position即代表了slave应该从何处开始进行复制。
若是master以前没有启用过二进制日志的功能,那么show master status
查询结果将为空。这时对于slave来讲,File是一个空字符串,Position是4,之因此是4,与二进制日志的文件格式有关。
根据以上步骤,获得了master二进制文件的坐标后,只须要告诉slave,slave即可以埋头进入复制的状态中。
这里根据master是否有旧数据须要同步,分为两种状况:
若是master是一个新的数据库服务器,其上没有任何旧的数据须要复制,那么就可使用change master to
命令为slave配置master的信息。
CHANGE MASTER TO MASTER_HOST='master_host_name', MASTER_USER='replication_user_name', MASTER_PASSWORD='replication_password', MASTER_LOG_FILE='recorded_log_file_name', MASTER_LOG_POS=recorded_log_position;
配置完后,能够经过start slave
命令正式开始进行复制。
能够经过mysqldump工具对当前master的数据库数据作一个快照,生成一个dump文件,在slave开始复制以前,把这个文件的数据导入slave中。
基本的使用方法:
mysqldump --all-databases --master-data > dbdump.db
-all-databases
代表为全部数据库做快照,也能够用--databases
来制定须要作快照的数据库。--ignore-table
能够跳过数据库中的全部表--master-data
会自动地在dump文件里加上change master to
语句,启动slave复制,若是不加这个选项,则须要先开启一个新的会话,对全部的表加读。
当存储引擎是InnoDB时,推荐使用mysqldump。
另一种方法是直接拷贝数据文件到slave。
基于语句的复制也称为(逻辑复制),slave把master上形成数据更改的SQL语句在本身的库上也执行一次。
master的binlog只记录SQL语句,使得日志文件体积更小。
master除了传输SQL语句给slave,还须要传输一些元数据,好比当前时间戳。
还有一些语句没法被正确复制,好比包含用户自定义函数的语句,这些函数可能有不肯定的行为。如下函数可能致使非正常的复制:
LOAD_FILE(), UUID(), UUID_SHORT(), USER(), FOUND_ROWS(), SYSDATE(), GET_LOCK(), IS_FREE_LOCK(), IS_USED_LOCK, MASTER_POS_WAIT, RAND(), RELEASE_LOCK(), SLEEP(), VERSION()
此外,INSERT......SELECT
语句须要获取更多的行级锁,比起基于行的复制来讲。UPDATE
语句可能致使全表扫描(where字句中没有包含索引字段)
若是使用的是InnoDB引擎,带有auto_increment
的insert
语句会堵塞其它非冲突的insert
语句。
slave上的更新是串行的,所以须要更多的锁。另外,并非全部的存储引擎都支持基于语句的复制。
MySQL5.1开始支持基于行的复制
更少的锁
对于某些语句,例如插入或者删除语句,基于行的复制方式会将整行的数据都写进binary log,致使binary log体积很大,也致使须要持有锁的时间变长。
若是包含用户自定义函数,这些函数输出值很是大的文本,那么采起行的复制,会把这么大的文本也写进日志里。
在slave端看不到执行了哪些SQL语句
当使用MyISAM引擎时,insert
语句须要得到重量级的锁,这意味着插入操做只能是串行的。
若是slave配置了log_slave_updates选项,slave也会像master同样记录binary log,从而能够做为一个master存在。
被动服务器时只读的(日志里记录的事件都带有一个server id,发现server id与本身的相同,则忽略这个事件)
很是脆弱,其中一个节点失效会致使由这个节点发起的事件在其它节点之间链式死循环,由于只有它本身能过滤掉与本身server id相同的事件。
改进:
主要用在当多个备库执行复制请求时,致使主库负载太高时,能够引进分发库来减小主库的负载。
故障处理过程更加复杂
mysql5.6 ref
mysql5.7 ref
《高性能MySQL》 3rd Edition