跳转至

Mysql OPS Review

1 查询语言 SQL

数据定义语言 (DDL)

show databases; # 查看所有数据库:
show tables; # 查看所有表:    

drop database db1; # 删除数据库    
create database db1 default character set utf8; # 创建数据库    

use database; # 选择数据库
create table t1(id int(3),name varchar(20)); # 创建表
desc t1 # 查看表

insert into t1 values(1,'user1'); # 插入数据
alter table t1 add(age int(3)); # 添加表字段语句  
alter table t1 drop id; # 删除表字段语句  
alter table t1 modify age varchar(2); # 修改表字段类型格式  
alter table t1 change age p1age int(3); # 修改表字段名称  
alter table t1 rname per; # 修改表名
truncate table t1; # 清空表结构  
drop table t1; # 删除表结构  

数据操纵语言(DML)

insert into test(id,name,address) values(102,'rose','beijing');

# 删除表test01中的所有数据。
delete from test;

# 删除表中test01中的id为101的记录。
delete from test where id=101;

# 修改表 test01 中的 id 为 102 的 address 为english,人名为 micheal。
update test01 set address='english',name='micheal' where id=102;


# 将 id 为 102 的 address 改为 null.
update test01 set address=null where id=102;

事物控制语言(TCL)

事物控制语言 (Transation Control Language) 有时可能需要使用 DML 进行批量数据的删除, 修改,增加。

数据查询语言(Data Query Language)

#查询员工表中部门号为 10 和 20 的员工的编号,姓名,职位,工资
select testid,name,job,sal from test where deptid=10 or deptid =20;

# 使用in ,not in修改上面的练习
select testid,name,job,sal from test where deptid in(10,20);
select * from test where deptid not in (10,20);

# 查询员工test,blake,clark三个人的工资
select * from test where sal>all(select sal from test where name in
('test','blake','clark'));


# 查询工资大于等于1500并且小于等于2500的员工的所有信息。
select * from test where sal between 1500 and 2500;

# 查询工资小于2000和工资大于2500的所有员工信息。
select * from test where sal not between 2000 and 2500;

# 查询员工姓名中有a和s的员工信息。
select name,job,sal,comm,deptid from test where name like '%a%' and name like
'%s%';


# 排序规则: ASC:升序 ,DESC: 降序,默认是升序排序
select * from test order by sal DESC;

# Distinct 去重
select distinct name from test;

# 分组查询 Group By 子句
# 查询以部门id为分组员工的平均工资
select deptid,avg(sal) as av from test group by deptid;

# 分组查询添加条件 Having 子句
# 查询以部门id为分组员工的平均工资并且大于2000的部门
select deptid,avg(sal) as av from test group by deptid having avg(sal)>2000;

# 高级关联查询
# 查询表中各部门人员中大于部门平均工资的人
select name,sal,a.deptid ,b.av
from test a,
(select deptid,avg(ifnull(sal,0)) as av from test group by deptid) b
where a.deptid=b.deptid and a.sal>b.av
order by deptid ASC;

数据控制语言(DCL)

数据控制语言 Data Control Language,作用是用来创建用户,给用户授权,撤销权限,删除用户。格式:

# 创建用户
create user username@ip identified by newPwd;
create user 'test'@'192.168.152.166' identified by 'test.123com';

# 显示用户的权限
show grants for username@ip;

#  授权
grant select,drop,insert on test.* to 'test'@'192.168.152.166';

# 撤销权限
revoke drop on test.* to 'test'@'192.168.152.166';

#  删除用户
drop user username;
drop user test;

# 使权限立即生效
flush privileges

2 MySQL 操作实例

mysql> create table slt(
num int auto_increment primary key,
name char(10),
job char(10),
age int,
salary int,
descrip char(128)not null default ''
)charset=utf8;
  • auto_increment : 自增 1 primary key : 主键索引,加快查询速度, 列的值不能重复 NOT NULL 标识该字段不能为空 DEFAULT 为该字段设置默认值
select distinct name, age from slt where job='teacher'

# 查看岗位是teacher且年龄大于30岁的员工姓名、年龄
mysql> select distinct name, age from slt where job='teacher' and age>30;

# 查看岗位是 teacher且薪资在1000-9000范围内的员工姓名、年龄、薪资
mysql> select distinct name, age, salary from slt where job='teacher' and
(salary>1000 and salary<9000)

# 查看岗位描述不为NULL的员工信息
mysql> select * from slt where descrip!=NULL

# 查看岗位是teacher且名字是'jin'开始的员工姓名、年薪
mysql> select * from slt where job='teacher' and name like 'jin%' ;

修改表

# ALTER TABLE 旧表名 RENAME 新表名;
alter table t3 rename t4;

ALTER TABLE 表名
ADD 字段名 列类型 [可选的参数],
ADD 字段名 列类型 [可选的参数];

alter table t88 add name varchar(32) not null default '';


<!--添加到开头语法
ALTER TABLE 表名
ADD 字段名 列类型 [可选的参数] FIRST-->
alter table t88 add name3 varchar(32) not null default '' first;

<!--添加到指定字段后面
ALTER TABLE 表名
ADD 字段名 列类型 [可选的参数] AFTER 字段名;-->
alter table t88 add name4 varchar(32) not null default '' after name;

# 删除字段
# ALTER TABLE 表名  DROP 字段名;
alter table t88 drop name4;

# 修改字段
# ALTER TABLE 表名 MODIFY 字段名 数据类型 [完整性约束条件…];
alter table t88 modify name char(20);
删除表
drop table t9;

查询表
show tables;

复制表结构
create table t8 like t1;

delete from t1 where id>=1 and id<10;
truncate t1;
  • delete 之后,插入数据从上一次主键自增加1开始, truncate则是从1开始
  • delete 删除, 是一行一行的删除, truncate:全选删除 truncate删除的速度是高于delete的

修改数据

# update 表名 set 列名1=新值1,列名2=新值2 where 条件;
update t1 set name='qfx' where id=1;

# 分组:Group By
注意:出现 `sql_mode=only_full_group_by` 错误 需修改 配置文件`/etc/my.cnf [mysqld] ` 段添加 sql模式,重启 mysqld

sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_
ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

select depart_id,name, max(age) from test group by depart_id;
select depart_id,count(depart_id) from test group by depart_id;
select depart_id, avg(age) from test group by depart_id;
select depart_id, avg(age) from test group by depart_id having avg(age)>35;

select * from test order by age asc, depart_id desc;

select * from test order by depart_id asc, age desc;

#  Limit 分页:Limit Offset, Size
# offset 表示 行数据索引;size 表示取多少条数据
# 从第 offset 行开始,取 size 行数据。

# 从第6行开始取10行 imit 6,10
select * from test limit 6,10;

多表操作

# 一对多
constraint 外键名 foreign key (被约束的字段) references 约束的表(约束的字段)
create table dep(
id int auto_increment primary key,
name varchar(32) not null default ''
)charset=utf8;


create table userinfo (
id int auto_increment primary key,
name varchar(32) not null default '',
depart_id int not null default 1,
constraint fk_user_depart foreign key (depart_id) references dep(id)
)charset utf8;

select * from boy left join b2g on boy.id=b2g.bid left join girl on girl.id=b2g.gid

# 多对多
create table b2g(
id int auto_increment primary key,
bid int not null default 1,
gid int not null default 0,
constraint fk_b2g_boy foreign key (bid) references boy(id),
constraint fk_b2g_girl foreign key (gid) references girl(id)
)charset utf8;

# 多表联查
select userinfo.name as uname, dep.name as dname from userinfo left join dep on depart_id=dep.id

3 MySQL 数据类型约束

  • 非空约束: 就是限制数据库中某个值是否可以为空,null字段值可以为空,not null字段值不能为空
create table testnull(id int, username varchar(20) not null);  # 创建testnull 设置 username 字段为非空约束 notnull
  • 唯一约束: 字段添加唯一约束之后,该字段的值不能重复,也就是说在一列当中不能出现一样的值
# 添加唯一约束
ALTER TABLE tbl_name ADD [CONSTRAINT[symbol]]
UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name)

# 删除唯一约束
ALTERT TABLE tbl_name DROP {INDEX|KEY} index_name

alter table testnull add unique(id);   # 设置 id 字段添加一个唯一约束 unique
  • 主键约束
    • 主键保证记录的唯一性,主键自动为NOT NULL
    • 每张数据表只能存在一个主键 NOT NULL + UNIQUE KEY 一个UNIQUE KEY
    • 一个NOT NULL的时候,那么它被当做PRIMARY KEY主键
    • 当一张表里没有一个主键的时候,第一个出现的非空且为唯一的列被视为有主键。
# 添加主键约束
ALTER TABLE tbl_name ADD [CONSTRAINT[sysbol]]
PRIMARY KEY [index_type] (index_col_name)

# 删除主键约束
ALTER TABLE tbl_name DROP PRIMARY KEY
  • 自增长

自增长 AUTO_INCREMENT 自动编号,且必须与主键组合使用 默认情况下,起始值为1,每次的 增量为1。当插入记录时,如果为AUTO_INCREMENT数据列明确指定了一个数值,则会出现两种 情况:

如果插入的值与已有的编号重复,则会出现出错信息,因为AUTO_INCREMENT数据列的值必须是 唯一的;

ALTER TABLE user CHANGE id id INT NOT NULL AUTO_INCREMENT;


#  删除自增长
ALTER TABLE user CHANGE id id INT NOT NULL;

默认约束
添加/删除默认约束
ALTER TABLE tbl_name ALTER [COLUMN] col_name {SET DEFAULT literal | DROP DEFAULT}

MySQL 索引

  • 普通索引(INDEX):索引列值可重复
    • 普通索引常用于过滤数据。例如,以商品种类作为索引,检索种类为“手机”的商品。
  • 唯一索引(UNIQUE):索引列值必须唯一,可以为NULL
    • 唯一索引主要用于标识一列数据不允许重复的特性,相比主键索引不常用于检索的场景。
  • 主键索引(PRIMARY KEY):索引列值必须唯一,不能为NULL,一个表只能有一个主键索引
    • 主键索引是行的唯一标识,因而其主要用途是检索特定数据。
  • 全文索引(FULL TEXT):给每个字段创建索引
    • 全文索引效率低,常用于文本中内容的检索。
# 普通索引(INDEX)

# 在创建表时指定
mysql> CREATE TABLE student (
   id INT NOT NULL,
   name VARCHAR(100) NOT NULL,
   birthday DATE,
   sex CHAR(1) NOT NULL,
    INDEX nameIndex (name(50))
);

# 基于表结构创建
mysql> CREATE INDEX nameIndex ON student(name(50));

# 修改表结构创建
mysql> ALTER TABLE student ADD INDEX nameIndex(name(50));
  • 在创建表时指定: INDEX nameIndex (name(50))
  • 基于表结构创建: CREATE INDEX nameIndex ON student(name(50));
  • 修改表结构创建: ALTER TABLE student ADD INDEX nameIndex(name(50));
基于表结构创建: CREATE UNIQUE INDEX idIndex ON student(id)
  • 主键索引(PRIMARY KEY): 主键索引不能使用基于表结构创建的方式创建
# 修改表结构创建

ALTER TABLE student ADD PRIMARY KEY (id):

删除索引

# 普通索引(INDEX)

# 直接删除
mysql> DROP INDEX nameIndex ON student;

# 修改表结构删除
mysql> ALTER TABLE student DROP INDEX nameIndex;

# 唯一索引(UNIQUE)
# 直接删除
mysql> DROP INDEX idIndex ON student;

# 修改表结构删除
mysql> ALTER TABLE student DROP INDEX idIndex;

# 主键索引(PRIMARY KEY)
mysql> ALTER TABLE student DROP PRIMARY KEY;

# 查看索引
mysql> SHOW INDEX FROM student;

MySQL 的用户管理和权限管理

DCL(数据库控制语言)

  • GRANT 用户授权,为用户赋予访问权限
  • REVOKE 取消授权,撤回授权权限

MySQL 权限表

  • mysql.user

    • 用户字段:Host、User、Password
    • 权限字段:_Priv结尾的字段
    • 安全字段:ssl x509字段
    • 资源控制字段:max_开头的字段
  • mysql.db

    • 用户字段:Host、User、Password
    • 权限字段:剩下的_Priv结尾的字段
  • 授权级别排列

    • mysql.user #全局授权
    • mysql.db #数据库级别授权
  • 用户和 IP格式

    • 用户名@IP地址 用户只能在改IP下才能访问
    • 用户名@192.168.1.% 用户只能在改IP段下才能访问(通配符%表示任意)
    • 用户名@%.qfedu.com
    • 用户名@% 用户可以再任意IP下访问(默认IP地址为%)

MySQL 用户管理

创建实例

CREATE USER 'qfedu'@'localhost' IDENTIFIED BY '123456';
CREATE USER 'qfedu'@'192.168.1.101' IDENDIFIED BY '123456';
CREATE USER 'qfedu'@'192.168.1.%' IDENDIFIED BY '123456';
CREATE USER 'qfedu'@'%' IDENTIFIED BY '123456';
GRANT ALL ON *.* TO 'user3'@’localhost’ IDENTIFIED BY ‘123456’;
# *.*所有数据库

# DROP USER 删除
DROP USER 'user1'@’localhost’;

# DELETE 语句删除
DELETE FROM mysql.user WHERE user=’user2’ AND host=’localhost’;

# 修改用户
RENAME USER 'old_user'@‘localhost’ TO 'new_user'@'localhost';

# 修改密码
# 注意:修改完密码必须刷新权限

FLUSH PRIVILEGES;

# root 用户修改自己密码
方法一:
mysqladmin -uroot -p123 password 'new_password'  # 123为旧密码

方法二: 
alter user 'root'@'localhost' identified by 'new_pssword';

方法三:
SET PASSWORD=password(‘new_password’);

# root 修改其他用户密码
方法一:
alter user 'qfedu'@'localhost' identified by 'Qfedu.1234com';

方法三:
GRANT SELECT ON *.* TO 用户名@’ip地址’ IDENTIFIED BY ‘yuan’;

# 普通用户修改自己密码
SET password=password(‘new_password’);

找回 root 密码

在[mysqld]下面加上 skip-grant-tables

# vim /etc/my.cnf
[mysqld]
···

#设置免密登录
skip-grant-tables

设置密码

mysql> update user set authentication_string=password('密码') where user='root';

密码复杂度

MySQL 默认启用了密码复杂度设置,插件名字叫做 validate_password

mysql> INSTALL PLUGIN validate_password SONAME 'validate_password.so';

修改配置

# vim /etc/my.cnf
[mysqld]
plugin-load=validate_password.so
validate_password_policy=0
validate-password=FORCE_PLUS_PERMANENT

查看密码策略

mysql> select @@validate_password_policy; # 查看密码复杂性策略

mysql> select @@validate_password_length; # 查看密码复杂性要求密码最低长度大小

MySQL 权限管理

查看权限
SHOW GRANTS FOR '用户'@'IP地址';
SHOW GRANTS FOR 'root'@'localhost';

授权及设置密码
GRANT 权限 [,权限...[,权限]] NO 数据库.数据表 TO '用户'@'IP地址';

GRANT 权限 [,权限...[,权限]] NO 数据库.数据表 TO '用户'@'IP地址' IDENTIFIED BY '密码';

mysql> GRANT ALL ON *.* TO admin1@'%' IDENTIFIED BY '(Qfedu.123com)';

mysql> GRANT ALL ON *.* TO admin2@'%' IDENTIFIED BY '(Qfedu.123com)' WITH GRANT
OPTION;

mysql> GRANT ALL ON qfedu.* TO admin3@'%' IDENTIFIED BY '(Qfedu.123com)';
mysql> GRANT ALL ON qfedu.* TO admin3@'192.168.122.220' IDENTIFIED BY
'(Qfedu.123com)';

mysql> GRANT ALL ON qfedu.user TO admin4@'%' IDENTIFIED BY '(Qfedu.123com)';
mysql> GRANT SELECT(col1),INSERT(col2,col3) ON qfedu.user TO admin5@'%'
IDENTIFIED BY '(Qfedu.123com)';

10 MySQL 日志管理

MySQL错误日志

$ vim /etc/my.cnf
log_error=/data/3306/data/mysql.log #这里的路径和文件名称可以随便定义

systemctl restart mysqld

查看错误日志

mysql> select @@log_error;
+---------------------------+
| @@log_error |
+---------------------------+
| /data/3306/data/mysql.log |
+---------------------------+
1 row in set (0.00 sec)

MySQL 二进制日志

  • 数据恢复必备的日志。
  • 主从复制依赖的日志。
# vim /etc/my.cnf
server_id=6
log_bin=/data/3306/binlog/mysql-bin

配置说明

  • mysql-bin 是在配置文件配置的前缀
  • 000001 MySQL每次重启,重新生成新的

二进制日志内容

DML 语句有三种模式:SBR、RBR、MBR

mysql> select @@binlog_format;
+-----------------+
| @@binlog_format |
+-----------------+
| ROW |
+-----------------+
1 row in set (0.00 sec)
  • statement---->SBR:做什么记录什么,即SQL语句
  • row---------->RBR:记录数据行的变化(默认模式,推荐)
  • mixed-------->MBR:自动判断记录模式

二进制日志工作模式

# vim /etc/my.cnf
[mysqld]
binlog_format='ROW'

查看二进制日志工作模式

show variables like "binlog%";

二进制日志三种模式的区别

ROW: 基于行的复制

  • 优点:所有的语句都可以复制,不记录执行的sql语句的上下文相关的信息,仅需要记录那一条记录被 修改成什么了
  • 缺点:binlog 大了很多,复杂的回滚时 binlog 中会包含大量的数据

Statement: 基于sql语句的复制

  • 优点:不需要记录每一行的变化,减少了binlog日志量,节约了IO,提高性能

mixed模式 :row 与 statement 结合

实际上就是前两种模式的结合,在mixed模式下,mysql会根据执行的每一条具体的sql语句来区分对待 记录的日志形式,也就是在statement和row之间选一种。

查看二进制日志的配置信息

mysql> show variables like '%log_bin%';
+---------------------------------+--------------------------------+
| Variable_name | Value |
+---------------------------------+--------------------------------+
| log_bin | ON |
| log_bin_basename | /var/log/mysql/mysql-bin |
| log_bin_index | /var/log/mysql/mysql-bin.index |
| log_bin_trust_function_creators | OFF |
| log_bin_use_v1_row_events | OFF |
| sql_log_bin | ON |
+---------------------------------+--------------------------------+
6 rows in set (0.00 sec)
  • log_bin 开启二进制日志的开关
  • log_bin_basename 位置
  • sql_log_bin 临时开启或关闭二进制日志的小开关

打印出当前MySQL的所有二进制日志,并且显示最后使用到的 position

mysql> show binary logs;
mysql> show master status;(常用)

二进制日志内容的查看和截取

# mysqlbinlog /data/3306/binlog/mysql-bin.000001

# mysqlbinlog --base64-output=decode-rows -vvv
/data/3306/binlog/mysql-bin.000001

# mysqlbinlog --start-position=xxx --stop-position=xxx
/data/3306/binlog/mysql-bin.000001 >/data/bin.sql

数据恢复实例

mysql> create database binlog charset utf8mb4;

mysql> use binlog;

mysql> show binlog events in 'mysql-bin.000001';
起点:
| mysql-bin.000001 | 381 | Query | 6 | 497 | create
database binlog charset utf8mb4 |
终点:
| mysql-bin.000001 | 1575 | Query | 6 | 1673 | drop
database binlog

# 截取日志
# mysqlbinlog --start-position=381 --stop-position=1575
/data/3306/binlog/mysql-bin.000003>/data/bin.sql

# 恢复日志
mysql> set sql_log_bin=0; # 临时关闭当前会话的binlog记录
mysql> source /data/bin.sql;
mysql> set sql_log_bin=1; # 打开当前会话的binlog

二进制日志其他操作

# 查看自动清理周期
mysql> show variables like '%expire%';
+--------------------------------+-------+
| Variable_name | Value |
+--------------------------------+-------+
| disconnect_on_expired_password | ON |
| expire_logs_days | 0 |
+--------------------------------+-------+
2 rows in set (0.00 sec)

# 零时设置自动清理周期
mysql> set global expire_logs_days=8;

mysql> show variables like '%expire%';
+--------------------------------+-------+
| Variable_name | Value |
+--------------------------------+-------+
| disconnect_on_expired_password | ON |
| expire_logs_days | 8 |
+--------------------------------+-------+
2 rows in set (0.00 sec)

永久生效

# vim /etc/my.cnf
[mysqld]
expire_logs_days=15;

手工清理

PURGE BINARY LOGS BEFORE now() - INTERVAL 3 day;
PURGE BINARY LOGS TO 'mysql-bin.000009';
  • 注意: 不要手工 rm binlog文件
  • 主从关系中,主库执行此操作 reset master; ,主从环境必崩

二进制日志的滚动

mysql> flush logs;
mysql> select @@max_binlog_size;

慢日志简介

  • 记录运行较慢的语句记录slowlog中。
  • 功能是辅助优化的工具日志。、
  • 应激性的慢可以通过show processlist进行监控
  • 一段时间的慢可以进行slow记录、统计

查看慢日志

mysql> show variables like '%slow_query%';
+---------------------+-----------------------------------+
| Variable_name | Value |
+---------------------+-----------------------------------+
| slow_query_log | OFF |
| slow_query_log_file | /var/lib/mysql/localhost-slow.log |
+---------------------+-----------------------------------+
2 rows in set (0.00 sec)

查看阈值

mysql> select @@long_query_time;

mysql> SHOW GLOBAL VARIABLES LIKE 'long_query_time%';

mysql> SHOW VARIABLES LIKE 'long_query_time%';

mysql> show variables like '%log_queries_not_using_indexes%';

配置慢日志

# 零时设置开启
SET GLOBAL slow_query_log = 1; #默认未开启,开启会影响性能,mysql重启会失效

#设置阈值:
SET GLOBAL long_query_time=3;

永久生效

# vim /etc/my.cnf
[mysqld]
slow_query_log=1
slow_query_log_file=/data/3306/data/qfedu-slow.log
long_query_time=0.1 默认配置10秒钟
log_queries_not_using_indexes=1

慢日志分析工具

# mysqldumpslow -s r -t 10 /data/3306/data/qfedu-slow.log
# 得到返回记录集最多的10个SQL

# mysqldumpslow -s c -t 10 /data/3306/data/qfedu-slow.log
# 得到访问次数最多的10个SQL

# mysqldumpslow -s t -t 10 -g "LEFT JOIN"
/data/3306/data/qfedu-slow.log # 得到按照时间排序的前10条里面含有左连接的查询语句

# mysqldumpslow -s r -t 10 /data/3306/data/qfedu-slow.log |
more # 结合| more使用,防止爆屏情况

11 MySQL备份概述

备份必须重视的内容

备份内容 databases Binlog my.conf

  • 数据的一致性
  • 服务的可用性

MySQL 备份类型

  • 物理备份: 对数据库操作系统的物理文件(如数据文件、日志文件等)的备份。
  • 热备(hot backup): 在线备份,数据库处于运行状态,这种备份方法依赖于数据库的日志文件
    • 对应用基本无影响(应用程序读写不会阻塞,但是性能还是会有下降,所以尽量不要在主上做备份,在 从库上做)
  • 冷备(cold backup)
    • 备份数据文件,需要停机,是在关闭数据库的时候进行的 备份 datadir 目录下的所有文件
  • 温备(warm backup)

  • 逻辑备份

MySQL 备份工具

  • ibbackup
  • xtrabackup
  • mysqldump
  • mysqlbackup
    • innodb 引擎的表mysqlbackup可以进行热备
    • 非innodb表mysqlbackup就只能温备

MySQL 备份策略

  • 完全备份: 每次对数据进行完整的备份,即对整个数据库的备份、数据库结构和文件结构的备份,保存的是备份完 成时刻的数据库,是差异备份与增量备份的基础。
  • 差异备份: 备份那些自从上次完全备份之后被修改过的所有文件,备份的时间起点是从上次完整备份起,备份数据量会越来越大
    • 恢复数据时,只需恢复上次的完全备份与最近的一次差异备份。
  • 增量备份: 只有那些在上次完全备份或者增量备份后被修改的文件才会被备份。
    • 以上次完整备份或上次的增量备份 的时间为时间点,仅备份这之间的数据变化,因而备份的数据量小,占用空间小,备份速度快。

MySQL 主从复制原理介绍

MySQL 主从复制过程

  • 开启binlog日志,通过把主库的 binlog 传送到从库,从新解析应用到从库。
  • 复制需要3个线程(dump、io、sql)完成
  • 复制是异步的过程。主从复制是异步的逻辑的SQL语句级的复制。

MySQL 主从复制前提

  • 主服务器一定要打开二进制日志
  • 必须两台服务器(或者是多个实例)
  • 从服务器需要一次数据初始化
  • 如果主从服务器都是新搭建的话,可以不做初始化
  • 如果主服务器已经运行了很长时间了,可以通过备份将主库数据恢复到从库。
  • 主库必须要有对从库复制请求的用户。
  • 从库需要有relay-log设置,存放从主库传送过来的二进制日志 show variables like '%relay%';
  • 在第一次的时候,从库需要change master to 去连接主库。
  • change master信息需要存放到 master.info 中 show variables like '%master_info%';
  • 从库怎么知道,主库发生了新的变化通过relay-log.info记录的已经应用过的relay-log信息。
  • 在复制过程中涉及到的线程
    • 从库会开启一个IO thread(线程),负责连接主库,请求binlog,接收binlog并写入relaylog。
    • 从库会开启一个SQL thread(线程),负责执行relay-log中的事件。
    • 主库会开启一个dump thrad(线程),负责响应从IO thread的请求。

MySQL 主从复制实现

  • 通过二进制日志
  • 至少两台(主、从)
  • 主服务器的二进制日志“拿”到从服务器上再运行一遍。
  • 通过网络连接两台机器,一般都会出现延迟的状态。也可以说是异步的。
  • 从库通过手工执行change master to语句连接主库,提供了连接的用户一切条件 user、 password、port、ip
  • 并且让从库知道,二进制日志的起点位置(file名 position号)
  • 启动从库同步服务 start slave
  • 从库的IO和主库的dump线程建立连接
  • 从库根据change master to 语句提供的file名和position号,IO线程向主库发起binlog的请求
  • 主库dump线程根据从库的请求,将本地binlog以events的方式发给从库IO线程
  • 从库IO线程接收binlog evnets,并存放到本地relay-log中,传送过来的信息,会记录到 master.info中。
  • 从库SQL线程应用relay-log,并且把应用过的记录到relay-log.info,默认情况下,已经应用过的 relay会自动被清理purge