MySQL 学习笔记

MySQL数据库介绍及安装
官方定义MySQL DBA工作内容
运维DBA
初级:各版本、各平台安装搭建、升级
中级:体系结构原理、基础管理(启动关闭、初始化配置文件管理、多实例管理、用户权限管理、基本SQL(增删改查))、
日志管理、备份与恢复、主从复制(构建、状态监控)
高级:高可用(MGR、InnoDB Cluster)、高性能(优化)
开发DBA
懂至少一门开发语言 :JAVA、Python
基本SQL语句深入学习(增删改查)、数据库结构设计(建模)
高级SQL:存储过程、函数、触发器、视图、事件
数据是什么
认为:账号密码、图片、视频、文字、链接等
计算机:二进制数据
数据如何储存
–使用专用的软件将数据转换为二进制存储在计算机指定位置
需要考虑:安全, 存储限制
数据库管理系统
EDBMS --关系型数据库(重要信息):Oracle、MySQL、MSSQL、PG
NoSQL --非关系型数据库(没那么重要)a. EDBMS 关系型数据库:MongoDB、ES、Redis
MySQL产品线
MySQL厂家:Oracle、MariaDB、Percona
Oracle MySQL企业版本选择:5.6 (5.6.36)/ 5.7 / 8.0
MySQL安装方式(Linux)
通用二进制版本:解压即用
rpm, yum版本:下载rpm包或者配置yum源
源码包:编译安装,非常慢,研究MySQL源码

MySQL 5.7.28二进制包安装
环境准备
准备虚拟机;
IP:
CPU:
清理历史环境
创建用户和组
root@howell-PC:/home/howell/Downloads# useradd mysql -s /sbin/nologin
创建软件目录
root@howell-PC:/home/howell/Downloads# mkdir -p /data/3306/
root@howell-PC:/home/howell/Downloads# mkdir -p /binlog/3306
root@howell-PC:/home/howell/Downloads# mkdir -p /app/database/
设置权限
root@howell-PC:/home/howell/DownloMySQL企业版本选择:5.6 (5.6.36)/ 5.7 / 8.0ads# chown -R mysql.mysql /app/ /data/ /binlog/
上传并解压MySQL软件
root@howell-PC:/app/database# tar xf mysql-5.7.28-linux-glibc2.12-x86_64.tar.gz
制作软件接:ln -s mysql-5.7.28-linux-glibc2.12-2-x86_64 mysql设置环境变量
设置环境变量
vim /etc/profile (即修改tec/profile文件)
添加一行:export PATH=/app/database/mysql/bin:PATH
生效配置:source /etc/profile

初始化系统库表
mysqld --initialize-insecure --user=mysql --basedir=/app/database/mysql --datadir=/data/3306/
拓展
Mysqld --initialize
初始完密码完成后,会有12位临时密码,但是必须在使用mysql之前重置这个密码;
mysqld --initialize-insecure
mysqld --initialize-insecure (5.7+)
初始完之后为空密码;

配置文件设置
cat > /etc/my.cnf <<EOF
[mysqld]
user=mysql
basedir=/app/database/mysql
datadir=/data/3306
server_id=6
port=3306
socket=/tmp/mysql.sock
[mysql]
socket=/tmp/mysql.sock
EOF

准备MySQL启动脚本
拷贝mysql启动脚本至管理目录cp mysql.server /etc/init.d/mysqld

MySQL体系结构及基础管理
MySQL客户端/服务起工作模型(C/S)

本地socket连接方式
mysql -S /tmp/mysql.sock
说明:只能在本地使用,不依赖ip和端口
远程TCP/IP连接方式
mysql -uroot -p123 -h 127.0.0.1 -p 3306

服务器端实例
实例:mysqld+ 工作线程+ 预分配的内存结构
功能:管理数据

mysqld程序结构
由两大主层:server层、引擎层;官方
细致:三主层:suerver层(链接层、SQL层)、引擎层

连接层
提供链接协议(socket, TCP/IP);
验证;
提供专用连接线程;
SQL层
语法检查;
语义(DDL, DCL, DML, DTL),权限检查;
解析器:解析预处理(评估执行方法消耗),得出执行计划;
优化器:选择最优方案(基于代价cost);
执行器:按照优化器的选择执行SQL语句,得出执行结果,你需要的数据在磁盘的具体位置
查询缓存(query cache 默认不开启8.0后取消):缓存SQL执行语句及查询过程;可以用redis替代自带的查询缓存;
日志记录:binlog二进制日志,默认未开启。

存储引擎层
相当于linux中的文件系统,和磁盘交互的模块。

MySQL的逻辑结构(对象)
库 database:库名、库的属性;
表 tables:表名、表的属性、表的内容、表的列
MySQL的物理存储结构
段:一个表就是一个段(分区表除外),可以由一个或者多个区构成
区 :一个区或者簇,默认1M,连续的64个page;
页 :一个page,默认16k,连续的4个OS block,最小的IO单元;
1个区或者簇/1MB(连续64个page) -> 1个page/16KB(连续4个block) -> 一个block/4KB(连续8个扇区) -> 一个扇区512/KB;
一个表就是一个段;

MySQL 基础管理
用户管理
用户的作用
Linux用户:登录linux系统、管理系统:文件;
MySQL:登录MySQL数据库、管理MySQL对象:表;
用户的定义
Linux用户:用户名;
MySQL用户:用户名@‘白名单’;
白名单:地址列表,允许通过白名单IP登录MySQL;
MySQL用户
howell@‘localhost’:howell用户能够通过本地登录MySQL(socket);
howell@‘10.0.0.10’:howell用户能够通过10.0.0.10远程登录MySQL;
howell@‘10.0.0.%’:howell用户能够通过10.0.0.xx/24远程登录MySQL服务器;
howell@‘10.0.0.5%’:howell用户能够通过10.0.0.50-10.0.0.59远程登录MySQL服务器;
howell@‘10.0.0.0/255.255.254.0’;
howell@’%’;
用户查询
use mysql;
show tables;
desc user;
mysql> select user,host,authentication_string from mysql.user;
root@‘localhost’:超级管理员用户,只能通过本地socket登录;
创建用户
mysql> create user howell@‘localhost’;
select user,host,authentication_string from mysql.user;#新建用户并设置密码
修改用户
mysql> alter user howell@‘localhost’ identified by ‘zxcv’;#修改用户密码
删除用户
mysql> drop user howell2@‘192.168.1.5’;
mysql> drop user howell@‘localhost’;
注意: 8.0 版本之前,是可以通过grant命令 建立用户+授权;8.0之后只能先建立用户,后授权;

权限管理
作用
用户对数据库对象,有哪些管理能力?
权限的表现方式
具体的命令
mysql> show privileges;#查询MySQL可设置权限的所有命令

±------------------------±--------------------------------------±------------------------------------------------------+
| Privilege | Context | Comment |
±------------------------±--------------------------------------±------------------------------------------------------+
| Alter | Tables | To alter the table |
| Alter routine | Functions,Procedures | To alter or drop stored functions/procedures |
| Create | Databases,Tables,Indexes | To create new databases and tables |
| Create routine | Databases | To use CREATE FUNCTION/PROCEDURE |
| Create temporary tables | Databases | To use CREATE TEMPORARY TABLE |
| Create view | Tables | To create new views |
| Create user | Server Admin | To create new users |
| Delete | Tables | To delete existing rows |
| Drop | Databases,Tables | To drop databases, tables, and views |
| Event | Server Admin | To create, alter, drop and execute events |
| Execute | Functions,Procedures | To execute stored routines |
| File | File access on server | To read and write files on the server |
| Grant option | Databases,Tables,Functions,Procedures | To give to other users those privileges you possess |
| Index | Tables | To create or drop indexes |
| Insert | Tables | To insert data into tables |
| Lock tables | Databases | To use LOCK TABLES (together with SELECT privilege) |
| Process | Server Admin | To view the plain text of currently executing queries |
| Proxy | Server Admin | To make proxy user possible |
| References | Databases,Tables | To have references on tables |
| Reload | Server Admin | To reload or refresh tables, logs and privileges |
| Replication client | Server Admin | To ask where the slave or master servers are |
| Replication slave | Server Admin | To read binary log events from the master |
| Select | Tables | To retrieve rows from table |
| Show databases | Server Admin | To see all databases with SHOW DATABASES |
| Show view | Tables | To see views with SHOW CREATE VIEW |
| Shutdown | Server Admin | To shut down the server |
| Super | Server Admin | To use KILL thread, SET GLOBAL, CHANGE MASTER, etc. |
| Trigger | Tables | To use triggers |
| Create tablespace | Server Admin | To create/alter/drop tablespaces |
| Update | Tables | To update existing rows |
| Usage | Server Admin | No privileges - allow connect only |
±------------------------±--------------------------------------±------------------------------------------------------+
授权、回收权限操作
语法
语法8.0以前:
grant 权限 on 对象 to 用户 identified by ‘密码’; #8.0以前,可以创建用户的同时授权

8.0以后:
create user 用户 identified by ‘密码’;
grant 权限1,权限2 on 对象 to 用户;#分两步,需先创建用户后授权
权限:可以在上表选择;
ALL:管理员;
权限1,权限2,…:普通用户;
grant option:给别的用户授权,后面添加 with grant option;
对象:库或者表
. :-------> chmod -R 755 /;所有授权
howell.* :--------> howell这个子目录所有授权;
howell.t1 : ----------> howell数据库下单表t1;
howell.t1() : ------------> 给howell数据库下t1表某个列授权;
授权的例子
例子1:创建并授权管理员用户howellroot,能够通过192.168.1.5网段登录并管理数据库
mysql> grant all on . to howellroot@‘192.168.1.5’ identified by ‘zxcv’ with grant option;
select user,host,authentication_string from mysql.user;#查看用户
mysql> show grants for howellroot@‘192.168.1.5’;#查询howellroot@'192.168.1.5’用户权限;
mysql> select * from mysql.user\G;#可以查看用户的权限
例子2:用户授权
mysql> grant create,update,select,insert,delete on app.* to app@‘192.168.1.5’ identified by ‘zxcv’;
mysql> show grants for app@‘192.168.1.5’;#查看权限
拓展
MySQL授权表:
user —> .
db ----> app.*
tables_priv ----> app.t1
columns_priv 列
回收权限
Linux:chmod -R 644 /howell -----> chmod -R 755 /howell 可以通过重复授权修改权限;
MySQL:不能通过重复授权的方式修改权限,只能通过回收权限的方式修改权限;
mysql> revoke create on app.* from app@‘192.168.1.5’;#回收app@'192.168.1.5’用户create权限
mysql> show grants for app@‘192.168.1.5’;#查看权限
超级管理员密码忘记了,怎么处理?
关闭连接层用户验证阶段:
–skip-grant-tables 跳过授权表
–skip-networking 跳过TCP/IP连接
etc/init.d/mysqld stop #关闭mysqld
which mysqld_safe
mysqld_safe --skip-grant-tables & #这种方式谁都可以登录,不安全

systemctl stop mysqld #关闭数据库
mysqld_safe --skip-grant-tables --skip-networking & #安全模式启动
拓展:也可以使用 service mysqld start --skip-grant-tables --skip-networking & 安全模式启动
mysql #登录数据库
flush privileges; 手工加载授权表;
alter user root@‘localhost’ identified by ‘zxcv’; #更改密码
service restart mysqld #重启数据库到正常模式

MySQL 连接管理
MySQL自带客户端程序、MysQL远程客户端程序、程序链接

MySQL 自带客户端程序
(1) mysql
参数列表:
-u 用户名
-p 密码
-S 本地socket文件
-h 数据库IP地址
-P 数据库端口号
-e 免交互执行数据库命令
< 导入SQL脚本
scoket连接方式:
前提:数据库中必须实现授权root@'localhost’用户
mysql -uroot -pzxcv -S /tmp/mysql.sock #最完整
mysql -uroot -p -S /tmp/mysql.sock #推荐方式
mysql -uroot -p
TCP/IP连接方式:
前提:必须提前创建好远程连接的用户 例如 howellwindows@‘192.168.1.5’
mysql -uhowellwindows -pzxcv -h 192.168.1.5 -P 3306 #远程连接,不加端口号默认3306
例子1:授权howell管理用户,可以通过本地socket登录
mysql> grant all on . to howell@‘localhost’ identified by ‘zxcv’; #创建howell用户
mysql> mysql -uhowell -p -S /tmp/mysql.sock #测试连接
例子2:授权ychowell用户,可以通过192.168.1.%远程登录
mysql> grant all on . to ychowell@‘192.168.1.%’ identified by ‘zxcv’; #创建ychowell用户通过192.168.1.5登录mysql
mysql> mysql -uychowell -p -h 192.168.1.6 -P 3306 #登录测试
查看连接user及ip,谁是远程连接谁是本地连接
grant all on . to ychowell@‘192.168.1.%’ identified by ‘zxcv’;

±—±---------±---------------±-----±--------±-----±---------±-----------------+
| Id | User | Host | db | Command | Time | State | Info |
±—±---------±---------------±-----±--------±-----±---------±-----------------+
| 8 | ychowell | howell-l:50448 | NULL | Sleep | 276 | | NULL |
| 10 | root | localhost | NULL | Query | 0 | starting | show processlist |
±—±---------±---------------±-----±--------±-----±---------±-----------------+
-e的使用,不交互取值
mysql -uroot -pzxcv -e “select user,host from mysql.user;” #没有交互直接取值
<的使用,导入SQL脚本
howell@howell-PC:~$ mysql -uroot -pzxcv < /root/world.sql
MySQL远程客户端程序(开发工具)
前提:必须提前创建好可以远程连接的用户(如:ychowell@‘192.168.1.%’)
程序连接
yum install -y php-mysql
pip3 install pymysql

初始化配置
方式
源码安装:编译过程中设置初始化参数;
配置文件:数据库启动之前,设定配置文件参数 /etc/my.cnf;
启动脚本命令行:如mysqld_safe --skip-grant-tables --skip-networking &.
配置文件应用
(1) 配置文件读取顺序
howell@howell-PC:~$ mysqld --help --verbose |grep my.cnf
/etc/my.cnf /etc/mysql/my.cnf /usr/local/mysql/etc/my.cnf ~/.my.cnf #mysqld会从这几个路径找配置文件
my.cnf, $MYSQL_TCP_PORT, /etc/services, built-in default
(2)意外情况:
手工定制配置文件位置点:/opt/my.cnf,/data/3306/my.cnf
mysqld --default-file=/opt/my.cnf & #启动时
mysqld_safe --default-file=/opt/my.cnf &
(3)配置文件的书写格式
[mysqld] #服务器端标签
user=mysql #负责数据库管理用户
basedir=/app/database/mysql #软件的安装位置
datadir=/data/3306 #数据的存放位置
server_id=6 #标识节点的唯一编号(主从有用)
port=3306 #端口号
socket=/tmp/mysql.sock #套接字文件 连接数据库中的 -S 参数
[mysql] #客户端标签
socket=/tmp/mysql.sock #MySQL登录时默认读取socket文件的位置
[标签]
配置参数
标签是什么?
标签是用来区分不同程序的参数;
服务器端标签:负责数据库服务器端运行参数设定
客户端标签:影响客户端连接,只影响本地客户端连接,不影响远程客户端连接
服务器端常见标签类型:
[mysqld]
[mysqld_safe]
客户端厂家爱你标签类型:
[mysql]
[mysqldump]

MySQL启动与关闭
启动

systemctl start mysqld -->mysql.server -->mysqld_safe -->mysqld
mysqld_safe和mysqld,可以在启动数据库时计入自己执行的参数,例如
–skip-grant-tables
–skip-networking
–default-file=/opt/my.cnf
关闭
systemctl stop m ysqld
service mysqld stop
/etc/init.d/mysqld stop
mysqladmin -uroot -pzxcv shutdown
mysql -uroot -pzxcv -e “shutdown”

MySQL的多实例
同版本多实例
(1)规划
软件1份
配置文件多份:/data/3307/my.cnf /data/3308/my.cnf /data/3309/my.cnf
数据目录多份 --初始化数据多次:/data/330(7…9)
日志目录多份:/binlog/330(7…9)
socket多份:/tmp/mysql330(7…9).sock
端口多份:port=3307,3308,3309
server_id多份:server_id=7,8,9
(2)配置过程
1)创建需要目录
mkdir -p /data/330{7…9}/data #创建数据目录
mkdir -p /binlog/330{7…9} #创建日志目录
2)创建配置文件
配置文件读取顺序:
cat > /data/3307/my.cnf <<EOF
[mysqld]
basedir=/app/database/mysql
datadir=/data/3307/data
socket=/tmp/mysql3307.sock
log_error=/data/3307/mysql.log
port=3307
server_id=7
log_bin=/binlog/3307/mysql-bin
EOF

cat > /data/3308/my.cnf <<EOF
[mysqld]
basedir=/app/database/mysql
datadir=/data/3308/data
socket=/tmp/mysql3308.sock
log_error=/data/3308/mysql.log
port=3308
server_id=8
log_bin=/binlog/3308/mysql-bin
EOF

cat > /data/3309/my.cnf <<EOF
[mysqld]
basedir=/app/database/mysql
datadir=/data/3309/data
socket=/tmp/mysql3309.sock
log_error=/data/3309/mysql.log
port=3309
server_id=9
log_bin=/binlog/3307/mysql-bin
EOF
3)初始化数据
mysqld --initialize-insecure --user=mysql --datadir=/data/3307/data --basedir=/app/database/mysql
mysqld --initialize-insecure --user=mysql --datadir=/data/3308/data --basedir=/app/database/mysql
mysqld --initialize-insecure --user=mysql --datadir=/data/3309/data --basedir=/app/database/mysql
4)准备启动脚本
cat >/etc/systemd/system/mysqld.service <<EOF
[Unit]
Description=MySQL Server
Documentation =man:mysqld(8)

不同版本多实例
1)软连接不同版本

ln -s mysql-5.6.46-linux-glibc2.12-x86_64 mysql56

ln -s mysql-8.0.18-linux-glibc2.12-x86_64 mysql80

mv /etc/my.cnf /etc/my.cnf.bak

#注释以下信息
#export PATH=/app/database/mysql/bin:$PATH
2)准备不同目录
3)准备配置文件
4)初始化数据
5)准备启动脚本

第四章 MySQL的SQL基础
SQL介绍
结构化查询语言
结构化查询语言:关系型数据库中通用的一类语言。
SQL常用类型
MySQL客户端自带的功能
mysql>help #可以使用help打印出来
MySQL Server端分类命令
mysql>help contents

DDL:数据定义语言
DCL:数据控制语言
DML:数据操作语言
DQL:数据查询语言
SQL的各种名词
SQL_modes SQL模式
SQL-mode作用:规范SQL语句书写的方式(例如:分母为0,或者0年0月0日),影响SQL执行行为
SQL_mode是一个参数
select @@sql_mode;
| @@sql_mode |
±------------------------------------------------------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,
STRICT_TRANS_TABLES,
NO_ZERO_IN_DATE,
NO_ZERO_DATE,E
RROR_FOR_DIVISION_BY_ZERO,
NO_AUTO_CREATE_USER,
NO_ENGINE_SUBSTITUTION |
±------------------------------------------------------------------------------------------------------------------------------------------+
字符集(charset)及校对规则(collation)
字符集
show charset;
utf8:单个字符最多3个字节
utf8mb4(建议):单个字符最多4个字节
差别:(1)utf8mb4支持的编码比utf8多,比如,emoji字符mb4中支持,utf8不支持,因为emoji字符,1个字符占4个字节;
create database zabbix charset utf8mb4;
show create database zabbix;
校对规则(collation)
每种字符集有多种校对规则(排序规则);
show collation;
作用:(1)影响排序的操作,简单来说就是大小写是否敏感;
#大小写敏感 | utf8mb4_general_ci | utf8mb4 | 45 | Yes | Yes | 1 |
#大小写不敏感 | utf8mb4_bin | utf8mb4 | 46 | | Yes | 1 |
数据类型(data_type)
数字:整数、小数
mysql> create database study;
mysql> use study;
mysql> create table t1(id int,name varchar(64),age tinyint);

tinyint1B=8 bitint4Bbigint8B
字符串类型
char(长度):定长字符串类型 最多255个字符varchar(长度):变长字符串类型 最多65535字符enum(‘bj’, sh):枚举类型enum(‘sd’, ‘sdsd’, ‘sa’)
char和varchar的区别 例如:
char(10):最多存10个字符,如果存储的字符不够10个,自动用空格填充剩余的空间,对于磁盘空间都会占满;
varchar(10):最多存10个字符,按需分配存储空间;
补充:

  1. varchar类型在存储数据时会先判断字符长度,然后合理分配存储空间,而char类型不会判断,立即分配。所以在固定长度列中,还是会选择char类型。
  2. varchar类型,除了会存储字符串之外,还会额外使用1-2个字节存储字符长度。
    例:varchar(10)
    asdf —> 1.判断字符长度 —> 2.申请空间 —> 3. 存字符 —> 4.申请一个字节,存储字符长度;
    3.应用场景:
    字符串固定长度,char类型;不固定,varchar类型;
    4.括号中数字问题
    括号中设置的是字符的个数,无关字符类型。
    但是不同种类的字符,占用的储存空间是不一样的。
    对于数字和英文,每个字符占1个字节长度。
    对于中文,占用空间大小要考虑字符集,utf,utf8mb4每个中文占3个字节长度。emoji字符占4个字节长度。
    总长度不能超过数据类型的最大长度。
    彩蛋:以上两种数据类型选择需考虑周到索引应用。

时间类型

DATATIME(常用):范围从1000-01-01 00:00:00.000000 至 9999-12-31 23:59:59.999999;占用8个字节长度
TIMESTAMP(常用):范围从1970-01-01 00:00:00.000000 至 2038-01-19 03:14:07:999999;占用4个字节长度;会收到时区的影响。
二进制类型
json数据类型
{
id: 101
name: ‘zhangsan’
}
表属性
约束
PK(Primary key) :主键约束;作用:唯一+ 非空;每张表只有一个主键,作为聚簇索引。
not null :非空约束;作用:必须非空,我们建议每个列都设置为非空。
unique key :唯一约束;作用:必须是不重复的。
unsigned :针对数字列,非负数。
其他属性
default :默认值(例如非空值里面填写默认值)
comment :注释
auto_increment:自增长

SQL的应用
Client
List of all MySQL commands:
Note that all text commands must be first on line and end with ‘;’
? (?) Synonym for `help’.
clear (\c) Clear the current input statement.
connect (\r) Reconnect to the server. Optional arguments are db and host.
delimiter (\d) Set statement delimiter.
edit (\e) Edit command with $EDITOR.
ego (\G) Send command to mysql server, display result vertically.
exit (\q) Exit mysql. Same as quit.
go (\g) Send command to mysql server.
help (\h) Display this help.
nopager (\n) Disable pager, print to stdout.
notee (\t) Don’t write into outfile.
pager (\P) Set PAGER [to_pager]. Print the query results via PAGER.
print (\p) Print current command.
prompt (\R) Change your mysql prompt.
quit (\q) Quit mysql.
rehash (#) Rebuild completion hash.
source (.) Execute an SQL script file.(导入SQL脚本) Takes a file name as an argument.
status (\s) Get status information from the server.
system (!) Execute a system shell command(调用系统的命令如linux).
tee (\T) Set outfile [to_outfile]. Append everything into given outfile.
use (\u) Use another database. Takes database name as argument.
charset (\C) Switch to another charset. Might be needed for processing binlog with multi-byte charsets.
warnings (\W) Show warnings after every statement.
nowarning (\w) Don’t show warnings after every statement.
resetconnection(\x) Clean session context.

Server
Linux中,一切皆命令,一切皆文件。
MySQL中,一切皆SQL,一切皆表。
DDL:数据定义语言
(1)库定义:库名& 库属性
1)创建库定义
CREATE DATABASE howell CHARSET utf8mb4;
规范:
1.库名:小写,与业务有关,不要数字开头,库名不要太长,不能使用保留字符串;
2.必须制定字符集
2)查询库定义
SHOW DATABASES;
SHOW CREATE DATABASE howell;
3)修改库定义
ALTER DATABASE howell CHARSET utf8;
注意:要从小往大了改,A-----B;那么需要B是A的严格超集;
4)删除库:注意,不代表生产操作
注意:除了管理员,任何人没有删库权限。
DROP howell;

(2)表定义
1)创建表
CREATE TABLE wp_user(
id INT NOT NULL AUTO_INCREMENT COMMENT ‘用户序号’,
name VARCHAR(64) NOT NULL COMMENT ‘用户名’,
age TINYINT UNSIGNED NOT NULL DEFAULT 18 COMMENT ‘年龄’,
gender CHAR(1) NOT NULL DEFAULT ‘F’ COMMENT ‘性别’,
cometime DATETIME NOT NULL COMMENT ‘注册时间’,
shengfen ENUM(‘北京市’,‘上海市’,‘天津市’,‘重庆市’) NOT NULL DEFAULT ‘北京市’ COMMENT’省份’,
PRIMARY KEY (id)
)ENGINE=INNODB CHARSET=utf8mb4;
建表规范:
i)表名:小写(多平台兼容性问题,windows不区分大小写),不能是数字开头,表名要和业务有关,名字不要太长,不能使用关键字;
ii)表属性必须设置存储引擎和字符集;
iii)数据类型:合适,简短,足够;
iv)必须要有主键;
v)每个列尽量设置not null,不知道填啥设定默认值(default);
vi)每个列要有注释;
2)查询表
mysql> show tables;
mysql> desc wp_user;
mysql> show create table wp_user;
3)修改表
#1.添加手机号列;
mysql> alter table wp_user add column shouji bigint not null unique key comment ‘手机号’;
#2.将手机列数据类型修改为char(11)
mysql> alter table wp_user modify shouji char(11) not null unique key comment’手机号’;
#3.删除手机号列
mysql> alter table wp_user drop shouji;
4)删除表
mysql> drop table wp_user;
业务流程

(3)DDL补充
1)手撕一张表:设计一张student表;
USE howell
CREATE TABLE howell.student(
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT ‘学号’,
sname VARCHAR(64) NOT NULL COMMENT ‘姓名’,
age TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT ‘年龄’,
gender TINYINT NOT NULL DEFAULT 2 COMMENT ‘0代表女,1代表男,2代表未知’,
addr ENUM(‘北京市’,‘上海市’,‘天津市’,‘重庆市’) NOT NULL DEFAULT ‘北京市’ COMMENT ‘地址’,
cometime DATETIME NOT NULL DEFAULT NOW() COMMENT ‘入学时间’,
telnum BIGINT NOT NULL UNIQUE KEY COMMENT ‘手机号’
)ENGINE=INNODB CHARSET=utf8mb4;
2)线上DDL操作(alter)对于生产的影响

i)SQL审核平台:yearing、inception
ii)说明:在MySQL中,DDL语句在对表进行操作时,是要锁“元数据表”的(数据库此时所有修改类的命令无法正常运行),所以在对于大表(业务繁忙的表)进行线上DDL操作时,要谨慎,尽量避开业务繁忙期。
iii)扩展:元数据是什么?类似于Linux Inode信息
iv)面试题回答要点:1.SQL语句的意思是什么:以上四条语句是对2张核心业务表进行DDL加列操作;2.以上操作带来的影响:对于大表(业务繁忙的表)进行线上DDL操作时,尽量避开业务繁忙时期;3.我们的建议:尽量避开业务繁忙期,走流程,建议使用:pt-osc工具(pt-online-scheme-change)工具减少锁表的影响,如果是8.0版本,可以不用工具。
扩展
pt-osc工具的使用

DCL:数据控制语言
grant命令
revoke命令

DML:数具操作语言
作用:对表中的数具行进行操作。
(1)insert的应用
–INSERT 应用
–规范用法
DESC student;
INSERT INTO
student(id,sname,age,gender,addr,cometime,telnum)
VALUES(1,‘张三’,18,1,‘北京市’,‘2020-02-16 11:50:00’,110);

–简约的方法
INSERT INTO
student
VALUES(2,‘李四’,20,0,‘重庆市’,‘2020-08-26 12:56:00’,112);

–部分录入数据(如含有默认值和自增)
INSERT INTO
student(sname,telnum)
VALUES(‘王五’,‘119’);

–批量录取方法
INSERT INTO
student(sname,telnum)
VALUES(‘howell1’,‘180’),(‘howell2’,‘181’),(‘howell3’,‘182’);

(2)update的应用
–update的应用
–修改指定数据行的值;
前提:需要明确修改哪一行,一般update语句到都有where的条件
UPDATE student SET sname=‘miaomiao’ WHERE id=6;

(3)delete的应用
–删除指定行的值
–前提:需要明确删除哪一行,一般delete语句都有where的条件
DELETE FROM student where id=5;

–扩展
–1.伪删除
–删除id为1的数据行;
–原操作
DELETE FROM student where id=1;
–删除原因:不想查询到该条数据
–修改表结构,添加state状态列
ALTER TABLE student ADD COLUMN state TINYINT NOT NULL DEFAULT 1;
–删除数据改为update
UPDATE student SET state=0 WHERE id=1;
–修改查询语句
SELECT * FROM student where state=1;

2.面试题:delete from student, drop table student, trucate table student 区别?
说明:1)以上三条命令都可以删除student表;
2)区别:
delete from student :逻辑上,逐行删除,数据行多,操作很慢,
并没有真正从磁盘上删除,只是在存储层打标记,磁盘空间不立即释放,HWM高水位不会降低;
drop table student :将表结构(元数据)和数据行物理层次删除;
truncate table student :清空表段中的所有数据页,物理层次
删除全表数据,磁盘空间立即释放,HWM高水位线会降低。
问题:delete\drop\truncate如果不小心删除了,他们可以恢复吗?
答:可以;常规方法:以上三种问题,都可以通过备份+日志,恢复数据,也可以通过延时库进行恢复
灵活方法:delete可以通过,翻转日志(binlog)

DQL:数据查询语言
(1)select:官方角度属于DML
1.功能:获取表中的数据行;
2.select 单独使用(MySQL独享)
1)select 配合内置函数(可以使用help查看)使用
–显示当前时间
SELECT NOW();
–显示当前使用数据库
SELECT DATABASE();
–命令拼接
SELECT CONCAT(“Hello World!”);
SELECT CONCAT(user,"@",host) FROM mysql.user;
–查看当前数据库版本
SELECT VERSION();
–查看当前登录用户
SELECT USER();
2)计算
SELECT 10*10;
3)查询数据库的参数(MySQL特有)
SELECT @@PORT;
SELECT @@SOCKET;
SELECT @@DATADIR;
–查看MySQL中所有参数
SHOW RIABLES;
–模糊查找法
SHOW VARIABLES LIKE ‘%trx%’;

3.select 标准用法-配合其他子句使用
1)单表
–默认执行顺序
SELECT
1.FROM 表1,表2…
2.WHERE 过滤条件1,过滤条件2…
3.GROUP BY 条件列1,条件列2…
3.5.SELECT LIST 列名
4.HAVING 过滤条件1,过滤条件2…
5.ORDER BY 条件列1,条件列2…
6.LIMIT 限制

–准备学习数据库
mysql -uroot -p <world.sql
DESC city;
SELECT * FROM city WHERE id<10;

–1. SELECT 配合 FROM 子句的使用
–语法
–SELECT 列 FROM 表;
–例子1:查询表中所有数据
SELECT * FROM world.city;
SELECT ID,Name,CountryCode,Districe,Population from world.city;
–查询部分列值
–例子2:查询城市名和对应的城市人口
SELECT Name,Population FROM world.city LIMIT 20,10;

–2. SELECT + FROM + WHERE 配合使用
–2.1 WHERE 配合比较比较判断符号 =,>,<,>=,<=,!=
–例子1:查询city中,中国所有城市信息;
SELECT * FROM world.city where ConutryCode=‘CHN’;
–例子2:查询city中人口数小于1000的城市;
SELECT * FROM world.city where Population<1000;

–2.2 WHERE 配合 LIKE 语句进行模糊查询;
–例子3:查询city中,国家代号是CH开头的城市信息;
SELECT * FROM world.city WHERE CountryCode LIKE ‘CH%’;
–注意:LIKE 语句使用时切忌不要出现前面带%的模糊查询,不走索引,而且只能是字符串类型;
–问题例子4:
SELECT * FROM world.city WHERE CountryCode LIKE ‘%CH%’;

–2.3 WHERE 配合逻辑连接符 AND OR
–例子5:查询中国城市中,人口大于500万的城市;
SELECT * FROM world.city
WHERE CountryCode=‘CHN’ AND Population>5000000;
–例子6:查询中国或美国的城市
SELECT * FROM world.city
WHERE CountryCode=‘CHN’ OR CountryCode=‘USA’;
–例子7:查询中国和美国城市中人口超过5000000的城市
SELECT * FROM world.city
WHERE CountryCode IN (‘CHN’,‘USA’) AND Population>500000;

–2.4 WHERE 配合 BETWEEN AND
–例子8:查询城市人口数在100万到200万之间的城市
SELECT * FROM world.city
WHERE Popualtion>=1000000 AND Population<=2000000;
SELECT * FROM world.city
WHERE Population BETWEEN 1000000 AND 2000000;

–3. SELECT + FROM + WHERE + GROUP BY
–GROUP BY 配合
–聚合函数(MAX(),MIN(),AVG(),COUNT(),SUM(),GROUP_CANCAT())使用
–GROUP_CONCAT:列转行
–说明:碰到GROUP BY 必然有聚合函数一起使用;
–例子1:统计city表中每个国家城市个数
SELECT CountryCode,COUNT(ID) FROM world.city
GROUP BY CountryCode;
–例子2:统计中国每个省的城市个数
SELECT District,COUNT(ID) FROM world.city
WHERE CountryCode=‘CHN’
GROUP BY District;
–例子3:统计每个国家的总人口
SELECT CountryCode,SUM(Population) FROM world.city
GROUP BY CountryCode;
–例子4:统计中国每个省的总人口
SELECT District,SUM(Population) FROM world.city
WHERE CountryCode=‘CHN’
GROUP BY District;
–例子5:统计中国每个省总人口,城市个数,城市名列表
SELECT District,SUM(Population),COUNT(id),GROUP_CONCAT(Name) FROM world.city
WHERE CountryCode=‘CHN’
GROUP BY District;
–说明:select list 中的列,要么时GROUP BY的条件,要么在聚合函数中出现,否则会违反SQL_mode不兼容
–原理:MySQL不支持,结果集是1行对多行的显示方式;

–4. HAVING 语句
–作用:与WHERE语句类似,HAVING属于后过滤
–场景:需要在GROUP BY+ 聚合函数后,再做判断过滤时使用
–例子1:统计中国,每个省的总人口,只显示人口数大于500w信息
SELECT District,SUM(Population) FROM world.city
WHERE CountryCode=“CHN”
GROUP BY District
HAVING SUM(Population)>5000000;

–5. ORDER BY 应用
–例子1:统计中国每个省的总人口,只显示总人口大于500w信息,并且按照总人口数从大到小排列
SELECT District,SUM(Population) FROM world.city
WHERE CountryCode=“CHN”
GROUP BY District
HAVING SUM(Popualtion)>5000000
ORDER BY SUM(Popualtion) DESC;

–6.0 LIMIT
–作用:分页显示结果集
–例子1:统计中国每个省的总人口,只显示总人口大于500w信息,并且按照总人口数从大到小排列
–只显示前五名
SELECT District,SUM(Population) FROM world.city
WHERE CountryCode=“CHN”
GROUP BY District
HAVING SUM(Popualtion)>5000000
ORDER BY SUM(Popualtion) DESC
LIMIT 5;
–显示6-10名
LIMIT 5,5;
LIMIT 5 OFFSET 5;
–显示3-5名
LIMIT 2,3;
LIMIT 3 OFFSET 2;
GROUP BY 原理:

作业2:GROUP BY + 聚合函数使用方法

  1. 应用场景:需要对一张表中,按照不同数句特点,需要分组计算统计时,会使用GROUP BY聚合函数;
  2. GROUP BY 使用核心使用方法:
    1)根据需求,找出分组条件;
    2)根据需求,使用合适的聚合函数;
    –练习
    USE school;

student:学生表
sno:学号
sname:学生姓名
sage:学生年龄
ssex:学生性别

teacher:教师表
tno:教师编号
tname:教师姓名

course:课程表
cno:课程编号
cname:课程名字
tno:教师编号

score:成绩表
sno:学号
cno:课程编号
score:成绩

–创建项目
DROP database SCHOOL;
CREATE DATABASE school CHARSET utf8mb4;
USE school;

CREATE TABLE student(
sno INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT ‘学号’,
sname VARCHAR(20) NOT NULL COMMENT ‘名字’,
sage TINYINT UNSIGNED NOT NULL COMMENT ‘年龄’,
ssex ENUM(‘f’,‘m’) NOT NULL DEFAULT ‘m’ COMMENT ‘性别’
)ENGINE=INNODB CHARSET=utf8mb4;

CREATE TABLE course(
cno INT NOT NULL PRIMARY KEY COMMENT ‘课程编号’,
cname VARCHAR(20) NOT NULL COMMENT ‘课程名字’,
tno INT NOT NULL COMMENT ‘教师编号’
)ENGINE=INNODB CHARSET=utf8mb4;

CREATE TABLE sc(
sno INT NOT NULL COMMENT ‘学号’,
cno INT NOT NULL COMMENT ‘课程编号’,
score INT NOT NULL DEFAULT 0 COMMENT ‘成绩’
)ENGINE=INNODB CHARSET=utf8mb4;

CREATE TABLE teacher(
tno INT NOT NULL PRIMARY KEY COMMENT ‘教师编号’,
tname VARCHAR(20) NOT NULL COMMENT ‘教师姓名’
)ENGINE=INNODB CHARSET=utf8mb4;

INSERT INTO student(sno,sname,sage,ssex)
VALUES(1,‘hong1’,18,‘m’),
(2,‘hong2’,26,‘f’),
(3,‘hong3’,25,‘m’),
(4,‘hong4’,21,‘m’),
(5,‘hong5’,22,‘m’),
(6,‘miao1’,21,‘m’),
(7,‘miao2’,20,‘m’),
(8,‘miao3’,19,‘f’),
(9,‘miao4’,18,‘f’),
(10,‘miao5’,19,‘m’);

INSERT INTO teacher(tno,tname)
VALUES(101,‘sir1’),
(102,‘sir2’),
(103,‘sir3’);

INSERT INTO course(cno,cname,tno)
VALUES(1001,‘linux’,101),
(1002,‘python’,102),
(1003,‘mysql’,103);

DESC sc;
INSERT INTO sc(sno,cno,score)
VALUES(1,1001,82),
(1,1002,59),
(2,1001,92),
(2,1003,90),
(3,1001,56),
(3,1002,65),
(4,1001,80),
(4,1002,86),
(4,1003,98),
(5,1003,89),
(6,1001,56),
(6,1002,89),
(7,1001,87),
(7,1003,65),
(8,1001,50),
(9,1003,89),
(10,1003,85);

–多表链接查询
–作用:我们的查询需求,单张表无法满足时,来自于多张表;
–多表链接查询类型:1)笛卡尔乘积;2)内链接;3)外链接;
–1. 笛卡尔乘积:将多张表合并成一张大表
SELECT * FROM teacher,course;
SELECT * FROM teacher JOIN course;
–2. 内链接(应用最广泛):取两个表有关联条件的数据,相当于交集
–语法:A JOIN B ON A.xx=B.xx
SELECT * FROM teacher JOIN course ON teacher.tno=course.tno;
–3. 外链接
–3.1 左外链接LEFT JOIN:左表所有数据和右表有关联条件的数据
SELECT * FROM teacher LEFT JOIN COURSE
SELECT city.name,country.name,city.population FROM city
LEFT JOIN country
ON city.countrycode=contry.code AND city.population<100
ORDER BY city.population DESC;

–简单理解:多表链接实际上是将多张表中,有关联的部分数据,合并成一张表
–然后在新表中去做 WHERE GROUP BY HAVING ORDER BY LIMIT
–左外链接:left join

–多表链接查询例子
–例子1:查询一下wuhan,所在的国家名,城市名,人口数,国土面积;
–第一步:找关联表:city:城市名city.name,城市人口city.population;country:国家名country.name,国土面积country.surfacearea.
–第二步:找关联条件city.countrycode和contry.code
–第三布:罗列其他查询条件
SELECT country.name,city.name,city.population,country.surfacearea
FROM city JOIN country ON city.countrycode=country.code
WHERE city.name=‘wuhan’;

–例子2:统计hong2学习了几门课;
SELECT student.sno,student.sname,COUNT(sc.cno) FROM student
JOIN sc ON student.sno=sc.sno
WHERE student.sname=‘hong2’ GROUP BY student.sno,student.sname;

–例子3:查询hong2学习课程名称有哪些;
SELECT student.sno,student.sname,GROUP_CONCAT(course.cname)
FROM student
JOIN sc ON student.sno=sc.sno
JOIN course ON sc.cno=course.cno
WHERE student.sname=‘hong2’
GROUP BY student.sno,student.sname;

–例子4:查询sir1老师交的学生名;
SELECT concat(teacher.tname, “_”, teacher.tno),group_concat(student.sname)
FROM teacher
JOIN course
ON teacher.tno= course.tno
JOIN sc
ON course.cno= sc.cno
JOIN student
ON sc.sno= student.sno
WHERE teacher.tname= “sir1”
GROUP BY teacher.tname, teacher.tno;

–例子5:查询sir1所交课程的平均分数;
SELECT concat(teacher.tname, “_”, teacher.tno), avg(sc.score)
FROM teacher
JOIN course
on teacher.tno= course.tno
JOIN sc
ON course.cno= sc.cno
WHERE teacher.tname= ‘sir1’
GROUP BY teacher.tname, teacher.tno;

–例子6:每位老师所交课程的平均分,并按平均分排序;
SELECT concat(teacher.tname, “_”, teacher.tno), avg(sc.score)
FROM teacher
JOIN course
on teacher.tno= course.tno
JOIN sc
ON course.cno= sc.cno
GROUP BY teacher.tname, teacher.tno
ORDER BY avg(sc.score) DESC;

–例子7:查询sir1所交不及格的学生姓名;
SELECT concat(teacher.tname, “_”, teacher.tno), group_concat(concat(student.sname, “:”, sc.score))
FROM teacher
JOIN course
ON teacher.tno= course.tno
JOIN sc
ON course.cno= sc.cno
JOIN student
ON sc.sno= student.sno
WHERE teacher.tname= “sir1” AND sc.score< 60
GROUP BY teacher.tname, teacher.tno;

–例子8:查询所有老师所交学生不及格的信息
SELECT concat(teacher.tname, “_”, teacher.tno), group_concat(concat(student.sname, “:”, sc.score))
FROM teacher
JOIN course
ON teacher.tno= course.tno
JOIN sc
ON course.cno= sc.cno
JOIN student
ON sc.sno= student.sno
WHERE sc.score< 60
GROUP BY teacher.tname, teacher.tno;

–例子9:查询平均成绩大于60分的同学的学号和平均成绩;
SELECT sc.sno, avg(sc.score)
FROM sc
GROUP BY sc.sno
HAVING avg(sc.score)> 60;

–例子10:查询所有同学的学号、姓名、选课数、总成绩;
SELECT student.sname, student.sno, count(cno) as “课程数”, sum(sc.score) as “总分”
FROM student
JOIN sc
ON student.sno= sc.sno
GROUP BY student.sname, student.sno;

–例子11:查询各科成绩最高和最低的分:以如下形式显示:课程ID、最高分、最低分
SELECT sc.cno, MAX(sc.score) as “最高分”, MIN(sc.score) as “最低分”
FROM sc
GROUP BY sc.cno;

– CASE 的使用
SELECT CASE WHEN sc.score> 90 THEN 1 END
FROM sc;

– CASE 语法:在执行列上加判断功能
CASE WHEN 判断 THEN 结果 END

–例子12:统计各位老师,所教课程的及格率
SELECT concat(teacher.tname, “_”, teacher.tno), course.cname, concat(count(case when sc.score> 60 then 1 end)/count(sc.sno)* 100, “%”) as “及格率”
FROM teacher
JOIN course
ON teacher.tno= course.tno
JOIN sc
ON course.cno= sc.cno
GROUP BY teacher.tname, teacher.tno, course.cname;

–例子13:查询每门课程被选修的学生数;
–例子14:查询出只选修了一门课程的全部学生的学号和姓名;
–例子15:查询选修课程门数超过了1门的学生信息;

–例子16:统计每门课程:优秀(85以上),良好(70-85),一般(60-70),不及格(小于60)的学生列表;
SELECT course.cname,
GROUP_CONCAT(CASE WHEN sc.score>= 85 THEN student.sname END) AS “优秀”,
GROUP_CONCAT(CASE WHEN sc.score>= 70 AND sc.score< 85 THEN student.sname END) AS “良好”,
GROUP_CONCAT(CASE WHEN sc.score>= 60 AND sc.score< 70 THEN student.sname END) AS “一般”,
GROUP_CONCAT(CASE WHEN sc.score< 60 THEN student.sname END) AS “不及格”
FROM course
JOIN sc
ON course.cno= sc.cno
JOIN student
ON sc.sno= student.sno
GROUP BY course.cname;

–例子17:查询怕
(2)外连接
作用:强制驱动表
SELECT city.name,city.population,country.name,country.surfacearea
FROM
city LEFT JOIN country
on city.CountryCode=country.Code
–此处city表就相当于驱动表(相当于for循环中的外循环),country表相当于被驱动表
驱动表是什么?
在多表连接当中,承当for循环中外层循环的角色。此时,MySQL会拿着驱动表的每个满足条件的关联列的值去依次找到for循环內循环中的关联值一一进行匹配和判断。
建议:将结果集小的表设置为驱动表更加合适,可以降低next_loop的次数。对于内链接来讲我们是没法控制驱动表是谁,完全由优化器决定。如果,需要人为干预,需要将内链接改写成外连接的方式。
建议:查询每门课程被选修的学生数

  1. 小表作为驱动表,降低next_loop次数;2. left join可以强制左表为驱动表;
    –例如
    SELECT city.name,city.population,country.name,country.surfacearea
    FROM city JOIN country
    ON city.CountryCode=country.Code
    WHERE city.name=‘wuhan’;
    –改写为强制驱动表的LEFT JOIN
    SELECT city.name,city.population,country.name,country.surfacearea
    FROM city JLEFT OIN country
    ON city.CountryCode=country.Code
    WHERE city.name=‘wuhan’;

  2. SELECT 补充
    (1)列别名
    SELECT student.sno AS ‘学号’
    FROM student;
    –作用
    1.可以定制显示的列名;
    2.可以在HAVING ORDER BY LIMIT语句中调用;
    –例子
    SELECT district AS ‘省’, SUM(population) AS ‘总人口’
    FROM world.city
    WHERE countrycode=‘CHN’
    GROUP BY district
    ORDER BY ‘总人口’ DESC
    LIMIT 5 OFFSET 0;
    (2)表别名
    SELECT student.sno
    FROM student AS s;
    –作用:全局调用定义的别名;
    (3)DISTINCT应用
    SELECT countrycode FROM world.city;
    SELECT DISTINCT(countrycode) FROM world.city;
    (4)union和union all
    –例子:查询中国或者美国的城市信息
    SELECT * FROM world.city WHERE countrycode=‘CHN’ OR countrycode=‘USA’;
    SELECT * FROM world.city WHERE countrycode IN (‘CHN’,‘USA’);
    SELECT * FROM world.city WHERE countrycode=‘CHN’
    UNION ALL
    SELECT * FROM world.city WHERE countrycode=‘USA’;

    –面试题:UNION和UNION ALL的区别
    –UNION:聚合连个结果集,会自动进行结果去重;
    –UNION ALL:聚合两个结果集,不会自动去重;

  3. show语句的介绍
    SHOW DATABASES; #查询所有的库
    SHOW TABLES; #查询use到库下的所有表
    SHOW TABLES FROM world; #查询world库下的所有表
    SHOW PROCESSLIST; #查询所有用户链接情况;
    SHOW FULL PROCESSLIST; #查询所有用户详细链接情况
    –SQL部分
    SHOW CHARSET; #查看支持的字符集
    SHOW COLLATION; #查看支持的校对规则
    SHOW ENGINES; #查看支持的引擎信息
    SHOW PRIVILEGE; #查看支持的权限信息
    SHOW GRANTS FOR; #查看某用户的权限
    SHOW CREATE DATABASE: #查看建库语句
    SHOW CREATE TABLE; #查询建表语句
    SHOW INDEX FROM; #查看表的索引信息
    SHOW ENGINE INNODB STATUS; #查询innodb引擎状态;
    SHOW STATUS; #查看数据库状态信息;
    SHOW STATUS LIKE ‘%%’ #模糊查询数据库状态;
    SHOW VARIABLES; #查看所有数据库参数
    SHOW VARIABLES LIKE ‘%%’; #模糊查询所有数据库参数
    SHOW BINARY LOGS; #查询所有二进制日志文件信息
    SHOW BINLOG EVENTS IN; #查询二进制日志事件
    SHOW MASTER STATUS; 查询二进制日志位置点信息
    SHOW SLAVE STATUS; #查询从库状态信息
    SHOW RELAYLOG EVENTS In; #查询中继日志事件

5.元数据获取 information_schema

5.1 作用:查询MySQL部分元数据信息
5.0 介绍:每次数据库启动,会自动在内存中生成I_S,生成查询MySQL部分元数据信息视图(select语句的执行方法,不保存数据本身)
CREATE VIEW v_select as
SELECT district, sum(population)
FROM world.city
WHERE countrycode=“CHN”
GROUP BY sum(population)
HAVING sum(population)> 5000000
LIMIT 5 OFFSET 0;
–调用视图
SELECT * FROM v_select;
–例子
USE information_schema常用信息介绍;
–I_S.tables视图:保存了所有表的数据字典信息
TABLE_SCHEMA 表所在的库
TABLE_NAME 表名
ENGINE 表的引擎
TABLE_ROWS 表的数据行(非实时)
AVG_ROW_LENGTH 平均行长度
DATA_LENGTH 表占用空间大小(不是实时的)
INDEX_LENGTH 表中索引占用空间大小
DATA_FREE 表中是否有碎片

–企业应用
–例子1:数据库资产统计-统计每个库下表的个数及表名
SELECT table_shema, COUNT(table_name), GROUP_CONCAT(name)
FROM information_schema.tables
GROUP BY table_schema;

–例子2:统计数据库中每个库的占用空间总大小
–一张表的大小= AVG_ROW_LENGTH* TABLE_ROWS+ INDEX_LENGTH
–一张表的大小= DATA_LENGTH
SELECT table_schema, SUM(AVG_ROW_LENGTH* TABLE_ROWS+ INDEX_LENGTH)
FROM information_schema.tables
GROUP BY table_schema;

–例子3:查询数据库中(非系统库),所有非InnoDB表,并将非InnoDB的表转换为InnoDB
SELECT table_schema, table_name FROM information_schema.tables
WHERE engine!= ‘InnoDB’
AND table_schema NOT IN (‘information_schema’, ‘sys’, ‘mysql’, ‘performance_schema’)
echo “deb https://download.sublimetext.com/ apt/stable/” | sudo tee /etc/apt/sources.list.d/sublime-text.list

-例子4:查询数据库中(非系统库),所有非InnoDB表,并将非InnoDB的表转换为InnoDB
SELECT CONCAT("ALTER TABLE “, table_schema, “.”, table_name, " ENGIN= INNODB;”)
FROM information_schema.tables
WHERE ENGIN!= “INNODB” AND table_schema not in (“sys”, “perforamnce_schema”, “information_schema”, “mysql”);
INTO OUTFILE “/tmp/alter.sql”
–此处会报错 secure-file-priv option, 安全限制,mysql不让把数据保存到本地,此时需要修改配置文件[mysqld];secure-file-priv=/tmp
–将tmp文件夹设置为安全文件夹
[mysqld]
secure-file-priv=/tmp
user=mysql
basedir=/app/database/mysql
datadir=/data/3306
server_id=6
port=3306
socket=/tmp/mysql.sock
[mysql]
socket=/tmp/mysql.sock

–重启数句库
/etc/init.d/mysqld restart

第五章 基础优化-索引及执行计划===================================================================================================================================================================

  1. MySQL索引介绍
    1.1 索引是什么?
    相当于一本书中的目录,帮助我们找到需要内容的页码;
    索引可以帮助我们快速找到所需要行的数据页码,起到优化查询的作用;
    1.2 MySQL索引类型
    Btree索引
    Rtree索引
    HASH索引
    Fulltext全文索引
    GIS地理位置索引

  2. B+Tree结构
    2.1 介绍:
    二叉树-------->平衡二叉树---------->Balance Tree
    2.2 Btree查找算法引入

2.3 Btree种类
B-TREE
B+TREE:MySQL目前使用这个查找结构:在叶子节点(数据库中数据行所在的数句页Page)加入了双向指针,方便范围查找
B*TREE

  1. MySQL B+TREE索引构建过程
    3.1 聚簇索引BTREE结构(Innodb独有)
    3.1.1 区==> 簇:64个Page(数据页)-1M
    作用:
    1.有了聚簇索引之后,将来插入的数据行,在同一个区内,都会按照ID值的顺序,有序的在磁盘存储数据;
    2.MySQL InnoDB表是聚簇索引组织存储数据表;
    3.1.2 构建前提:
    1.建表时,指定了主键列,MySQL Innodb 会将主键作为聚簇索引列,比如ID not null primary key;
    2.没有指定主键,自动选择唯一键(unioque)的列,作为聚簇索引;
    3.以上都没有,生成隐藏聚簇索引;
    3.1.3 聚簇索引的构建过程,画图说明;

3.2 辅助索引BTREE结构
3.2.1 说明
使用普通列作为条件构建的索引,需要人为创建。
3.2.2 作用
优化非聚簇索引列之外的查询条件
ALTER TABLE t1 ADD INDEX IDX(name);
3,2,3 构建过程
1.取出PK列和辅助索引列(与聚簇索引的区别,聚簇索引取整表);
2.按照辅助索引列排序,然后构建叶子节点,分配存储空间;
3.构建枝节点列,分配存储空间;
4.构建跟节点;
5.根据非聚簇索引查询,获取PK值,然后进行回表查询,再根据PK进行聚簇索引;
3.2.4 辅助索引的细分
单列索引:
多列:联合索引:
ALTER TABLE t1 ADD IDX(name, gender),枝节点时,只会提取最左列;
注意:最左原则,1.查询时必须包含最左列;2.建索引时选择重复值少的作为最左列;
例如:IDX(a,b,c): SELECT * FROM t1 WHERE a= and b= AND c= ;
前缀索引:针对与索引列值长度过长,会导致索引树高度曾增高,MySQL中建议,索引树高度3-4层;
构建过程:选取大字段的前面部分作为索引数据项;

  1. B+TREE索引树高度影响因素
    1.索引字段较长–>前缀索引;
    2.数据行过多–>分表–>归档表(pt-arhive)–>分布式架构;
    3.数据类型–>使用合适的数据类型;

  2. 索引的管理命令
    5.1 什么时候创建索引
    按照业务语句需求,创建合适的索引;并不是将所有列都建立索引。也不是索引越多越好。
    如,经常使用的语句:SELECT * FROM t1 WHERE name= ; 此时需要在name列建立索引列
    将索引建立在,经常 WHERE GROUP BY ORDER BY JOIN ON…的列中;
    为什么不能乱建索引?
    1.如果冗余索引过多的话,表数据变化的时候,很有可能导致索引的频繁更新,会阻塞一些正常的业务更新的请求
    2.索引过多,会导致优化器选择出现偏差。
    5.2 管理命令
    建索引:
    1.查询表的索引情况:PRI-主键索引;MUL-辅助索引
    mysql>DESC city;
    key: PRI-聚簇索引, MUL-辅助索引,UNI-索引
    mysql>SHOW INDEX FROM city;
    2.建立索引
    分析业务语句:
    mysql>SELECT * FROM city WHERE name=“wuhan”;
    mysql>ALTER TABLE city ADD INDEX idx_na(name); --此处idx_na是索引名字;
    联合索引:mysql>ALTER TABLE city ADD INDEX idx_n_c(name, countrycode);
    前缀索引:mysql>ALTER TBALE city ADD INDEX idx_d(district(5));
    3.删除索引
    mysql>ALTER TABLE city DROP ADD INDEX idx_na;
    5.3 压力测试
    5.4 回顾
    1.数据库中的表长什么样?
    MySQL用来存储数据行的逻辑结构,表的数据行最终存储到了很多的Page上;InnoDB存储引擎,会按照聚簇索引有序的组织存储表数据到各个区的连续的页上;这些连续的数据页,成为了聚簇索引的叶子节点。可以认为叶子节点就是原表数据。
    2.什么是回表:?
    回表即是回聚簇索引;辅助索引将辅助索引列值+ ID(PK)去构建辅助索引BTREE结构;用户使用辅助索引列作为条件查询时,首先扫描辅助索引的BTREE,
    a.如果辅助索引可以覆盖全部我们的查询结果时,则不需要回表;
    b.如果不能完全覆盖到,只能通过得出的ID主键值,回到聚簇索引(回表)扫描,最终得到想要的结果。
    3.回表的影响:IO量级变大,IOPS会增大,随机IO增大;
    4.避免回表:a.将查询尽可能用ID主键查询;b.设计合理的联合索引;c.更精确的查询条件+联合索引;d.优化器的算法MRR;
    5.更新数据时,会对索引有影响吗,数据的变化会使索引实时更新吗?
    DML语句,比如INSERT,UPDATE,DELETE 一行数据,
    a. 对于聚簇索引会立即更新;
    b. 对于辅助索引,不是实时更新的,change buffer会临时缓存辅助索引需要的数据更新,当我们需要查询新INSERT的数据,会在内存中进行merge(合并),此时我们的辅助索引时最新的,之后再在磁盘中进行更新;
    c. 在InnoDB内存结构中;

  3. 执行计划分析
    1.1 什么是执行计划
    select * from t1 where name= ‘zs’;
    分析的是优化器按照内置的代价(cost)计算算法,最终选择后的执行计划;
    对于计算机来讲,代价是:IO/ CPU/ 内存MEM;
    1.2 查看执行计划
    mysql>explain select * from world.city;或者desc命令
    mysql> desc select * from world.city;
    ±—±------------±------±-----------±-----±--------------±-----±--------±-----±-----±---------±------+
    | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    ±—±------------±------±-----------±-----±--------------±-----±--------±-----±-----±---------±------+
    | 1 | SIMPLE | city | NULL | ALL | NULL | NULL | NULL | NULL | 4046 | 100.00 | NULL |
    ±—±------------±------±-----------±-----±--------------±-----±--------±-----±-----±---------±------+
    1.3 执行计划,显示结果的分析
    table :此次执行计划涉及到的表;
    type :查询类型(全表扫描or 索引扫描);
    possible_keys :可能会用到的索引;
    key :最后选择的索引;
    key_len :索引的覆盖长度;
    rows :此次查询需要扫描的行数;
    Extra :额外的信息。
    1.4 输出信息介绍
    mysql> desc select country.name ,city.name from city join country on city.countrycode= country.code where city.population= ‘CHN’;
    ±—±------------±--------±-----------±-----±--------------±------------±--------±-------------------±-----±---------±------+
    | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    ±—±------------±--------±-----------±-----±--------------±------------±--------±-------------------±-----±---------±------+
    | 1 | SIMPLE | country | NULL | ALL | PRIMARY | NULL | NULL | NULL | 239 | 100.00 | NULL |
    | 1 | SIMPLE | city | NULL | ref | CountryCode | CountryCode | 12 | world.country.Code | 17 | 100.00 | NULL |
    ±—±------------±--------±-----------±-----±--------------±------------±--------±-------------------±-----±---------±------+
    1.4.1 table
    此次查询涉及到的表:针对查询中多个表时,精确到问题表;
    1.4.2 type
    查询类型:
    全表扫描:不用到任何的索引—>ALL;
    mysql> desc select * from city;
    mysql> desc select * from city where 1= 1;
    mysql> desc select * from city where countrycode like ‘ch%’;
    mysql> desc select * from city where countrycode not in (‘chn’, ‘usa’);
    索引扫描:index< range< ref< eq_ref< const(system)
    index:全索引扫描,扫描整个索引树; --mysql> desc select countrycode from world.city;
    range:索引的范围查询; >,<,<=,>=,like,in,or,between and; --mysql> desc select * from city where id< 10;
    例如:select * from city where countrycode in ('chn, 'usa); --改写为 select * from city where countrycode= ‘chn’ union all select * from city where countycode= ‘usa’;
    特殊情况:抓紧查询条件为主键时 --mysql>desc select * from city where id!= 10; --mysql>desc select * from city where id not in (9, 10);
    ref:辅助索引等值查询
    mysql>desc select * from city where countrycode=‘chn’;
    eq-ref:多表链接,非驱动表的链接条件是主键或唯一建;
    –A join B on a.xx= b.xx b.xx是=主键或唯一键会出现eq-ref;
    –desc select country.name, city.name from city join country on city.countrycode= country.code where city.population= ‘chn’;
    const(system):聚簇索引等值查询
    –mysql>desc select * from city where id =10;
    1.4.3 possible_key& key
    possible_key:可能会走的索引,此次查询所有有关的索引;
    key:此次查询选择的索引;
    1.4.4 key_len:联合索引覆盖的长度
    对于联合索引:index(a, b, c) --我们希望将来的查询语句,对于联合索引应用越充分越好;
    key_len:可以帮助我们判断走了联合索引的几部分
    key_len的计算:
    假设某条查询–select * from t1 where a= and b= and c= ;可以完全覆盖三列联合索引;
    则key_len= a长度+ b长度+ c长度;
    –长度是指:列的最大储值字节长度,长度收到数据类型和字符集的影响;初始化列时没有设置列not null则需要单独一个字节空间存储是否为null值;
    数字: not null 没有设置 not null
    tinyint1 1 1+1
    int 4 4+1
    bigint 8 8+1
    字符: utf8 ----->一个字符最大占3个字节,utf8mb4占4个字节
    not null 没有设置 not null
    char(10) 30 30+1
    varchar(10) 30+2(存储字符长度) 30+2+1
    例如:
    mysql>creat table t1(
    a int not null,
    b int,
    c char(10) not null,
    d varchar(10)
    )charset= utf8mb4;
    mysql>alter table t1 add index idx(a, b, c, d);
    mysql>desc select * from t1 where a=1 and b= 1, c= ‘a’, d= ‘a’;
    查询中完全覆盖到4列索引,key_len= 92;
    1.4.5 extra
    using filesort:(不正常)表示此次查询使用到了文件排序,说明在查询中的排序操作不合理; 如:order by, group by, distinct ,.
    –mysql>select * from city where countrycode= ‘CHN’ order by population;
    –mysql>alter table city add index idx_c_p(countrycode, polulation); --此处建了一个联合索引,优化前语句

  4. 索引应用规范
    2.1 建立索引的原则(DBA运维规范)
    2.1.1 说明
    为了使索引的使用更加规范,在创建索引时,必须要考虑在那些字段上shanghai索引和创建什么类型的索引。那么索引设计的原则又是什么呢?
    2.1.2 建表时一定要有主键,一般是一个无关列
    2.1.3 选择唯一性索引
    唯一性索引的值时唯一的,可以更快地通过该索引来确定某条记录;在联合索引中将唯一值最多的列作为联合索引的最左条件;
    例如,学生表中的学号是唯一的,孩子段建立唯一性索引可以很快的确定某个学生的信息,如果用名字可能存在重名,从而降低查询速度;
    优化方案:
    a.如果非得使用重复值较多的列作为查询条件(如,男女),可以将表逻辑拆分(将男女分开放);
    b.可以将此列和其他的查询类,做联合查询;
    2.1.4 为经常需要where,order by,griup by,join in等操作的字段添加索引:排序会浪费很多时间;
    2.1.5 如果索引字段的值很长,就最好使用值的前缀来索引,前缀索引
    2.1.6 限制索引的数目
    索引的数目并不是越多越好,可能产生的问题:
    a.每个索引要占用磁盘空间,索引越多,需要的磁盘空间就越大;
    b.修改表时,对索引的重构很麻烦,越多的索引,会使更新表变得浪费时间;
    c.优化器的负担会很重,有可能会影响到优化器的选择;
    d.percona-toolkit中有个工具,专门分析索引是否有用。
    2.1.7 删除不再使用的或很少使用的索引(percona toolkit)
    pt-duplicate-key-checker
    表中的数据被大量更新,或者数据的使用方法被改变后,原有的一些索引可能不需要,数据库管理员应该定期找出这些索引,将他们删除,从而减少对更新操作的影响
    2.1.8 大表加索引,要在业务不繁忙期间操作
    2.1.9 尽量少在经常更新值的列上建索引
    2.1.10 建索引原则
    a.必须要有主键,如果没有可以做为主键条件的列,可以创建无关列;
    b.经常作为where条件列,order by,group by,join on,distinct的条件;
    c.最好使用唯一值多的列作为索引,如果索引列重复值较多,可以考虑来拿和索引;
    d.列值长度较长的索引列建议使用前缀索引;
    e.降低索引条目,一方面不要创建没用的索引,不常使用的索引要清理;
    f.索引维护要避免业务繁忙器
    2.2 不走索引的情况
    2.2.1 没有查询条件,或者查询条件没有建立索引
    –mysql>select * from tab; --全表扫描
    –mysql>select * from tab where 1=1;
    在业务数据库中,特别是数据量比较大的表,是没有全表扫描这种需求的;
    a.–select * from tab; --改写成 select * from tab order by price limit 10; --需要在price列建立索引;
    b.–select * from tab where name= ‘zhangsan’; --name列没有索引 --改:换成有索引的列作为查询条件 或者 将name列建立索引
    2.2.2 查询结果是原表中的大部分数据,应该是15-30%
    查询的结果集超过了总行数的25%,优化器就觉得没有必要走索引了,跟数据库的预读能力有关,以及一些预读参数有关;
    2.2.3 索引本身失效,统计数据不真实
    索引和表有自我维护能力,对于表内容变化比较频繁的情况下,统计信息不准确,过旧。有可能出现索引失效,一般是删除重建 或者 手工收集错误信息 更新;
    现象:有一条 select 语句平时查询时都很快,突然有一天变慢,会是什么原因?select,统计数据(innodb_index_stats 和 innodb_table_stats)不真实(因为统计信息不会实时更新,需要使用如,optimize table world.city 去手动更新),导致索引失效,大量修改表后容易出现这种问题;
    2.2.4 查询条件使用函数在索引项上,或者对索引进行计算,运算包括(+,-,*,/,!等),都会导致索引失效;
    例如,–mysql>select * from city where id- 1= 9;(错误,会导致全表扫描)
    –mysql>select * from city where id= 10;
    2.3.5 隐式转换导致索引失效,这一点应该引起重视,也是开发中经常会犯的错误;这样会导致索引失效;
    如,–mysql>create table t2(id int, telnum char(11));
    mysql>alter table t2 add index idx(telnum);
    mysql>select * from t2 where telnum= 110; --不走索引,会先将110转换成’110’,做了函数运算
    mysql>select * from t2 where telnum= ‘110’; --走索引
    2.3.6 <>,not in不走索引(辅助索引)
    –mysql>desc select * from tab where telnum <> ‘155555’;
    –mysql>desc select * from tab where telnum not in (‘110’, ‘119’);
    单独的>,<,in 有可能走也有可能不走,和结果集有关(参考2.2.2),尽量结合业务添加limit;
    or 或 in尽量改写成union
    –desc select * from t2 where telnum in (‘110’, ‘119’)
    改写成
    –desc select * from t2 where telnum=‘110’ union all select * from t2 where telnum= ‘119’
    2.3.7 like "%_"百分号在最前面不走索引
    –desc select * from t2 where telnum like “31%” --走range索引扫描
    –desc select * from t2 where telnum like “%110” --不走索引
    '%linux%'类的搜索需求,可以使用elasticsearch或mongodb专门做搜索服务的数据库产品;

  5. 扩展;优化器针对索引的算法
    3.1 MySQL索引的自优化-AHI(自适应哈希索引adaptive_hash_index):索引的索引
    MySQL的InnoDB引擎能够创建的索引类型只有Btree;
    AHI的作用:自动评"热"的内存索引Page,生成HASH索引表,帮助InnoDB快速读取索引页,加速索引读取的速度;
    3.2 MySQL索引的自优化-Change buffer
    比如insert,update,delete数据,对于聚簇索引会立即更新,对于辅助索引不会实时更新;
    在InnoDB结构中,加入了insert buffer(会话),现在版本叫change buffer,其功能是临时缓冲辅助索引需要的数据更新;
    当我们需要查询新insert的数据,会在内存中进行merge(合并)操作,此时辅助索引就是最新的。
    3.3 ICP:索引下推(index_condition_pushdown)
    作用:解决了联合索引部分只能部分应用的情况,为了减少没必要的数据页被扫描,在取数据之前将不走索引的条件在引擎层做二次过滤,提前过滤掉无关数据。
    例如,index(a, b, c)
    –mysql>select * from t1 where a=yy and c=xx; --server层解析优化会判定只走a的索引,(联合索引从左到右条件过滤,此处缺少b条件,所以只有a走索引)
    –索引下推后,把第二个条件在引擎层(engine)走进行c= xx过滤,过滤好后再加载数据页,缩小了无关数据页的扫描。
    3.4 优化器算法介绍
    mysql>select @@optimizer_swith --查询
    ±----------------------------------------------------------------------------
    @@optimizer_switch
    index_merge=on,
    index_merge_union=on,
    index_merge_sort_union=on,
    index_merge_intersection=on,
    engine_condition_pushdown=on,
    index_condition_pushdown=on,
    mrr=on,
    mrr_cost_based=on,
    block_nested_loop=on,
    batched_key_access=off,
    materialization=on,
    semijoin=on,
    loosescan=on,
    firstmatch=on,
    duplicateweedout=on,
    subquery_materialization_cost_based=on,
    use_index_extensions=on,
    condition_fanout_filter=on,
    derived_merge=on,
    use_invisible_indexes=off,
    skip_scan=on
    ±----------------------------------------------------------------------------
    3.5 如何修改

    1. my.cnf
    2. mysql>set global optimizer_switch= ‘index_condition_pushdown= on’; --开启,将算法参数设置为’on’;
    3. hints --https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html
      SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY, f2_idx) / f1
      FROM t3 WHERE f1 > 30 AND f1 < 33;
      SELECT /
      + BKA(t1) NO_BKA(t2) / * FROM t1 INNER JOIN t2 WHERE …;
      SELECT /
      + NO_ICP(t1, t2) / * FROM t1 INNER JOIN t2 WHERE …;
      SELECT /
      + SEMIJOIN(FIRSTMATCH, LOOSESCAN) / * FROM t1 …;
      EXPLAIN SELECT /
      + NO_ICP(t1) / * FROM t1 WHERE …;
      SELECT /
      + MERGE(dt) / * FROM (SELECT * FROM t1) AS dt;
      INSERT /
      + SET_VAR(foreign_key_checks=OFF) */ INTO t2 VALUES(2);
      3.6 MRR- multi range read
      开启MRR(在引擎层返回作用)–mysql>set global optimizer_switch= ‘mrr= on, mrr_cost_based= off’;
      体现辅助索引 —回表—> 聚簇索引;每读取到一个辅助索引的id就要回表一次;
      转换为 辅助索引–>sort id —>回表 —> 聚簇索引;有一个缓冲区(rowid buffer),排序,然后一次性回表;
      作用:减少回表次数,减少IOPS,尽可能的减少随机IO;
      3.7 SNLJ- Simple Nested-Loops Join(SNLJ,简单嵌套循环联接)–https://dev.mysql.com/doc/refman/8.0/en/nested-loop-joins.html
      a join b on a.xx= b.yy where…;
      –伪代码
      for each row in a matching range {
      for each row in b {
      if a.xx= b.yy, send to client
      }
      }
      以上例子,可以通过left join强制驱动表
      3.8 BNLJ- Block Nested-Loop 块嵌套循环
      在a和b关联条件匹配时,不再是一行一行的匹配循环了,而是采用一次性将外层循环的关联值(存在join buffer中)和非驱动表进行匹配,一次性返回结果;
      主要优化了CPU消耗和IO次数;
      the Extra value contains Using join buffer (Block Nested Loop)
      3.9 BKA- Batched Key Access --https://dev.mysql.com/doc/refman/8.0/en/bnl-bka-optimization.html
      开启方式:–mysql>set global optimizer_switch= ‘mrr= on, mrr_cost_based= off’;
      mysql>set global optimizer_switch= ‘batched_key_access= on’;
      应用场景:非驱动表关联列(b.yy)是一个普通的辅助索引;
      在BNLJ的基础上,加入MRR算法,将存在 join buffer 中的关联值进行排序,然后再和非驱动表匹配;
      主要作用:优化非驱动表的关联列有辅助索引;
      相当于 BNLJ+ MRR;

==============================================================================================================================================================================================
第六章节 MySQL存储引擎

  1. 什么是存储引擎?
    相当于MySQL内置的文件系统,与linux中的文件系统打交道的层次结构。

  2. MySQL存储引擎种类
    2.1 Oracle MySQL
    可以针对不同的表设定不同的存储引擎,
    mysql> show engines;
    ±-------------------±--------±---------------------------------------------------------------±-------------±-----±-----------+
    | Engine | Support | Comment | Transactions | XA | Savepoints |
    ±-------------------±--------±---------------------------------------------------------------±-------------±-----±-----------+
    | MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO |
    | MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO |
    | CSV | YES | CSV storage engine | NO | NO | NO |
    | FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL |
    | PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO |
    | MyISAM | YES | MyISAM storage engine | NO | NO | NO |
    | InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES |
    | BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO |
    | ARCHIVE | YES | Archive storage engine | NO | NO | NO |
    ±-------------------±--------±---------------------------------------------------------------±-------------±-----±-----------+
    面试题:列举MySQL中支持的存储引擎种类;
    MySQL5.5以后默认的存储引擎99%以上都是InnoDB;
    2.2 其他分支
    percona: XtraDB;
    MariaDB: InnoDB;
    其他的引擎:ToKuDB:高压缩比,更快的insert和delete,适合于业务中有大量插入和删除的场景以及数据量级大的场景;
    MyRock:。

  3. InnoDB的核心特性
    3.1 介绍 -也是InnoDB与MyISAM的区别
    MVCC: 多版本并发控制;
    Clustered Index: 聚簇索引;
    多缓冲区池:
    事务:
    行级锁粒度:导致表并发度不一样 ;
    外键:
    更多复制特性:
    支持热备:
    自动故障恢复:
    Change Buffer:
    自适应hash索引(AHI):
    面试题:
    a.请你列举MySQL InnoDB存储引擎的优点?
    b.请你列举InnoDB和MyISAM的区别?

  4. 存储引擎的管理命令
    4.1 使用select确认会话存储引擎
    mysql> select @@default_storage_engine;
    ±-------------------------+
    | @@default_storage_engine |
    ±-------------------------+
    | InnoDB |
    ±-------------------------+
    4.2 存储引擎
    设置默认存储引擎:会话级别
    mysql>set default_storage_engine= myisam; --只影响当前登陆的会话;
    设置默认存储引擎:全局级别(仅影响新会话)
    mysql>set global default_storage_engine= myisam; --全局global
    重启之后,所有参数均失效;
    设置默认存储引擎:如果要永久生效,需要写入配置文件
    –vim /etc/my.cnf
    [mysqld]
    default_storage_engine= myisam
    存储引擎是表级别的,每个表创建的时候可以指定不同的存储引擎,但是建议统一为InnoDB。
    4.3 show 确认每个表的存储引擎:
    mysql> show create table city\G
    *************************** 1. row ***************************
    Table: city
    Create Table: CREATE TABLE city (
    ID int(11) NOT NULL AUTO_INCREMENT,
    Name char(35) NOT NULL DEFAULT ‘’,
    CountryCode char(3) NOT NULL DEFAULT ‘’,
    District char(20) NOT NULL DEFAULT ‘’,
    Population int(11) NOT NULL DEFAULT ‘0’,
    PRIMARY KEY (ID),
    KEY CountryCode (CountryCode),
    CONSTRAINT city_ibfk_1 FOREIGN KEY (CountryCode) REFERENCES country (Code)
    ) ENGINE=InnoDB AUTO_INCREMENT=4080 DEFAULT CHARSET=latin1

    mysql> show table status like ‘city’\G
    *************************** 1. row ***************************
    Name: city
    Engine: InnoDB
    Version: 10
    Row_format: Dynamic
    Rows: 4188
    Avg_row_length: 97
    Data_length: 409600
    Max_data_length: 0
    Index_length: 131072
    Data_free: 0
    Auto_increment: 4079
    Create_time: 2019-09-01 17:09:30
    Update_time: NULL
    Check_time: NULL
    Collation: latin1_swedish_ci
    Checksum: NULL
    Create_options:
    Comment:
    4.4 information_schema 确认每个表的储存状态
    mysql> select table_schema,table_name,engine from information_schema.tables where table_schema not in (‘sys’, ‘mysql’, ‘information_schema’, ‘performance_schema’);
    4.5 修改一个表的引擎
    mysql>alter table x engine= InnoDB;
    注意:这条命令可以经常的使用,还可以用它来进行InnoDB表的碎片整理。
    –mysql>desc information_schema;
    select table_schema,table_name,data_free from information_schema.tables; --用来查看一张表有没有碎片
    4.6 平常处理过的问题–碎片处理
    环境:centos7.4, MySQL 5.7.20, InnoDB存储引擎
    业务特点:数据量级较大,经常需要按月删除历史数据,
    问题:磁盘空间占用很大,不释放,
    处理方法:
    以前:将数据逻辑导出,手工drop表,然后导入进去;
    现在:对表按月进行分表(partition,中间件)或者归档表,业务替换为truncate;
    面试题:2 亿行的表,要删除约1000万,怎么做?
    1.如果2亿数据表还灭生成,建议在设计表时就采用分区表的方式(如,按月range),然后删除时用truncate;
    2.如果已经存在,建议使用pt-archive工具进行归档表,并且删除无用数据。
    4.6 扩展:如何批量修改
    需求1:将zabbix库中的所有表,innodb转换为tokudb
    –mysql>select concat("alter table ", table_schema, “.”, table_name, “engine= tokudb;”) from information_schema.tables where table_schema= ‘zabbix’ into outfile ‘tmp/tokudb.sql’;

  5. MySQL存储引擎体系结构
    5.1 宏观结构
    5.1.1 MyISAM
    –mysql> create table myt(id int)engine= myisam;
    myt.frm - 数据字典信息,列和它的定义以及属性
    myt.MYD - 数据行
    myt.MYI - 索引
    5.2.2 InnoDB
    磁盘区域:
    city.ibd - 用户表空间(独立表空间 File-Per-Tbale Tbalespace - 数据行和索引;
    city.frm - 数据字典信息;
    ibdata1 - 系统表空间(共享表空间)文件 - InnoDB数据字典信息、 Doublewrite Buffer、 Change Buffer、 Undo logs(事务回滚日志);
    iblogfile0~ iblogfilen - InnoDB重做日志(redo logs);
    ibtmp1 - 临时表空间文件(排序、分组、多表连接、子查询、逻辑备份等会使用临时表空间文件);
    ib-buffer-pool - 关机时把热数据放在集中位置存储(顺序IO)
    db01.err - 错误日志
    8.0:ibdata1-取消存储数据字典信息和 Undo logs,MySQL在慢慢瘦身ibdata1文件,版比较关键的数据独立出来了,分别进行存储。
    所以,仅仅拷贝ibd和frm文件到新的数据库,是无法正常使用的。
    5.2 微观结构
    一、磁盘
    5.2.2表空间
    1.什么是表空间?
    表空间概念是引入于Oracle数据库,起初是为了解决存储空间扩展的问题,MySQL5.5引入了共享表空间模式
    2.MySQL表空间类型
    共享表空间(The System Tablespace):5.5默认存储方式,用户来存储系统数据、日志、undo、临时表、用户数据和索引;
    独立表空间(File-Per-Table Tablespaces):5.6默认存储方式,单表空间(一张表一个ibd文件);
    普通表空间(General Table Tablespaces):完全和Oracle一致的表空间管理模式;可以个人定制;
    undo表空间(Undo Tablespaces):存储undo logs(回滚日志);
    临时表空间(The Temporary Tablespaces):存储临时表,5.7默认独立;
    3.表空间管理
    –查看默认表空间模式:1-独立表空间(目前默认独立表空间);0-共享表空间;
    – mysql> select @@innodb_file_per_table;
    ±------------------------+
    | @@innodb_file_per_table |
    ±------------------------+
    | 1 |
    ±------------------------+
    切换表空间:
    临时: --mysql>set global innodb_file_per_table= 0; 然后重新登录会话;
    永久: --vim/etc/my.cnf
    innodb_file_per_table= 0 --说明,修改完之后只影响新创建的表;
    拓展共享表空间的大小和个数:说明,通常在初始化数据库的时候就设定好参数;
    方法1:初始化之前,需要在my.cnf加入以下配置:
    –innodb_data_file_path= ibdata1: 1G; ibdata2: 1G: autoextend;
    方法2:已运行的数据库上拓展多个ibdata文件
    错误的方式:
    –innodb_data_file_path= ibdata1: 128M; ibdata2: 128M; ibdata3: 128M: autoextend
    正确的方式:
    –innodb_data_file_path= ibdata1: 76M; indata2: 128M; ibdata3: 128M: autoextend
    因为,在设置innodb_data_file_path参数时,已有的ibdata1文件大小应该和磁盘上的真实大小一致,而不是随便的指定。
    5.2.3段区页
    表—> 表空间—> 段—> 多个区—> 连续的Page—> 连续的block—> 连续的扇区;
    5.2.4日志
    1.事务日志:
    redo log: 重做日志- 文件位置:ib_logfile0~ ib_logfilen
    参数:–mysql>show variables like ‘%innodb_log%’;
    ±-----------------------------------±---------+
    | Variable_name | Value |
    ±-----------------------------------±---------+
    | innodb_log_buffer_size | 1048576 | #设置文件大小
    | innodb_log_checksums | ON |
    | innodb_log_compressed_pages | ON |
    | innodb_log_file_size | 50331648 |
    | innodb_log_files_in_group | 2 | #设置文件个数
    | innodb_log_group_home_dir | .\ | #设置存储位置
    | innodb_log_spin_cpu_abs_lwm | 80 |
    | innodb_log_spin_cpu_pct_hwm | 50 |
    | innodb_log_wait_for_flush_spin_hwm | 400 |
    | innodb_log_write_ahead_size | 8192 |
    ±-----------------------------------±---------+
    功能:用来存储MySQL在做一些修改类(DML:insert, update, delete)操作时的数据页变化过程及版本号(LSN),(属于物理日志);
    默认两个文件存储redo,时循环使用的。
    undo log:回滚日志- 文件位置 5.7默认位置ibdataN以及ibtmp1
    参数:–mysql>show variables like ‘%undo%’;
    ±-------------------------±-----------+
    | Variable_name | Value |
    ±-------------------------±-----------+
    | innodb_max_undo_log_size | 1073741824 | #设置文件大小
    | innodb_undo_directory | .\ | #设置文件路径
    | innodb_undo_log_encrypt | OFF |
    | innodb_undo_log_truncate | ON |
    | innodb_undo_tablespaces | 2 |
    ±-------------------------±-----------+
    –mysql>show variables like ‘%segments%’; # *回滚段参数
    ±-------------------------±------+
    | Variable_name | Value |
    ±-------------------------±------+
    | innodb_rollback_segments | 128 |
    ±------------------ -------±------+
    功能:用来存储回滚日志(版本快照),提供多版本InnoDB读写;
    提供回滚功能:记录了每条操作的反操作,属于逻辑日志;
    二、内存
    5.2.5MySQL数据内存区域= 共享内存+ 会话内存
    会话个数+ 额外的内存使用(文件系统缓存)
    共享内存缓冲区域:
    InnoDB Buffer Pool(缓冲区池):
    参数:–mysql>select @@innodb_buffer_pool_size;
    ±--------------------------+
    | @@innodb_buffer_pool_size |
    ±--------------------------+
    | 8388608 |
    ±--------------------------+
    功能:缓冲MySQL数据页+ 索引页,预分配内存区域;
    会话内存缓冲区域:
    –mysql>show variables like ‘%buffer%’;
    | join_buffer_size | 262144 |
    | key_buffer_size | 8388608 |
    | myisam_sort_buffer_size | 60817408 |
    | net_buffer_length | 16384 |
    | preload_buffer_size | 32768 |
    | read_buffer_size | 65536 |
    | read_rnd_buffer_size | 262144 |
    | sort_buffer_size
    5.2.6日志
    log_buffer_size= 16777216;
    功能:负责redo日志的缓冲;

  6. InnoDB 核心特性详解
    6.1 事务
    6.1.1 什么是事务
    事务是伴随着交易类业务场景出现的工作机制;保证交易的"和谐"(等价交易)。
    交易: a.物换物;
    b.货币换物:实物货币或虚拟货币;
    计算机中交易指:计算
    6.1.2 事务ACID标准特性介绍
    A -atomicity(原子性): 原子是物质的最小构成单元,具备不可再分割;在一个MySQL事务工作单元中,所有标准事务语句(DML),要么全成功,要么全回滚。
    C -consistency(一致性): 事务发生前中后,此次事务都应该保证数据是始终一致状态;MySQL的各项功能的设计,都是最终要保证一致性。(比如发红包中,钱的总数不变)。
    I -isolation(隔离性): MySQL可以支持多事务并发工作的系统,某个事务工作的时候,不能受其他事务的影响。
    D -durability(持久性): 当事务提交(Commit命令执行)成功后,此次事务操作的所有数据,都要永久保存下去(“落盘”),不会因为数据实例发生故障,导致数据失效。
    6.1.3 事务生命周期管理
    1.标准的事务控制语句
    begin/ start transaction: 开启事务;
    commit: 提交事务;
    rollback: 回滚事务(返回);提交后的语句不能rollback;
    –mysql>begin;
    DML1; --注意为DML语句
    DML2;
    commit;(rollback;)
    自动提交功能:
    –mysql>select @@autocommit;
    ±-------------+
    | @@autocommit |
    ±-------------+
    | 1 |
    ±-------------+
    在autocommit=1的时候,在执行dml时,没有加begin(没有显示开启事务):
    在你执行DML语句时,会自动在这个DML之前加一个begin;
    执行之后,会自动添加commit;
    begin;—>自动
    DML;
    commit;—>自动
    autocommit= 1,一般适用于非交易类业务场景;
    如果是交易类业务:
    1.设置autocommit= 0; commit,手工提交时才生效;
    2.每次想要发生事务性操作时,begin和commit都要手工操作。
    设置方法:
    1.临时生效:–mysql>set global autocommit= 0; 重新开启会话,生效;
    2.永久生效:–vim /etc/my.cnf
    autocommit= 0; --重启数据库生效;
    2.标准的事务语句
    insert
    update
    delete
    select
    例如,–mysql>begin;
    use world;
    delete from city where id> 10;
    rollback; --回滚整个事务(从begin到rollback),前面相当于什么都没做;
    –mysql>begin;
    use world;
    delete from city where id> 10;
    commit; --提交,永久保存;
    3.隐式事务控制
    a.隐式提交:
    1.设置了autocommit= 1;
    2.发生了DDL,DCL等非DML语句时,会出发隐式提交
    例如,–mysql>begin;
    DML1;
    DML2;
    drop database world;
    –会导致在DML2语句后自动添加commit;隐式提交;
    3.导致隐式提交的非实物语句:
    DDL语句:alter, create, drop;
    DCL语句:grant, revoke, set password;
    锁定语句:lock tables, unlock tables;
    其他语句:truncate table; load data infile; select for update;
    b.隐式回滚:
    1.会话断开或者死掉;
    2.数据库宕机;
    3.事务中语句执行失败。
    6.1.4 InnoDB事务的ACID如何保证?

    1. 名词介绍
      a. 重做日志
      redo log—> 重做日志 ib_logfile0~ ib_logfileN 默认2个,48M, 轮循使用
      作用:记录的是数据页的变化。
      redo内存位置:redo log buffer。
      b. 磁盘数据页存储位置
      idb文件:存储数据行和索引
      buffer pool: 缓冲区池,数据页和索引页的缓冲。
      c. LSN(log sequence number): 日志序列号
      存在于:磁盘数据页,redo文件,buffer pool,redo buffer;做版本控制;
      MySQL每次数据库启动,都会比较磁盘数据页和redolog的LSN,必须要求两者LSN一致,数据库才能正常启动;
      d. WAL: Write ahead log 日志优先写的方式实现持久化(先写日志再写数据);
      e. 脏页:内存脏页,内存中发生了修改,没写入到磁盘之前,我们把该内存也称为脏页;
      f. CKPT(check point): 检查点,就是将脏页刷写到磁盘的动作(一种工作机制);
      g. TXID(transaction id): 事务号,InnoDB会为每个事务生成一个事务号,伴随着整个事务;
      h. undo: ibdata1中存储,存储了事务工作中的回滚信息
      6.2 InnoDB事务工作流程
      6.2.1 redo
    2. redo,重做日志,事务日志的一种;
    3. ACID过程中,实现的时"D"(持久性)持久化的作用,对"A"原子性"C"一致性也有相应的作用;
    4. 日志位置:ib_logfile0~N;
    5. 内存区域:redo buffer- 记录数据页的变化信息+ 数据修改后的的LSN版本号;
    6. redo的刷新策略:commit;刷新当前事务的redo buffer到磁盘,还会顺便将一部分redo buffer中没有提交的事务日志也刷新到磁盘。
    7. 补充:redo存储的是在事务工作过程中,数据页变化,commit时会立即写入磁盘,日志落盘成功;
      正常MySQL工作过程中,主要工作是提供快速持久化功能;MySQL出现Crash异常宕机时,主要提供的是前滚功能(CSR-自动故障恢复)。
      双一标准:
      innodb_flush_log_at_trx_commit= 0/ 1/ 2;
      1 - 在每次事务提交时,会立即刷新redo到磁盘,commit才能成功;推荐使用;
      0 - 每秒刷新redo buffer到os cache, 再fysnc()到磁盘,异常宕机可能会导致丢失1s内的事务;
      2 - 每次事务提交都立即刷新redo buffer 到 os cache, 再每秒 fsync() 到磁盘,异常宕机可能丢失1s内事务。
      另外,
      1. redo buffer还和操作系统缓存机制有关,所以刷写策略可能和innodb_flush_method参数有一定关系;
      2. redo也有group commit,可以理解为,在每次刷新已提交的redo时,顺便可以将一些未提交的事务redo也一次性刷写到磁盘(但是会打上特殊标记)。
      6.2.2 undo: 回滚日志
    8. 作用:在事务ACID过程中,实现的是"A"原子性的作用;另外CI也依赖与undo;在rollback时,将数据恢复到修改之前的状态,在CSR实现的是,先redo前滚,再undo回滚 (CSR- 前滚+ 回滚)
    9. 磁盘位置:ibdata, ibtmp;
    10. undo在生成过程中也会记录redo信息;
    11. 一致性快照: 每个事务开启时都会通过Undo生成一个一致性的快照,
    12. undo提供快照结束,保存事务修改之前的数据状态,保证了MVCC, 隔离性,mysqldump的热恢复机制。
      6.2.3 隔离级别和锁机制
    13. 作用:主要是提供I(隔离性)的特性,另外对于C(一致性)的特征也有保证;
    14. transaction_isolation 事务隔离性 & 隔离级别说明
      a. RU:读未提交(READ UNCOMMITTED) - 出现的问题:脏页读,不可重复读,幻读;
      b. RC:读已提交(READ COMMITTED) - 不可重复度,幻读
      c. RR:可重复读(REPEATABLE READ)默认级别 - 有 读;
      d. SR:可串行化(SERIALIZABLE) - 串行化事务操作,不利于事务的并发。
      此处的R"读"表示:page的读取,是存储引擎层的读,不代表select(SQL层的读);
    15. 参数修改
      临时: --mysql>select @@transaction_isolation;
      ±------------------------+
      | @@transaction_isolation |
      ±------------------------+
      | REPEATABLE-READ |
      ±------------------------+
      mysql>set global transaction_isolation= ‘read-uncommitted’; --重启会话生效;
      永久修改:vim /etc/my.cnf
      transaction_isolation= ‘read-uncommitted’ --重启生效;
    16. 例子演示:
      a. 脏读:session2读到session1正在修改,但还未提交的脏页;对于脏读,在业务生产中是不允许的;
      session1:
      session2:
      b. 不可重复读现象:在同一个会话session2窗口中,执行同一条语句如(select * from city),但是不同时间段得到的结果是不一样的(因为session1事务,提交时间差导致的);比较严谨的场景下,事务的隔离性和数据最终一致性要求较高的业务,不允许出现的;
      c. 幻读:在一个事务更新过程中,出现了其他事务操作过的数据,导致更新出现不应该出现的问题(session1 commit前,session2 commit,此时就会得要意料之外的结果);
      d. 通过RR,已经可以解决99%以上的幻读,为了更加严谨,加入了GAP锁,next-lock;
      6.3 MySQL的锁机制
      6.3.1 介绍
      6.3.2 作用
      保证事务的隔离性,保证资源不会被征用;锁是属于资源的,不是某个事务的,每次事务需要资源的时候,需要申请持有资源的锁。
      6.3.3 锁的类型
    17. 资源:
      a. 内存锁: mutex, latch, 保证内存数据页资源不被争用,不被置换。
      b. 对象锁: MDL(元数据锁): 修改元数据时(属性类修改),DDL操作—> alter;
      Table_lock,: 表锁;DDL,备份时(FTWRL全局表锁),也有可能升级而来(由行锁升级)触发表锁; --mysql>lock tables city;
      record(row) lock: 行锁,索隐锁,锁定聚簇索引
      GAP: 间隙锁,RR级别,普通辅助索引间隙锁
      Next-lock : 下一键锁GAP+ record lock,普通辅助索引的范围锁。
    18. 粒度:对象锁的一些粒度
      MDL(元数据锁): 修改元数据时(属性类修改),DDL操作—> alter;粒度高
      Table_lock,: 表锁;DDL,备份时(FTWRL全局表锁),也有可能升级而来(由行锁升级)触发表锁; --mysql>lock tables city; 粒度高
      record(row) lock: 行锁,索隐锁,锁定聚簇索引;一行的话粒度低
      GAP: 间隙锁,RR级别,普通辅助索引间隙锁;范围锁;
      Next-lock : 下一键锁GAP+ record lock,普通辅助索引的范围锁。
    19. 功能上分类:
      IS: 意向共享锁 ,表级别
      S: 共享锁,读锁 ,行级别
      IX: 意向排他锁 ,表级别
      X: 排他锁,写锁 ,行级别
      行锁,例子
      session1 session2
      mysql>update x set num= 2 where id= 1; mysql>update x set num= 481 where id= 40; --session1和session2之间没有阻塞
    20. 查看锁等待 --mysql>select * from sys.innodb_lock_waits\G
    21. 死锁:两个事务之间出现了资源的交叉争用;
      查看死锁: --mysql>show engine innodb status\G
      或,–vim /etc/my.cnf
      unnodb_print_all_deadlocks= 1 --打印所有死锁信息
      处理流程:得到监控数据----->trx_id, thread -----> SQL。
    22. 乐观锁和悲观锁
      抢火车票;乐观锁:一定没人跟我抢,过会再付款;悲观锁:一定有人跟我抢,先锁定,然后付款;
      乐观锁一般配合队列使用。
      6.4 事务的一致性ACID的C的特性
      A: 原子性,undo(回滚), redo(前滚);
      C: 一致性,保证事务工作前,中,后,数据的最终状态都是完整的;
      I: 隔离性,isolation level, 锁的机制,MVCC一致性快照(undo日志);
      D: 持久性,commit的数据,redi(WAL)。

    C(一致性)的特性,是以上所有特性来保证一致性的;
    写一致性:undo,redo,isolation,lock;
    读一致性:isolation level,MVCC;
    数据页的一致性:double write buffer(磁盘区域):往磁盘写之前,先顺序往ibdata1中的double write buffer中写,写完后再在原数据更新。

  7. 存储引擎核心参数
    7.1 innodb_flush_log_at_trx_commit= 1/0/2 (双一标准之一)控制redo log 刷写参数;
    1- default, logs are writen and flushed to disk at each transaction commit.
    0- logs are writen and flushed to disk once per second.
    2- logs are written after each transaction commit and flushed to disk once per second.
    7.2 innodb_flush_method= fsync/ O_DIRECT/ O_DSYNC;
    作用:控制MySQL刷写磁盘时是否使用OS Cache;
    fsync模式- buffer pool的数据写磁盘的时候,需要先经过OS Cache,然后再写到磁盘; —默认是fsync模式
    redo buffer的数据写磁盘的时候,需要先经过OS Cache,然后再写到磁盘。
    O_DSYNC模式- buffer pool的数据写磁盘的时候,需要先经过OS Cache,然后再写到磁盘; —生产中不建议使用
    redo buffer的数据写磁盘的时候,穿过OS Cache。
    O_DIRECT模式- buffer pool的数据写磁盘的时候,直接写磁盘,跨过OS Cache; —生产中建议使用O_DIRECT,最好是配合固态盘使用
    redo buffer的数据写磁盘的时候,需要先经过OS Cache,然后再写到磁盘。
    7.3 innodb_buffer_pool_size
    作用:控制数据缓冲区的总大小(缓冲数据页和索引页),是MysQL最大的内存区域;
    默认:128M;
    官方建议:80%- 90%;容易出现OOM;
    生产建议:75%一下,按需设置。
    OMM(内存溢出)? 解决方案 ----> innodb_buffer_pool_size= 75* Total

第七章 日志管理 ==============================================================================================================================================================================

  1. 错误日志
    1.1 作用:
    记录MySQL从启动以来,所有的状态,警告,错误;为我们定位数据库的问题,提供帮助;
    1.2 配置方法
    默认:开启状态;
    位置:/datadir/hostname.err
    mysql> select @@datadir;
    ±--------------------------------------------+
    | @@datadir |
    ±--------------------------------------------+
    | C:\ProgramData\MySQL\MySQL Server 8.0\Data\ |
    ±--------------------------------------------+
    定制位置:–vim/etc/my.cnf
    log_error= /tmp/mysql.log —重启生效:/etc/init.d/mysqld resart
    1.3 怎么用?

  2. binlog 二进制日志
    2.1 作用:数据恢复和主从复制中应用,主要记录数据库变化性质的日志;(包括DDL,DCL,DML), 是逻辑性质日志;
    2.2 配置方法:
    默认:没有开启 8.0以前,8.0以后自动开启,生产建议开启;
    vim /etc/my.cnf
    server_id= 6 #主机编号,主从中使用,5.7之后开binlog要加这个参数;
    log_bin= /data/binlog/mysql-bin #日志存放目录+ 日志名前缀(如,mysql-bin.00001);
    sync_binlog= 1 #binlog日志刷盘策略,双一中的第二个(第一个是redo log的刷盘策略innodb_flush_log_at_trx_commit);1- 每次事务提交,binlog cache中日志立即刷写bin log到磁盘;
    binlog_format= row #控制bin log的记录模式为row模式。
    –重启生效,注意路径要有且有权限。一定要和数据盘分开
    2.3 binlog记录内容详情
    2.3.1 引入
    binlog是SQL层的功能,记录的是变更的SQL语句,不记录查询语句;
    2.3.2 记录SQL语句种类
    DDL:原封不动的记录当前DDL(statement语句方式),执行啥记录啥;
    DCL:原封不动的记录当前DCL(同上);
    DML:只记录已经提交的事务DML;
    2.3.3 DML三种记录方式
    binlog_firmat(binlog的记录模式)参数影响,且之影响DML语句的记录方式,不影响DDL和DCL;
    a. statement(5.6默认)SBR(statement based replication)模式: 语句模糊原封不动的记录当前DML;
    b. row(5.7默认) RBR(Row based replication)模式: 记录数据行的变化(用户看不懂,需要工具分析);
    c. mixed(混合) MNR(mixed based replication)模式:以上两种的混合,由MySQL去选择哪种好。
    2.3.4 面试题
    SBR与RBR模式对比
    STATEMENT:可读性高,日志量小,但是不够严谨;
    ROW :可读性低,日志量大,足够严谨。
    如, --mysql>update t1 set xxx= xxx where id> 1000; ?一共500w行 —此时statement只需记录这条DML语句,而RBR则记录500w行数据;
    2.4 事件是什么?
    2.4.1 事件的简介
    二进制的最小记录单元是事件;
    对于DDL,DCL,一个语句就是event;对于DML来讲:只记录已提交的事务。—mysql>begin; DML1; DML2; commit; —记录了4个event;
    2.4.2 event的组成
    三部分组成: position
    a. 事件的开始标识: at 194;
    b. 事件内容:
    c. 事件结束标识: end_log_pos 254;
    位置号(position)的作用:方便我们截取事件。
    2.5 binlog的查看
    文件位置: --select @@log_bin_basename;
    ±--------------------------------------------------------+
    | @@log_bin_basename |
    ±--------------------------------------------------------+
    | C:\ProgramData\MySQL\MySQL Server 8.0\Data\HOWELL-L-bin |
    ±--------------------------------------------------------+
    查看开启状态: --select @@log_bin;
    ±----------+
    | @@log_bin |
    ±----------+
    | 1 |
    ±----------+
    2.5.2 文件查看 --#ls -l /data/binlog/
    2.5.3 二进制内置查看命令
    a. 查看目前有几个日志文件; --mysql>show binary logs;
    ±--------------------±----------±----------+
    | Log_name | File_size | Encrypted |
    ±--------------------±----------±----------+
    | HOWELL-L-bin.000020 | 351 | No |
    ±--------------------±----------±----------+
    b. 查看当前在用日志文件; --mysql>show master status;
    ±--------------------±---------±-------------±-----------------±------------------+
    | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
    ±--------------------±---------±-------------±-----------------±------------------+
    | HOWELL-L-bin.000020 | 351 | | | |
    ±--------------------±---------±-------------±-----------------±------------------+
    c. 查看二进制日志事件; --mysql>show binlog events in ‘HOWELL-L-bin.000020’;
    ±--------------------±----±---------------±----------±------------±----------------------------------------------------+
    | Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
    ±--------------------±----±---------------±----------±------------±----------------------------------------------------+
    | HOWELL-L-bin.000020 | 4 | Format_desc | 1 | 124 | Server ver: 8.0.17, Binlog ver: 4 |
    | HOWELL-L-bin.000020 | 124 | Previous_gtids | 1 | 155 | |
    | HOWELL-L-bin.000020 | 155 | Anonymous_Gtid | 1 | 232 | SET @@SESSION.GTID_NEXT= ‘ANONYMOUS’ |
    | HOWELL-L-bin.000020 | 232 | Query | 1 | 351 | use world; create table myt(id int)engine= myisam |
    ±--------------------±----±---------------±----------±------------±----------------------------------------------------+
    2.6 binlog 文件内容查看及数据恢复
    2.6.1 事件查看
    –#mysql -uroot -pzxcv -e “show binlog events in ‘HOWELL-L-bin.000020’” |grep DROP
    2.6.2 binlog日志内容查看
    –#mysqlbinlog HOWELL-L-bin.000020;
    –#mysqlbinlog HOWELL-L-bin.000020> /tmp/a.sql
    #vim /tmp/a.sql
    a. DDL:
    # at 219
    #200225 17:52:16 end_log_pos 338
    create database oldguo charset utf8mb4;
    # at 338
    b. DML:
    # at 690
    #200225 17:55:53 server id 5 end_log_pos 763
    BEGIN

    # at 763

    # at 821

    # at 1107
    COMMIT

    –#mysqlbinlog --base64-output=decode-rows -vvv HOWELL-L-bin.000020 > /tmp/b.sql --详细显示,仅限于查看详细内容
    –#mysqlbinlog --help
    2.6.3 日志截取恢复
    mysql>flush logs; --刷新出一个新的日志文件,滚动一个新的日志;
    日志恢复案例:
    –数据准备
    mysql>create database bindb charset utf8mb4;
    mysql>use bindb;
    mysql>create table t1(id int);
    mysql>begin;
    mysql>insert into t1 values(1),(2),(3);
    mysql>commit;
    mysql>begin;
    mysql>insert into t1 values(4),(5),(6);
    –删除数据库
    mysql>drop database bindb;
    –根据日志进行数据恢复
    –1. 分析binlog,找到起点终点;
    –起点:HOWELL-L-bin.000021 | 232 | Query | 1 | 359 | create database bindb charset utf8mb4 /* xid=872 /
    –终点:HOWELL-L-bin.000021 | 1196 | Query | 1 | 1303 | drop database bindb /
    xid=885 */
    mysql>show master status;
    mysql>show binlog events in ‘HOWELL-L-bin.000021’;
    –2. 截取日志
    #mysqlbinlog --start-position=232 --stop-position=1196 /data/binlog/HOWELL-L-bin.000021 >/tmp/bin.sql --windows下需要cd到binlog文件目录下;
    –windows操作系统下C:\ProgramData\MySQL\MySQL Server 8.0\Data>mysqlbinlog --start-position=232 --stop-position=1196 HOWELL-L-bin.000021> bin.sql
    mysql>set sql_log_bin= 0; --再当前会话关闭binlog
    mysql>source /tmp/bin.sql; --恢复
    –windows为:mysql> source C:\ProgramData\MySQL\MySQL Server 8.0\Data\bin.sql
    mysql>set sql_log_bin= 1;
    –验证数据
    mysql>select * from bindb.t1;
    思考?如果是生产环境中,此种恢复手段会有什么弊端?
    a. 数据多了怎么办?数据行多
    b. binlog记录不单单一个数据库的操作,可能对其他数据库重复操作; #mysqlbinlog -d bindb --start-position=219 --stop-position=1357 /data/binlog/mysql-bin.0000005
    c. 创建了几年,期间一直在使用,插入的数据操作从bin_log.0000001到bin_log.0012314123; --每周六23:00全备份,binlog每天23:00备份
    d. 跨多文件,可以使用时间截取。
    binlog实际上是我们数据恢复时配合备份一起使用的。
    2.7 binlog维护操作
    2.7.1 日志滚动
    mysql>flush logs; --手动出发滚动日志
    #mysqladmin -uroot -phowell flush-logs --滚动日志
    mysql>select @@max_binlog_size; --如果日志文件达到1G,自动滚动
    ±------------------+
    | @@max_binlog_size |
    ±------------------+
    | 1073741824 |
    ±------------------+
    mysqldump -F --自动滚动
    重启数据库 --自动滚动,触发创建新binlog
    2.7.2 日志删除
    注意:不要使用rm命令删除日志。
    mysql>select @@expire_logs_days; --自动删除,默认0,单位是天,代表永不删除。多少天合适?超过一个全备周期;生产中一般建议最少两个全备周期合适;
    ±-------------------+
    | @@expire_logs_days |
    ±-------------------+
    | 0 |
    ±-------------------+
    mysql>purge binary logs to ‘mysql-bin.000010’; --手工删除,删除到00010号为止
    mysql>purge binary logs before ‘2-19-04-02 22:46"26’; --删除多久之前的
    mysql>reset naster; --清空,注意:比较危险,在主库执行此操作,主从必宕。
    2.8 binlog的GTID模式管理-global transaction id
    2.8.1 介绍
    5.6新加的特性,5.7和8.0做了加强;5.7中的GTID,即使不开也会自动生成 SET @@SESSION.GTID_NEXT= ‘ANONYMOUS’
    2.8.2 GTID(Global Transaction ID)
    是对于一个已提交事务的编号,并且是一个全局唯一的编号。
    GTID= server_uuid: transaction_id
    7E11FA47-31CA-19E1-9E56-C43AA21293967:29
    2.8.3 开启
    vim /etc/my.cnf
    gtid-mode= on
    enforce-gtid-consistency= true
    –查看gtid是否开启 mysql>select @@gtid_mode;
    ±------------+
    | @@gtid_mode |
    ±------------+
    | OFF |
    ±------------+
    mysql>show master status;
    ±--------------------±---------±-------------±-----------------±------------------+
    | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
    ±--------------------±---------±-------------±-----------------±------------------+
    | HOWELL-L-bin.000023 | 155 | | | |
    ±--------------------±---------±-------------±-----------------±------------------+
    2.8.4 基于GTID进行查看binlog
    具备GTID后,截取查看某些事务日志;
    –include-gtids
    –exclude-gtids: 排除
    –skip-gtids
    例子+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    mysql>show master status;
    mysql>create database gtdb charset utf8mb4;
    mysql>use gtdb
    mysql>create table t1(int id);
    mysql>begin;
    mysql>insert into t1 values(1),(2),(3);
    mysql>commit;
    mysql>flush logs;
    mysql>show master status;
    ##第二波命令++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    mysql>create table t2(id int);
    mysql>begin:
    mysql>insert into t2 values(1),(2),(3);
    mysql>commit();
    mysql>flush logs;
    mysql>show master status;
    ##第三波命令++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    mysql>create table t3(id int);
    mysql>begin;
    mysql>insert into t3 values(1),(2),(3);
    mysql>commit;
    mysql>show master status;

     	mysql>drop database gtbd;
     	++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     	#截取日志:gtid:7- 13
     	#起点:SESSION.GTID_NEXT= '1a79e16f-cc98-11e9-b42b-80fa5b693575:7'
     	#终点:SESSION.GTID_NEXT= '1a79e16f-cc98-11e9-b42b-80fa5b693575:14'
     	mysql>show master status;
     	mysql>show binlog events in 'HOWELL-L-bin.000028'; --查看最后一个binlog
     	--内容| HOWELL-L-bin.000028 | 666 | Gtid           |         1 |         743 | SET @@SESSION.GTID_NEXT= '1a79e16f-cc98-11e9-b42b-80fa5b693575:14' |
     	mysql>show binlog events in'HOWELL-L-bin.000026';  --查看第一个binlog 找到创建gtdb时的gtid;
     	++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     	--gtid:7_13; 文件:HOWELL-L-bin.000026,HOWELL-L-bin.000027,HOWELL-L-bin.000028;
     	+++开始截取++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     	--先cd 到binlog文件目录下
     	mysqlbinlog --include-gtids= '1a79e16f-cc98-11e9-b42b-80fa5b693575:7-13' HOWELL-L-bin.000026 HOWELL-L-bin.000027 HOWELL-L-bin.000028> gtid.sql
     	--此时并不能恢复gtdb,开启GTID后,MySQL恢复Binlog,重复GTID的事务不会在执行了,此时我们需要使用 --skip-gtid参数
     	mysqlbinlog --skip-gtid --include-gtids= '1a79e16f-cc98-11e9-b42b-80fa5b693575:7-13' HOWELL-L-bin.000026 HOWELL-L-bin.000027 HOWELL-L-bin.000028> gtid2.sql
     	mysql>set sql_log_bin= 0;  	--再当前会话关闭binlog
     	mysql>source /tmp/bin.sql;	--恢复
     	--windows为:mysql> source C:\ProgramData\MySQL\MySQL Server 8.0\Data\gtid2.sql
     	mysql>set sql_log_bin= 1;
     	--验证数据
     	mysql>show databases;
    

2.8.5 GTID的幂等性
开启GTID后,MySQL恢复Binlog,重复GTID的事务不会在执行了,我们在执行语句的时候及创建的时候该gtid已经在计算机中执行过一次
–skip-gtids

  1. slowlog 慢日志
    3.1 作用
    记录MySQL运行过程中运行较慢的语句,通过一个文本的文件记录下来,帮助我们进行优化的工具日志
    3.2 配置方法
    3.2.1 参数配置:
    mysql>select @@slow_query_log; #是否开启;
    ±-----------------+
    | @@slow_query_log |
    ±-----------------+
    | 1 |
    ±-----------------+
    mysql> select @@slow_query_log_file; #文件存放日志;
    ±----------------------+
    | @@slow_query_log_file |
    ±----------------------+
    | HOWELL-L-slow.log |
    ±----------------------+
    mysql> select @@long_query_time; #慢语句认定时间阈值,默认10s;
    ±------------------+
    | @@long_query_time |
    ±------------------+
    | 10.000000 |
    ±------------------+
    mysql> select @@log_queries_not_using_indexes; #不走索引的查询,默认关闭;
    ±--------------------------------+
    | @@log_queries_not_using_indexes |
    ±--------------------------------+
    | 0 |
    ±--------------------------------+
    3.2.2 修改配置
    vim /etc/my.cnf
    show_query_log= 1
    slow_query_log_file= /data/3306/db01-slow.log
    long_query_time= 1
    log_queries_not_using-indexes= 1
    #重启数据库生效
    3.2.3 慢语句分析
    mysqldumpslow -s c -t 5 db01-slow.log
    -s c : 按照执行次数排序
    -t 5 : top5,排名靠前的5条
    然后使用explain和desc查看执行计划;
    3.2.4 扩展 pt-query-digest + Amemometer 可视化演示

第八章 备份恢复================================================================================================================================================================================

  1. MySQL数据损坏
    1.1 物理损坏
    磁盘损坏:硬件,磁坏道,dd,格式化;
    文件损坏:数据文件损坏,日志文件损坏;
    1.2 逻辑损坏
    drop
    delete
    truncate
    update

  2. DBA运维人员在备份、恢复的职责
    2.1 设计备份和容灾的策略
    2.1.1 备份策略
    备份工具的选择
    备份周期的设定
    备份监控方法
    2.1.2 容灾策略
    备份:用什么备份?
    架构:高可用,演示从库,灾备库
    2.2 定期的备份、容灾检查

2.3 定期的故障恢复演练

2.4 数据损坏时快速准确的恢复

2.5 数据迁移工作

  1. 备份工具
    3.1 逻辑备份方式: 备份的SQL语句
    mysqldump(MDP)
    mydumper(自行扩展)
    load data in file(自行扩展)
    主从方式
    3.2 物理备份方式: 备份的数据文件
    MySQL Enterprise Backup(企业版)
    Percona Xtrabackup(PBK, XBK)
    3.3 架构备份方式

  2. mysqldump(MBP) 应用
    4.1 介绍
    逻辑备份工具。备份的时SQL语句。
    选择场景:数据量较少,100G以内1-2小时;
    优点:可读性比较强,压缩比高,不需要下载安装,分布式架构中(数据量级)可以采用分布式备份;
    缺点:备份时间相对较长,恢复时间更长。
    4.2 备份方式
    4.2.1 InnoDB表
    InnoDB可以采取快照的备份方式(不需要锁表)。开启一个独立的事务,获取当前最新的一致性快照.将快照数据,放在临时表中,转换成SQL语句(create database, create table, insert),保存到sql文件中。
    4.2.2 非InnoDB表-不支持事务
    需要锁表备份。触发FTWRL,全局锁表,转换成SQL,保存到sql中。
    4.3 mysqldump的核心参数
    4.3.1 连接相关的参数
    -u :数据库用户
    -p :密码
    -h :设置连接的服务器名或者Ip
    -P :设置端口
    -S :连接服务器的socket文件
    可以看出mysqldump支持远程备份。
    4.3.2 备份参数
    -A : 全备 --mysqldump -uroot -p123 -S /tmp/mysql.scok -A>/data/backup/full.sql ##windows##C:\Users\Howell.L>mysqldump -uroot -p123 -S -A> D:\data\backup\full.sql;
    -B : 备份一个或多个库 --mysqldump -uroot -p123 -B world bindb> D:\data\backup\world_bindb.sql;
    -S : 若不加socket文件位置,mysql会自动去tmp目录下找,如果在其他位置则需要指明;
    : 备份单个或多个表 --mysqldump -uroot -p123 -S world city country> D:\data\backup\world_country_city.sql;
    验证一下:mysqldump -uroot -p123 -B world> > D:\data\backup\db1.sql和
    mysqldump -uroot -p123 world> D:\data\backup\db1.sql的区别:
    结果一样,但是第一条语句比别人条隐含多两条语句:create database world; use world; 第二条备份数据表,且第二条语句应用时:若world库不存在,需要手工创建,并且use到world数据库下
    4.3.3 备份高级参数
    –master-data= 2 (非常重要)一般认为实际生产中必加参数
    场景:若每周日23:00进行全备,每天备份binlog。周三时有人把数据库删了:
    恢复全备+ 所有需要binlog恢复。
    痛点:binlog的截取;
    起点:比较困难
    终点:drop之前的位置点。
    解决:1.备份开始时,切割日志。 -F 备份开始的时候,刷新日志(一个库一个,一般不用这个参数);mysqldump -uroot -p123 -A -F> /data/backup/full2.sql
    2.备份开始时,自动记录当前日志文件状态信息 --master-data= 2。
    参数介绍:#mysqdump --help:
    This causes the binary log position and filename to be appended to the output. If equal to 1, will print it as a CHANGE MASTER command; if equal to 2, that command will be prefixed with a comment symbol. This option will turn --lock-all-tables on, unless --single-transaction is specified too (in which case a global read lock is only taken a short time at the beginning of the dump; don’t forget to read about --single-transaction below). In all cases, any action on logs will happen at the exact moment of the dump. Option automatically turns --lock-tables off.
    =1 : 以命令写到备份文件中;
    =2 : 以注释写到备份文件中
    功能:
    1. 备份时自动记录binlog信息;
    2. 自动锁表和解锁;
    3. 配合single transacion 可以减少锁表的时间。
    示例: mysqldump -uroot -p123 -A --master-data= 2 >data/backup/full.sql
    –single-transaction 一般认为生产中必加参数
    官方说明:mysqldump --help
    Creates a consistent snapshot(一致性快照) by dumping all tables in a single transaction. Works ONLY for tables stored in storage engines which support multiversioning (currently only InnoDB does); the dump is NOT guaranteed to be consistent for other storage engines. While a --single-transaction dump is in process, to ensure a valid dump file (correct table contents and binary log position), no other connection should use the following statements: ALTER TABLE, DROP TABLE, RENAME TABLE, TRUNCATE TABLE, as consistent snapshot is not isolated from them. Option automatically turns off --lock-tables.
    功能:
    对于InnoDB引擎表备份时,开启一个独立事务,获取一致性快照进行备份。(扩展:热备-减少数据备份过程中对数据库的影响),如果不加这个参数会进行全局锁表,看–master-data。
    示例:
    mysqldump -uroot -p123 -A --master-data= 2 --single-transaction> /data/backup/full.sql
    -R -E --triggers 也是生产过程中必备的
    -R 备份过程中一起备份存储过程和函数
    -E 备份事件
    –triggers 备份触发器
    示例: mysqldump -uroot -p123 -A --master-data= 2 --single-transaction -R -E --triggers> /data/backup/full.sql
    –max_allowed_packet= 64M 必加参数,注意备份时从服务端往客户端传数据
    ±---------------------+
    | @@max_allowed_packet |
    ±---------------------+
    | 4194304 |
    ±---------------------+
    设置超出数据包的最大传输大小;若超过大小,会报错 1153-Got a packet bigger than ‘max_allowed_pocket’ bytes
    示例 :mysqldump -uroot -p123 -A --master-data= 2 --single-transaction -R -E --triggers --max_allowed_packet= 64M

  3. 基于mysqldum+ binlog 故障恢复案例
    5.1 场景
    基础环境:centOS 7.6 + MySQL 5.7.38, LNMT网站业务, 数据量100G, 5-20M增长每天;
    备份策略:mysqldump每天全备,binlog定时备份;
    故障模拟:模拟三上午10点数据故障,例如:核心业务库被误删除;
    5.2 恢复思路

    1. 挂维护页;
    2. 找测试库,进行数据恢复(MySQL为覆盖恢复,所以要找测试库进行恢复);
    3. 恢复周二的全备;
    4. 截取周二全备----->周三10点误删前的binlog,并恢复;
    5. 测试业务功能是否正常;
    6. 恢复业务:1.故障库导回到原生产;2.直接用测试库充当生产,先跑着;
      5.3 模拟数据损坏及恢复
    7. 模拟原始数据
      create database test1 charset utf8mb4;
      use test1;
      create table t1(id int);
      begin;
      insert into t1 values(1),(2),(3);
      commit;
    8. 模拟周二晚上全备
      #mysqldump -uroot -p -A --master-data=2 --single-transaction -R -E --triggers --max_allowed_packet=64M> D:\data\backup\test.sql
    9. 模拟周三白天数据变化
      use test1;
      create table t2(id int);
      begin;
      insert into t2 values(1),(2),(3);
      commit;
    10. 搞破坏
      drop database test1;
    11. 开始恢复
      5.1 检查全备
      – CHANGE MASTER TO MASTER_LOG_FILE=‘HOWELL-L-bin.000030’, MASTER_LOG_POS=1736;
      5.3 恢复全备
      source D:\data\backup\test.sql; (此处不需要set sql_log_bin= 0,因为备份中自动加了这条语句)
      或者 mysql -uroot -p< D:\data\backup\test.sql
      5.4 截取日志
      获取起点: grep “-- CHANGE MASTER TO”
      获取终点: mysql>show master status;
      show binlog events in ‘HOWELL-L-bin.000030’;
      position 截取:
      mysqlbinlog --skip-gtids --start-position=1736 --stop-position= 1989 C:\ProgramData\MySQL\MySQL Server 8.0\Data\HOWELL-L-bin.000030> binlog.sql
      GTID截取
      mysqlbinlog --skip-gtids --include-gtids= ‘1a79e16f-cc98-11e9-b42b-80fa5b693575:15-16’ C:\ProgramData\MySQL\MySQL Server 8.0\Data\HOWELL-L-bin.000030> binlog.sql> binlog2.sql
      5.5 恢复binlog
      mysql>set sql_log_bin= 0;
      mysql>source binlog.sql;
      mysql>set sql_log_bin= 1;
  4. Percona Xtrabackup
    7.1 安装
    7.1.1. 安装依赖包 wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
    7.1.2 下载软件并安装
    7.2 介绍
    物理备份工具,拷贝数据文件,比mysqldump快很多;原生态支持全备和增量。

    1. InooDB表:
      热备份:业务正常发生的时候可以进行备份,影响比较小的备份方式;
      1. checkpoint:将已提交数据页刷新到磁盘,会记录一个LSN号;
      2. 拷贝InnoDB表相关的文件(ibdata,frm,ibd);
      3. 如果备份期间产生的新的数据变化,redo也会备份走。
        2, 非InnoDB表:
        温备份:锁表备份(全局锁)。
      4. FTWRL,触发全局锁;
      5. 拷贝非InnoDB的数据;
      6. 解锁;
    2. 再次统计LSN号码,写入到专用文件,记录二进制日志位置进行保存。
    3. 所有的备份文件统一存放在一个目录下
      7.3 XBK应用-全备和恢复
      7.3.1 前提
    4. 数据库必须启动;
    5. 能连上数据库;
      配置文件my.cnf中指定socket,需要在配置文件中加入,
      [client]
      socket=/tmp/mysql.sock
    6. 默认会读取[mysqld]----> datadir= xxxxxxx
    7. 服务器端工具,不能远程备份;
      7.3.2 使用-全备
      #innobackupex --user=root --password=123 /data/xbk
      #innobackupex --user=root --password=123 --no-timestamp /data/xbk/full_‘date +%F’ ##控制输出文件夹名字
      7.3.3 备份结果查看
      需要着重关注xtrabackup_binlog_info(记录备份后binlog为位置信息,方便做binglog截取位置点),
      xtrabackup_checkpoints(备份过程中的LSN记录,方便做增量备份)
      7.3.4 全备恢复演练
      破坏
      pkill mysqld
      rm -rf /data/3306/* #破坏
      备份处理:prepare(在恢复之前都要进行prepare, 原理:redo前滚,undo后滚,模仿CSR(自动故障恢复)过程,)
      innobakupex --apply-log /data/xbk/full_2021-03-31/
      数据恢复:
      cp -a /data/xbk/full_2021-03-31/* /data/3306/
      授权:
      chown -R mysql.mysql /data/*
      启动数据库
      /etc/init.d/mysqld start

7.4 xbk的增量备份
7.4.1 说明:
备份时:
1. 增量必须依赖全备;
2. 每次增量都要参照上次备份的LSN号码,在此基础上变化的数据页,备份走;并且,会将备份过程中产生新的变化的redo一并备份走。
恢复时:
1. 需要将所有需要的INC备份(增量备份)按顺序合并到全备中,并且需要将每个备份进行prepare
7.4.3 增量备份演练
1. 创建环境
create database xbk charset unf8mb4;
use xbk;
create table t1(id int);
insert into t1 values(1),(2),(3);
commit;
2. 模拟周日全备
innobackupex --user=root -password=123 --no-timestamp /data/backup/full
3. 模拟周一的数据变化
use xbk;
create table t2(id int);
insert into t2 values(1),(2),(3);
commit;
4. 模拟周一晚上增量备份inc1
innobackupex --user=root --password=123 --no-timestamp --incremental --incremental-basedir=/data/backup/full /data/back/inc1
参数:
–incremental: 增量备份开关;
–incremental-basedir: 增量备份基目录,上次备份的路径;
5. 模拟周二的数据变化
use xbk;
create table t3(id, int);
insert into t3 values(1),(2),(3);
commit;
6. 模拟周二晚上增量备份inc2
innobackupex --user=root --password=123 --no-timestamp --incremental --incremental-basedir=/data/backup/inc1 /data/back/inc2
7. 模拟周三数据变化
use xbk;
create table t4(id, int);
insert into t4 values(1),(2),(3);
commit;
8. 周三10点搞破坏
pkill mysqld
rm -rf /data/3306/*
9. 确认备份完整性
检查checkpoint,增量备份的from_lsn= 基文件的last_lsn- 9(内置原因);则说明是完整的。
10. xbk full+ inc+ binlog备份恢复
a. 恢复思路
1.合并整理(prepare)所有inc备份到全备,
2.恢复数据,启动数据库,
3.截取而二进制日志,
4.恢复日志;
b. 恢复过程
1. 合并,prepare所有inc备份到全备
innobackupex --apply-log --redo-only /data/backup/full #基础全备的整理,
2. 合并,prepare inc2到full
innobackupex --apply-log --redo-only --incremental-dir=/data/backup/inc1 /data/backup/full
3. 合并,prepare inc2到full,检查checkpoint是否对的上
innobackupex --apply-log --incremental-dir=/data/backup/inc2 /data/backup/full
4. 整体再整理一次(prepare)
innobackupex --apply-log /data/backup/full
5. 恢复1:修改mysql 数据路径 -修复数据至周二晚上
chown -R mysql.mysql /data/backup/full #
更改配置文件my.cnf中data路径 datadir=/data/backup/full
重启数据库
6. 截取日志恢复
起点:/data/backup/inc2/xtrabackup_binlog_info
终点:文件末尾
mysqlbinlog --skip-gtids --start-position=1629 /data/binlog/mysql-bin.000020 /data/binlog/mysql-bin.000021> tmp/bin.sql
7. 恢复截取文件
mysql -uroot -p
set sql_log_bin=0;
source tmp/bin.sql;
set sql_log_bin=1;
7.4.4 小彩蛋***
思考问题:总数据量30T,共10个业务,10个库500张表,周三上午10点,误DROP掉了taobao.t1核心业务表20G,导致taobao库业务无法正常运行;
备份策略:周日full,周一到周五inc,binlog完整。
怎么快速恢复,还不影响其他业务?方法:迁移表空间
提示:
alter table taobao.t1 discard tablespace;
alter table tabobao.t1 import tablespace;

第九章 主从复制(Replication) ==================================================================================================================================================================

  1. 介绍
    两台或以上数据库实例,通过二进制日志,实现数据的"同步"关系;

  2. 主从复制前提(或者是搭建过程)
    #时间同步
    #至少两台以上实例,有角色划分
    #主库开binlog
    #网络通畅
    #serverid不同
    #要开启专用的复制线程
    #开启专门复制用户
    #“补课”,若从库落后主库数据,则需从库补上所缺数据
    #确认复制起点
    总结:
    a. 需要两台以上实例,时间同步,网络通畅,且serverid要不同,为了区分不同的角色(主从);
    b. 主库要开启binlog,且建立一个专用复制用户;
    c. 从库需要提前"补课",补偿落下的数据;
    d. 从库:主库的连接信息,且确认复制的起点;
    e. 从库需要开启专用的复制线程。

  3. 实现主从复制搭建
    3.1 实例准备
    systemctl start mysqld3307
    systemctl start mysqld3308
    systemctl start mysqld3309
    netstat -tuinp
    3.2 检查关键信息
    检查serverid
    mysql -S /tmp/mysql3307.sock -e “select @@serverid”
    mysql -S /tmp/mysql3308.sock -e “select @@serverid”
    mysql -S /tmp/mysql3309.sock -e “select @@serverid”
    3.3 检查主库binlog
    mysql -S /tmp/mysql3307.sock -e “select @@log_bin”;
    3.4 主库建立复制用户
    mysql -S /tmp/mysql3307.sock -e “grant replication slave on . to repl@'10.0.0.%” identified by ‘123’
    mysql -S /tmp/mysql3307.sock -e “select user,host from mysql.user” --确认用户是否存在
    3.5 主库备份恢复到从库
    mysqldump -S /tmp/mysql3307.sock --A --master-data=2 --single-transaction> /tmp/all.sql
    mysql -S /tmp/mysql3308.sock< /tmp/all.sql
    mysql -S /tmp/mysql3309.sock< /tmp/all.sql
    3.6 告知从库复制信息

    help change master to --查看chang master to 参数

    CHANGE MASTER TO
    MASTER_HOST=“10.0.0.51”,
    MASTER_USER=‘repl’,
    MASTER_PASSWORD=“123”,
    MASTER_PORT=3307,
    MASTER_LOG_FILE=“mysql-bin.000002”,
    MASTER_LOG_POS=444,
    MASTER_CONNECT_RETRY=10;
    grep “-- CHANGE MASTER TO” /tmp/all.sql --获取MASTER_LOG_FILE位置点信息
    mysql -S /tmp/mysql3308.sock --告知3308
    CHANGE MASTER TO
    MASTER_HOST=“10.0.0.51”,
    MASTER_USER=‘repl’,
    MASTER_PASSWORD=“123”,
    MASTER_PORT=3307,
    MASTER_LOG_FILE=“mysql-bin.000002”,
    MASTER_LOG_POS=444,
    MASTER_CONNECT_RETRY=10;
    mysql -S /tmp/mysql3309.sock --告知3309
    CHANGE MASTER TO
    MASTER_HOST=“10.0.0.51”,
    MASTER_USER=‘repl’,
    MASTER_PASSWORD=“123”,
    MASTER_PORT=3307,
    MASTER_LOG_FILE=“mysql-bin.000002”,
    MASTER_LOG_POS=444,
    MASTER_CONNECT_RETRY=10;
    3.7 开启专用服务线程
    mysql -S /tmp/mysql3308.sock
    start slave;
    mysql -S /tmp/mysql3309.sock
    start slave;
    3.8 验证主从状态
    mysql -S /tmp/mysql3308.sock -e “show slave status\G”| grep Runing:
    mysql -S /tmp/mysql3309.sock -e “show slave status\G”| grep Runing:
    3.9 如果搭建不成,可以执行一下命令,重新来做
    mysql -S /etc/mysql3308.sock -e “stop slave;reset slave all;”
    mysql -S /etc/mysql3309.sock -e “stop slave;reset slave all;”

  4. 主从复制原理
    检查是否可以同步
    mysql -S /tmp/mysql3307.sock mysql -S /tmp/mysql3308.sock
    create database test charset utf8mb4; show databases;
    4.1 主从复制中涉及到的资源
    4.1.1 文件
    主库: binlog;
    从库: relay-log: 从库存储接受的binlog,默认再从库的数据目录下,手工定义方法:
    show variables like “%relay%”;
    relay_log_basename= /data/3308/data/db01-relay-bin;
    master.info: 连接主库的信息,以及已经接受到的binlog位置点信息,默认存储再从库的数据路径下;修改master_info_repository=FILE/TABLE可以修改master.info的存储方式,文件或表;
    relay-log.info: 记录从库回访到的relay-log的位置点,默认位置在从库数据路径下relay-log.info,跟master.info一样可以自定义位置,以及修改文件存储方式。
    4.1.2 线程资源
    主库线程:
    Binlog_dump_Thread:
    作用:用来接受从库请求,并且投递binlog给从库;
    show processlist; --可以看到这个线程
    从库线程:
    IO线程:请求并接受日志;
    SQL线程:回放relay-log;
    mysql -S /tmp/mysql3309.sock -e “show slave status\G”| grep Runing: --可以看到这两个线程
    4.2 主从复制原理
    1.Slave: CHANGE MASTER TO: IP,PORT,USER,PSAAWORD,Binlog point写入到M.info文件中,start_slave(启动SQL和IO);
    2.Slave: 连接主库,
    3.Master: 分配Dump_Thread,专门和Slave的IO线程进行通信,一个从库产生一个,一直存在;
    4.Slave: IO_Thread请求新的binlog;
    5.Master: Dump_thread 截取日志,返回给从库,从库IO_Thread接受请求;
    6.Slave: IO_Thread接受binlog放在TCP/IP缓存中,此时网络层返回ACK给主库;主库工作完成;
    7.Slave: IO_Thread将binlog写入relay-log中并更新M.info;IO_Tread线程工作完成;
    8.SQL: SQL线程将读R.info,获取上次执行到的位置点;
    9.Slave: SQL线程向后执行新的relay-log,再次更新R.info;
    10.Slave: Relay-log 参数: relay_log_purge=ON,定期删除应用过的relay-log;
    11.Master: Dump线程实时监控主库中的binlog变化,如果有新变化,发信号给从库。

  5. 主从监控
    5.1 主库
    show process list;
    show slave hosts;
    5.2 从库
    show slave status\G
    主库相关信息:来自于M.info:
    Master_Host:10.0.51
    Master_Port:3307
    Connect_Retry:10
    Master_Log_File:mysql-bin.000002
    Read_Master_Log_Pos:619

     从库relay-log的执行情况:来自于relay.info,一般用作判断主从延时:
     Relay_Log_File:db01-relay-bin.000002
     Relay_Log_Pos:495
     Relay_Master_Log_File:mysql.bin.000002
     Exec_Master_Log_Pos:619(已经执行到的主库额位置点信息)
     Seconds_Behinds_Master:0
    
     从库线程状态及具体报错信息:
     Slave_IO_Running:Yes
     Slave_SQL_Running:Yes
     Last_IO_Errno:0
     Last_IO_Error:
     Last_SQL_Errno:0
     Last_SQL_Error:
    
     过滤复制相关信息:
     Replication_Do_DB:
     Replication_Ignore_DB:
     Replication_Do_Table:
     Replication_Ignore_Tbale:
     Replication_Wild_Do_Table:
     Replication_Wild_Ignore_Table:
    
     延时从库的配置信息:
     SQL_Delay:0
     SQL_Remaining_Delay:NULL
    
     GTIDS相关复制信息:
     Retrieved_Gtid_Set:
     Executed_Gtid_Set:
    
  6. 主从故障分析及处理
    6.1 监控方法
    show slave status\G
    Slave_IO_Running:Yes
    Slave_SQL_Running:Yes
    Last_IO_Errno:
    Last_IO_Error:
    Last_SQL_Errno:0
    Last_SQL_Error:
    6.2 IO线程故障
    6.2.1 正常状态
    Slave_IO_Running:Yes
    6.2.1 非正常状态
    Slave_IO_Running:No/ Connecting
    6.2.2 故障原因
    连接主库: 网络,端口,防火墙;
    用户,密码,授权问题:replication slave;
    主库连接数上限:默认连接数上线可以通过select @@max_connections;
    ±------------------+
    | @@max_connections |
    ±------------------+
    | 151 |
    ±------------------+
    数据库版本之间的差距:5.7 使用native,8.0使用sha2.
    故障模拟:
    主从中的线程管理:
    mysql>start slave; -启动所有线程
    mysql>stop slave; -关闭所有线程
    mysql>start slave sql_thread; -单独启动SQL线程
    mysql>start slave io_thread; -单独启动IO线程
    mysql>stop slave sql_thread; -单独关闭SQL线程
    mysql>reset slave all -解除从库身份
    模拟网络、端口、防火墙错误:
    Last_IO_Errno:1045
    Last_IO_Error:error connecting to master ‘repl@10.0.0.51:3307’-retry-time:10 retries:1
    通用故障处理思路:
    1.手工通过复制用户连接主库
    mysql -urepl -p123456 -h10.0.0.51 -P3307
    请求/接受日志:
    主库二进制日志不完整:损坏、不连续…
    从库请求起点问题…
    主从之间serverid(server_uuid)相同…
    relaylog的问题…
    故障模拟:
    6.3 SQL线程故障
    6.3.1 SQL线程主要工作
    回放relay-log日志,后台回放,执行relay-log中的SQL。
    6.3.2 原因

    创建的对象已经存在;

    需要操作的对象不存在;

    操作冲突-约束冲突

    SQL_MODE,及参数,版本

    大机率原因出现在从库写入或者双结构中容易出现

6.3.2 故障模拟
1. 先在从库 create database test1;
2. 再在主库 create database test1;
3. 检查从库SQL线程状态 Slave_SQL_Running:No
4. 处理故障方法一,以主库为准:
将从库进行反操作,重启线程:
myxql>drop database test1;
mysql>start slave;
5. 处理故障方法二,以从库为主
跳过此次错误:
方法1. stop slave;
set global sql_slave_skip_counter= 1; --跳过错误,如果要用这种办法,一定保证此时主从数据是一致的;
方法2. /etc/my.cnf --遇到自动跳
slave-skip-errors= 1032,1062,1007;
常见报错代码:1007-对象已存在;1032-无法执行SQL;1062-主键冲突,或约束冲突;
6.4 从库怎么当主库?
1. 修复到最新状况
2. 取消从库身份 mysql>reset slave all;
3. 清空所有binlog日志信息
6.5 预防从库写入
1. 从库只读
mysql>select @@read_only #普通用户制度
mysql>select @@super_read_only #普通管理员只读
2. 读写分离中间件
用户请求操作,会通过中间件,写操作分流到主库,读操作分流到从库。

  1. 主从延时问题的原因分析及处理
    7.1 什么是主从延时
    主库发生可操作,从库很久才跟上来
    7.2 主从延时怎么监控
    1. mysql>shou slave status; --粗略的评估
      Seconds_Behind_Master:0 #从库落后于主库的时间,可以得出有或者没有延时的情况;定性的;等于0不代表没有延时。
    2. 评估主从延时更精确的指标是,延时了多少日志量 --日志量的评估
      即:主库执行的日志量与从库执行的日志量的对比; 日志量(主从位置点) 对比 从relay执行的位置点
      对比从库中relay-log.info中的位置点与 主库中show master status中的位置点,就可以知道具体延时日志量;
      7.3 主从复制延时原因
    3. 主库
      a. 外部原因:网络,硬件配置,主库业务繁忙(可以拆分业务-垂直或水平拆分;大事务的拆分),从库太多(一般带三到四个从库,但是可以建立多级从库-适合读多写少);
      b. 内部因素:i)二进制日志更新(不及时,影响参数sync_binlog,解决方案sync_binlog= 1(双一));
      ii)5.7版本之前没有开GTID的,Dump线程串行传输binlog,但是主库可以并行很多事务,导致有很多事务等待传输(出现GTID后,事务实现全局唯一性,可以并发传输binlog,但仍然会受大事务的影响,以及锁的征用问题);
      c. 怎么判断时主库传输不及时?
      1. mysql>seconds_behind_master; --主库
      2. mysql>show master status; --主库 #cat master.info or mysql>show slave status; --从库
    4. 从库
      a. 外部原因:网络,从库配置过低(主要是靠内存和IO),参数谁当出现差异;
      b. 内部因素:i)IO线程:写relay-log–>取决于IO性能,
      ii)SQL线程:单线程回放主库SQL;非GTID模式下串行回放(解决方案:需要保证执行顺序,取决于GTID,必须要打开GTID,并行回放SQL;5.6+ GTID:dataabse级别,基于库级别SQL线程并发;5.7+ GTID:logical_clock逻辑时钟,保证了在同库级别下的事务顺序,支持基于事务级别并发回放,MTS);
    5. 即使有自带的优化机制,还要注意对于大事务的处理问题,需要减少大事务的大小,同时需注意锁的问题。

第十章 主从复制的高级进阶======================================================================================================================================================================

  1. 特殊从库的应用
    1.1 延时从库
    作用:普通的主从复制,只能帮我们解决物理故障,如果主库出现了drop database操纵,延时从库延长一定时间回放(SQL),可以处理逻辑损坏;
    1.1.2 配置:在从库中配置
    mysql>stop slave;
    mysql>CHANGE MASTER TO MASTER_DELAY= 300;
    mysql>start slave;
    mysql>show salve status\G
    SQL_DELAY: 300
    SQL_Remaining_Delay:NULL
    1.1.3 故障模拟及恢复
    a. 模拟数据
    create database ys charset utf8mb4;
    use ys;
    create table t1(id int);
    begin;
    isnert into t1 values(1),(2),(3);
    commit;
    drop database ys;
    b. 恢复思路
    1.先停业务,挂维护页;
    2.停从库SQL线程;mysql>stop slave sql_thread; 查看relay-log.info的位置点信息;
    mysql>stop slave;
    3.追加后续缺失半部分的日志到从库:
    日志位置:relay-log.info
    追加范围:relay.info ±–>DROP ±–>之后的
    4. 直接迁移业务到从库;
    c. 恢复过程
    1. 停SQL线程,关从库
    mysql>show slave status; --Slave
    mysql>show master status; --Master
    mysql>stop slave sql_thread; --Slave
    mysql>stop slave; --Slave 可以稍等一会儿,等待还在传输的;
    2. 截取relay-log
    起点: Relay_Log_File:db01-relay-log.000002
    Relay_Log_Pos:482
    或者:cat /data/3308/data/relay-log.info 也可以找到起始点;
    终点: mysql>show relaylog events in ‘db01-relay-log-bin.000002’; --找到drop前的位置点,只观察Pos列,End_log_pos对应主库中binlog中的位置点
    mysqlbinlog --start-position 482 --stop-position 1402 /data/3308/data/db01-relay-bin.000002 >tmp/relay.sql;
    3. 从库的恢复
    mysql>set sql_log_bin=0;
    mysql>source tmp/relay.sql;
    mysql>set sql_log_bin=1;
    1.2 过滤复制
    1.2.1 配置方法
    主库配置: 在配置文件中修改,用的少
    mysql>show master status;
    binlog_do_db - 白名单
    binlog_ignore_db - 黑名单
    从库配置:在从库中配置,常用(binlog日志会传输,但是SQL线程只执行过滤后的relaylog)
    mysql>show slave status;
    replication_do_db= --库级别白名单
    replication_ignore_db= --黑名单
    replication_do_table = --表级别
    replication_ignore_table=
    replication_wild_do_table= world.t* --模糊表级别
    replication_wild_ignore_table=
    将 replication_do_db= test1
    replication_do_db= test2 写入从库配置文件 --vim /data/3309/my.cnf
    重启数据库 systemctl restart mysql3309
    1.3 半同步复制:已经成为历史
    Classical replication:传统异步非GTID复制工作模式下,会导致从库数据不一致的情况;
    5.5版本为了保证主从数据的一致性问题,加入了半同步复制的组件(插件),让从库relaylog落盘后再通过插件传送应用层面的ACK给主库的插件,接收到后主库的事务才能够commit成功,默认超时10s没有返回ACK,则自动切换为传统异步复制;5.6和5.7中也加入了一些比较好的特性,但仍然无法保证主从数据完全一致;如果业务中比较关注主从数据一致,推荐使用MGR架构,或者PXC等一致性架构;
    1.4 GTID复制
    作用:主要是为了保证主从复制中的高级的特性;
    介绍:5.6默认不开启,5.6即使不开启也会产生匿名的GTID记录;可以使DUMP并行传输,且提供SQL线程并发回放;5.7.17之后基本就是GTID模式了;
    搭建GTID复制:
    1.主备3台虚拟机
    IP:51/52/53
    hostname:db01/dn02/db03
    防火墙关闭,实现远程xshell连接

    1. 清理环境(3个节点都做)
      pkill mysqld
      rm -rf /data/3306/*
      rm -rf /data/binlog/*
    2. 生成配置文件(3个节点都做,注意server_id)
      #db01
      cat>/etc/my.cnf<<EOF
      [mysqld]
      basedir=/app/database/mysql
      datadir=/data/3306
      socket=/tmp/mysql.sock
      server_id=51
      port=3306
      secure-file-priv=/tmp
      autocommit=0
      log_bin=/data/binlog/mysql-bin
      gtid-mod=on
      enforce-gtid-consistency=true
      log-slave-updates=1
      [mysql]
      prompt=db01 [\d]> #显示登录mysql后>前面的字符,默认为mysql
      EOF
    3. 初始化数据(3个节点多做)
      mysqld --initialize-insecure --user=mysql --basedir=app/database/mysql --datadir=/data/3306
    4. 分别启动数据库
      /etc/init.d/mysqld start
    5. 构建主从,主库创建用户(db01)
      mysql>grant replication slave on . to repl@‘10.0.0.%’ identified by ‘123’;
    6. 从库开启主从
      52/53:
      mysql> change master to
      master_host=‘10.0.0.51’,
      master_user=‘repl’,
      master_password=‘123’,
      MASTER_AUTO_POSITION=1;
      start slave;
      show slave status;
      show master status;
      若主库有数据则需要先将数据备份到从库;
    7. 说明:GTID的主从复制,第一次开启的时候,读取relaylog的最后GTID+读取GTID_PURGE参数,确认参数起点
      优点:
    8. 保证事务全局统一;
    9. 截取日志更加方便,跨多文件,判断起点和终点更加方便;
    10. 判断主从工作状态更方便;
    11. 传输日志,可以并发传输,SQL回放可以高并发;
    12. 主从复制更加方便 master_auto_position=1
  2. 主从架构演变
    2.1 原生态支持:
    一主一从、一主多从、多级主从、双主结构、延时从库、过滤复制、MGR组复制(5.7.17+);
    2.2 非原生态:
    2.2.1 安全:高可用
    全年无故障率:
    99% 一般级别
    99.9% 普通级别
    99.99% 准高可用级别 MHA架构
    99.999% 金融级别 Cluster\InnoDB Cluster\MGC\Oracle RAC\sysabse cluster架构
    99.9999% 超金融级别
    2.2.2 性能
    读多写少:读写分离 代表产品:Altas,ProxySQL,Mycat…
    什么都多的:分布式方案 代表产品:Altas-sharing,Mycat(DBLE)…

第十一章 高可用及读写分离=======================================================================================================================================================================

  1. MHA高可用架构介绍
    1.1 主从架构要求

    1. 3个以上的节点,1主2从,不能是多实例;
    2. 多节点SSH互信(为简化SSH过程,采用证书方式,免去SSH登入时需要输入账号密码的过程)
      1.2 软件结构
      Master: 管理软件
      masterha_manager 启动MHA
      masterha_check_ssh 检查MHA的SSH配置情况
      masterha_check_repl 检查MySQL复制情况
      masterha_master_monitor 检查master是否宕机
      masterha_check_status 检查当前MHA运行状态
      masterha_master_swithch 控制故障转移(自动或者手动)
      masterha_conf_host 添加或者删除配置的server信息

    Node: 被管理的软件
    save_binary_logs 保存和复制master的二进制日志
    apply_diff_relay_logs 识别差异的中继日志事件并将其差异的事件应用于其他的
    purge_relay_logs 清楚中继日志(不会阻塞SQL线程)

  2. MHA基础架构规划和实施
    2.1 规划
    主库: 51 db01 node
    从库: 52 db02 node
    53 db03 node manager
    2.2 准备环境(1主2从GTID复制)
    2.3 配置关键程序软连接(所有节点)
    ln -s /app/database/mysql/bin/mysqlbinlog /user/bin/mysqlbinlog
    ln -s /app/database/mysql/bin/mysql /user/bin/mysql
    2.4 配置各节点互信(密钥对)
    db01:
    rm -rf /root/.ssh
    ssh-keygen
    sc /root/.ssh
    mv id_rsa.pub authorized_keys
    scp -r /root/.ssh 10.0.0.52:/root
    scp -r /root/.ssh 10.0.0.53:/root
    各节点验证
    db01:
    ssh 10.0.0.51 data
    ssh 10.0.0.52 data
    ssh 10.0.0.53 data
    db02:
    ssh 10.0.0.51 data
    ssh 10.0.0.52 data
    ssh 10.0.0.53 data
    db03:
    ssh 10.0.0.51 data
    ssh 10.0.0.52 data
    ssh 10.0.0.53 data
    2.5 安装软件
    下载MHA软件:
    MHA官网:
    github下载地址:https://github.com/yoshinorim/mha4mysql-manager/wiki/Downloads
    说明:
    1. 8.0版本无法使用这个版本的,需要更改密码加密模式(sha2----->native)
    2. 需要使用0.58+版本MHA软件;
    所有节点安装Node软件依赖包
    yum install perl-DBD-MySQL -y perl-Config-Tiny epel-release perl-Log-Dispatch perl-Parallel-ForkManager perl-Time-HiRes rpm -ivh mha4mysql-node-0.56-0.e16.noarch.rpm
    在db01主库中创建MHA需要的用户
    grant all peiviledges on . to mha@‘10.0.0.%’ identified by ‘mha’;
    2.6 Manage软件安装(db03)

    1. 创建配置文件目录
      mkdir -p /etc/mha
    2. 创建日志目录
      mkdir -p /var/log/mha/app1
    3. 编辑mha配置文件
      cat>/etc/mha/app1.cnf <<EOF
      [server default]
      manager_log=/var/log/mha/app1/manager
      manager_workdir=/var/log/mha/app1
      master_binlog_dir=/data/binlog
      user=mha
      password=mha
      ping_interval=2
      repl_password=repl
      ssh_user=root #互信用户名
      [server1] #节点
      hostname=10.0.0.51
      port=3306
      [server2]
      hostname=10.0.0.52
      port=3306
      [server3]
      hostname=10.0.0.53
      port=3306
      EOF
      2.7 检查状态(db03)
      masterha_check_ssh --conf=/etc/mha/aap1.cnf #检查互信
      masterha_check_repl --conf=/etc/mha/app1.cnf #检查主从情况
      2.8 开启MHA-manager
      nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover< /dev/null> /var/log/mha/app1/manager.log 2>&1 &
      2.9 查看MHA状态
      masterha_check_status --conf=/etc/mha/app1.cnf
  3. 高可用:
    最擅长的是为我们解决物理损坏
    首先:启动MHA;

    1. 监控:数据可节点,主要监控主库
      通过:masterha_master_monitor心跳检测脚本,监控主库,同时检测ssh连通性;默认探测四次,每隔ping_interval=2秒,如果主库还没有心跳,则认为主库宕机,进入failover故障转移过程;
    2. 选主策略:
      a.事先设置优先级(管理员主观行为):
      如果节点配置时,加入了candidate_master=1参数,则会被优先判定为主库;如果备选主日志量落后主库master太多(100M)也不会被选为新主;此时可以添加参数check_repl_delay=0不检查日志落后主库的情况;
      如,在app1.cnf中[server1]下添加 candidate_master=1;
      b.日志量最接近主库;
      c.日志量一样的话,按照配置文件顺序选择新的主库;
    3. 日志补偿:追上缺的数据
      情况1:ssh能连上,通过asve_binary_logs立即保存缺失部分的日志到从库(var/tmp目录下)并修复;
      情况2:ssh不能连上,尽可能止损,两个从库通过(apply_diff_relay_logs)进行relaylog日志diff差异计算并进行;
    4. 主从身份的切换:
      a.所有从库取消和原有主库的复制关系
      mysql>stop slave;
      mysql>reset slave all;
      b. 新主库和剩余从库重新构架主从关系
    5. 故障库自动剔除;
      通过masterha_conf_host脚本去掉配置文件中故障库信息;
    6. MHA是一次性的高可用,Failover后,Manager自动退出,需要重新启动MHA;
    7. 不足的地方:
      a.数据补偿;
      b.自动提醒;
      c.自愈功能:待开发;MHA+K9s+Operator, 8.0 MGR+mysqlsh
      d.应用透明;vip漂移
  4. 应用透明(vip)功能实现
    4.1 说明:
    只能在同机房使用,无法跨机房跨网络;
    4.2 配置参数(db03)
    vim /etc/mha/app1.cnf
    master_ip_failover_script=/user/local/bin/master_ip_failover #加在配置文件下server_default下
    4.3 修改脚本内容(db03)
    cp master_ip_failover.txt /user/local/bin/master_ip_failover #master_ip_failover.txt可以在网上下载
    vim /user/local/bin/master_ip_failover
    my $vip=‘10.0.0.55/24’; #vip地址
    my $key=‘1’ #
    my s s h s t a r t v i p = " / s b i n / i f c o n f i g e n s 33 : ssh_start_vip="/sbin/ifconfig ens33: sshstartvip="/sbin/ifconfigens33:key $vip";
    my s s h s t o p v i p = " / s b i n / i f c o n f i g e n s 33 : ssh_stop_vip="/sbin/ifconfig ens33: sshstopvip="/sbin/ifconfigens33:key down";
    技巧将中文字符转换为unix dosunix /user/local/bin/master_ip_failover
    添加执行权限 chmod +x /user/local/bin/master_ip_failover
    4.4 在主库(db01)上手工绑定第一个vip地址
    ifconfug ens33:1 10/0.0.24
    4.5 重启MHA(db03)
    masterha_stop --conf=/etc/mha/app1.cnf
    nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover < /dev/null> var/log/mha/app1/mamager.log 2>&1 &
    4.6 查看MHA状态
    masterha_check_status --conf=/etc/mha/app1.cnf

  5. binlog server(db03)
    5.1 参数
    vim /etc/mha/app1.cnf
    [binlog1]
    no_master=1 #选主时不考虑该节点,不参与选主
    hostname=10.0.0.53
    master_binlog_dir=/data/mysql/binlog #注意和节点中master_binlog_dir位置不要一样,会覆盖掉
    5.2 创建必要路径
    mkdir -p /data/mysql/binlgo #创建路径
    chown -R mysql.mysql /data/* #授权
    5.3 拉取主库binlog日志
    cd /data/mysql/binlog #必须进入到自己创建好的目录
    mysqlbinlgo -R --host=10.0.0.51 --user=mha --password=mha --raw --stop-never mysql-bin.000001 & #一定要先cd到目录下,只要主库不宕机,就会一直运行
    #注意:拉取日志的起点,需要按照目前从库的已经获取到的二进制日志为起点
    5.4 重启MHA
    masterha_stop --conf=/etc/mha/app1.cnf
    nohub masterha_manager --conf=/etc/mhaapp1.cnf --remove_dead_master_conf --ignore_last_failover< /dev/null> /var/log/mha/app1/manager.log 2>&1 &

  6. 邮件提醒
    6.1 参数
    report _script=/user/local/bin/send
    6.2 准备邮件脚本
    send_report

    1. 准备发邮件的脚本到/user/local/bin中;
      cd mail
      cp -a /user/local/bin
      chomd +x /user/local/bin/
    2. 将准备好的脚本添加到mha配置文件中,让其调用;
      6.3 修改MHA配置文件,调用邮件脚本
      vim /etc/mha/app1.cnf
      report_script=/user/local/bin/send
      6.4 重启MHA
      masterha_stop --conf=/etc/mha/app1.cnf
      nohub masterha_manager --conf=/etc/mhaapp1.cnf --remove_dead_master_conf --ignore_last_failover< /dev/null> /var/log/mha/app1/manager.log 2>&1 &
  7. 测试MHA的功能
    7.1 宕机测试

    1. 测试查看 vip
    2. 查看邮件
    3. 切换日志
    4. 故障库是否剔除
    5. 切换日志
    6. 主从状态
      7.2 主库宕机
      /etc/init.d/mysqld stop
      7.3 查看/var/log/mha/app1/manager文件
      vim /var/log/mha/app1/manager.log
  8. 故障修复思路
    8.1 排查进程状态
    (db03) ps -ef |gerp manager
    masterha_check_status --conf/etc/mha/app1.cnf
    8.2 检查配置文件节点情况
    cat /etc/mha/app1.cnf
    若一个节点不见了,说明切换国过程成功了,还节点已经被移除;如果都还在,说明切换过程在中间卡住;然后查看看日志/var/log/mha/app1/manager
    8.3 修复故障库(修复)
    8.4 修复主从
    将故障库修好后手工加入已有的主从中作为从库;
    CHANGE MASTER TO
    master_host=‘10.0.0.52’,
    master_user=‘repl’,
    master_password=‘213’,
    MASTER_AUTO_POSITION=1;
    start slave;
    show slave status;
    8.5 配置文件修复,恢复成原样
    8.6 检查SSH的互信和repl的主从关系
    masterha_check_ssh --conf=/etc/mha/app1.cnf
    masterha_check_repl --conf=/etc/mha/app1.cnf
    8.7 修复binlog server(注意谁是主库)
    cd /data/mysql/binlog
    rm -rf *
    mysqlbinlog -R --host=10.0.0.52 --user=mha --password=mha --raw --stop-never mysql-bin.000001 & #注意用新主库的二进制文件 show master status\G
    8.8 检查主节点vip状态,看看在不在主节点上
    (db02) ip a
    如果不在,再手工生成
    ifconfug ens33:1 10.0.0.55/24
    8.9 启动MHA
    masterha_check_status --cong=/etc/mha/app1.cnf

  9. MHA高可用应用
    MHA基础架构+binlogserver+VIP+Sendreport
    9.1 MHA高可用架构改造

    1. 历史架构:MHA基础架构
    2. 应用的痛点
      a. 不支持VIP,应用端只能通过主库IP连接集群;如果主库宕机,需要手工修改应用端配置。
      b. 如果主库整体宕机,SSH连接不上,很有可能丢失部分事务,因为没有binlogserver
      c. 没有故障提醒功能,管理员不能及时反应;
    3. 架构改造方案
      a. 添加binlogserver 日志补偿
      b. VIP功能 应用透明
      c. sendreport 及时提醒
    4. 管理员职责
      a. MHA切换之后可以快速反应,修复架构,因为MHA是一次性
      b. MHA优化:尽可能缩短MHA failover事件
      监控:修改参数ping_interval参数可以减少监控时间
      选主:强制选主 candidate_master=1
      check_repl_delay=0
      日志补偿:binlogserver
      日志补偿阶段是最影响Faliover速度,所以从根本上降低日志补偿时间,归根结底就是减少主从延时才是大方向;需考考虑GTID,锁,大事务,SQL并发线程,双一
  10. Atlas读写分离中间件应用
    10.1 下载安装
    下载:https://github.com/Qihoo360/Atlas/releases
    安装:rpm -ivh Atlas-2.2.1.e16.x86_64.rpm #安装在db03下
    10.2 配置
    cd /user/local/mysql-proxy/conf
    mv test.cnf test.cnf.bak
    cat> test.cnf <<EOF
    [mysql-proxy]
    admin-username=user #管理员用户
    admin-password=pwd #管理员密码
    proxy-backend-addresses=10.0.0.55:336 #55,将其放在vip上,可以随着主库漂移而漂移;负责写的IP地址和端口,主节点
    proxy-read-only-backend-addresses=10.0.0.52:3306,10.0.0.53:3306 #从节点,只读
    pwds=repl:3yb5jEku5h4=,mha:O2jBXONX098= #应用端连接后端数据库的用户名和密码
    daemon=true #后台运行,守护式
    keepalive=true #检查各个节点心跳
    event-threads=8
    log-level=message
    log-path=/user/local/mysql-proxy/log
    sql-log=ON
    proxy-address=0.0.0.0:33060 #33060:Atlas对外提供服务的端口
    admin-address=0.0.0.0:2345 #给管理员提供的端口,
    charset=utf8
    EOF
    10.3 启动Atlas
    /user/local/mysql-proxy/bin/mysql-proxy test start
    ps -ef| grep proxy
    10.4 测试读写分离功能
    mysql>mysql -umha -h 10.0.0.53 -P33060
    mysql>select @@server_id #读操作测试,执行多次,可以看到轮巡查询
    mysql>begin; select @@server_id; commit; #写操作测试,可以看到写操作在51上执行
    10.5 Atlas的管理db03
    mysql>mysql -uuser -ppwd -h 10.0.0.53 -P2345 #登陆管理员账户
    mysql>select * from help; #查看所有Atlas管理命令
    10.6 管理命令
    select * from help; #帮助命令
    select * from backends; #列出后端节点情况及状态
    set offline 3 #下线,3号节点(backend_ndx)临时设置为offline
    set online 3 #上线
    add master $backend
    add slave 10.0.0.53:3306 #
    remove backend 3 #从Atlas上删除3号节点,临时的,不会对配置文件产生作用
    select * from pwds #查看用户
    add pwd $pwd
    add enpwd $pwd
    remove pwd $pwd
    10.7 企业用户管理

    1. 第一步数据库主节点添加用户
      mysql>grant all on . to user1@‘10.0.0.%’ identified by ‘123’;
    2. 第二步在atlas中添加用户:
      add pwd user1:123; #明文加密
      mysql>add enpwd user1:O2jBXONX098= #密文加密
    3. 保存到配置文件,永久生效:
      mysql>save config;

第十三章 MySQL分布式架构========================================================================================================================================================================

  1. 基础环境准备
    1.1 环境准备:
    两台虚拟机 db01 db02
    没太创建4个mysql实例:3307,3308,3309,3310
    1.2 两台虚拟机删除历史环境
    pkill mysqld
    rm rf /data/33{07…10}
    mv /etc/my.cnf /etc/my.cnf.bak
    1.3 两台虚拟机分别创建相关目录初始化数据
    mkdir /data/33{07…10}/data -p
    mysqld --initialize-insecure --user=mysql --datadir=/data/3307/data --basedir=/app/database/mysql
    mysqld --initialize-insecure --user=mysql --datadir=/data/3308/data --basedir=/app/database/mysql
    mysqld --initialize-insecure --user=mysql --datadir=/data/3309/data --basedir=/app/database/mysql
    mysqld --initialize-insecure --user=mysql --datadir=/data/3310/data --basedir=/app/database/mysql
    1.4 准备配置文件
    db01=========================================================================================
    [mysqld]
    basedir=/app/database/mysql
    datadir=/data/3307/data
    socket=/data/3307/mysql.sock
    port=3307
    log-error=/data/3307/mysql.log
    log_bin=/data/3307/mysql-bin
    binlog_format=row
    skip-name-resolve
    server-id=7
    gtid-mode=on
    enforce-gtid-consistency=true
    log-slave-updates=1
    EOF

    cat >data/3308/my.cnf<<EOF
    [mysqld]
    basedir=/app/database/mysql
    datadir=/data/3308/data
    socket=/data/3308/mysql.sock
    port=3308
    log-error=/data/3308/mysql.log
    log_bin=/data/3308/mysql-bin
    binlog_format=row
    skip-name-resolve
    server-id=8
    gtid-mode=on
    enforce-gtid-consistency=true
    log-slave-updates=1
    EOF

    cat >data/3309/my.cnf<<EOF
    [mysqld]
    basedir=/app/database/mysql
    datadir=/data/3309/data
    socket=/data/3309/mysql.sock
    port=3308
    log-error=/data/3309/mysql.log
    log_bin=/data/3309/mysql-bin
    binlog_format=row
    skip-name-resolve
    server-id=9
    gtid-mode=on
    enforce-gtid-consistency=true
    log-slave-updates=1
    EOF

    cat >data/3310/my.cnf<<EOF
    [mysqld]
    basedir=/app/database/mysql
    datadir=/data/3310/data
    socket=/data/3310/mysql.sock
    port=3310
    log-error=/data/3310/mysql.log
    log_bin=/data/3310/mysql-bin
    binlog_format=row
    skip-name-resolve
    server-id=10
    gtid-mode=on
    enforce-gtid-consistency=true
    log-slave-updates=1
    EOF

    cat >/etc/systemd/system/mysqld3307.server<<EOF
    [Unit]
    Description=MySQL Server
    Documentation=man:mysqld(8)
    Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
    After=network.target
    After=syslog.target
    [Install]
    WantedBy=multi-user.target
    [Service]
    User=mysql
    Group=mysql
    ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3307/my.cnf
    LimitNOFILE=5000
    EOF

    cat >/etc/systemd/system/mysqld3308.server<<EOF
    [Unit]
    Description=MySQL Server
    Documentation=man:mysqld(8)
    Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
    After=network.target
    After=syslog.target
    [Install]
    WantedBy=multi-user.target
    [Service]
    User=mysql
    Group=mysql
    ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3308/my.cnf
    LimitNOFILE=5000
    EOF

    cat >/etc/systemd/system/mysqld3309.server<<EOF
    [Unit]
    Description=MySQL Server
    Documentation=man:mysqld(8)
    Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
    After=network.target
    After=syslog.target
    [Install]
    WantedBy=multi-user.target
    [Service]
    User=mysql
    Group=mysql
    ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3309/my.cnf
    LimitNOFILE=5000
    EOF

    cat >/etc/systemd/system/mysqld3310.server<<EOF
    [Unit]
    Description=MySQL Server
    Documentation=man:mysqld(8)
    Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
    After=network.target
    After=syslog.target
    [Install]
    WantedBy=multi-user.target
    [Service]
    User=mysql
    Group=mysql
    ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3310/my.cnf
    LimitNOFILE=5000
    EOF

    db02============================================================================
    cat >data/3307/my.cnf<<EOF
    [mysqld]
    basedir=/app/database/mysql
    datadir=/data/3307/data
    cocket=/data/3307/mysql.scok
    port=3307
    log-eoor=/data/3307/mysql.log
    log_bin=/data/3307/mysql-bin
    binlog_format=row
    skip-name-resolve
    server-id=17
    gtid-mode=on
    enforce-gtid-consistency=true
    log-slave-updates=1
    EOF

    cat >data/3308/my.cnf<<EOF
    [mysqld]
    basedir=/app/database/mysql
    datadir=/data/3308/data
    cocket=/data/3308/mysql.scok
    port=3307
    log-eoor=/data/3308/mysql.log
    log_bin=/data/3308/mysql-bin
    binlog_format=row
    skip-name-resolve
    server-id=18
    gtid-mode=on
    enforce-gtid-consistency=true
    log-slave-updates=1
    EOF

    cat >data/3309/my.cnf<<EOF
    [mysqld]
    basedir=/app/database/mysql
    datadir=/data/3309/data
    cocket=/data/3309/mysql.scok
    port=3307
    log-eoor=/data/3309/mysql.log
    log_bin=/data/3309/mysql-bin
    binlog_format=row
    skip-name-resolve
    server-id=19
    gtid-mode=on
    enforce-gtid-consistency=true
    log-slave-updates=1
    EOF

    cat >data/3310/my.cnf<<EOF
    [mysqld]
    basedir=/app/database/mysql
    datadir=/data/3310/data
    cocket=/data/3310/mysql.scok
    port=3307
    log-eoor=/data/3310/mysql.log
    log_bin=/data/3310/mysql-bin
    binlog_format=row
    skip-name-resolve
    server-id=20
    gtid-mode=on
    enforce-gtid-consistency=true
    log-slave-updates=1
    EOF

    cat >/etc/systemd/system/mysqld3307.server<<EOF
    [Unit]
    Description=MySQL Server
    Documentation=man:mysqld(8)
    Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
    After=network.target
    After=syslog.target
    [Install]
    WantedBy=multi-user.target
    [Service]
    User=mysql
    Group=mysql
    ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3307/my.cnf
    LimitNOFILE=5000
    EOF

    cat >/etc/systemd/system/mysqld3308.server<<EOF
    [Unit]
    Description=MySQL Server
    Documentation=man:mysqld(8)
    Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
    After=network.target
    After=syslog.target
    [Install]
    WantedBy=multi-user.target
    [Service]
    User=mysql
    Group=mysql
    ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3308/my.cnf
    LimitNOFILE=5000
    EOF

    cat >/etc/systemd/system/mysqld3309.server<<EOF
    [Unit]
    Description=MySQL Server
    Documentation=man:mysqld(8)
    Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
    After=network.target
    After=syslog.target
    [Install]
    WantedBy=multi-user.target
    [Service]
    User=mysql
    Group=mysql
    ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3309/my.cnf
    LimitNOFILE=5000
    EOF

    cat >/etc/systemd/system/mysqld3310.server<<EOF
    [Unit]
    Description=MySQL Server
    Documentation=man:mysqld(8)
    Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
    After=network.target
    After=syslog.target
    [Install]
    WantedBy=multi-user.target
    [Service]
    User=mysql
    Group=mysql
    ExecStart=/app/database/mysql/bin/mysqld --defaults-file=/data/3310/my.cnf
    LimitNOFILE=5000
    EOF

1.5 两台虚拟机分别修改权限,启动多实例
chown -R mysql.mysql /data/*
systemctl start mysqld3307
systemctl start mysqld3308
systemctl start mysqld3309
systemctl start mysqld3310

mysqld -S /data/3307/mysql.sock -e "show variables like 'server_id';"
mysqld -S /data/3308/mysql.sock -e "show variables like 'server_id';"
mysqld -S /data/3309/mysql.sock -e "show variables like 'server_id';"
mysqld -S /data/3310/mysql.sock -e "show variables like 'server_id';"
配置完之后,可以使用命令 netstat -tulnp 检查网络连接状态

1.6 节点主从规划
剪头指谁谁是主库
#shard1
10.0.0.51:3307 <--------> 10.0.0.52:3307
10.0.0.51:3309 ---------> 10.0.0.51:3307
10.0.0.52:3309 ---------> 10.0.0.51:3307
#shard1
10.0.0.52:3308 <--------> 10.0.0.51:3308
10.0.0.52:3310 ---------> 10.0.0.51:3308
10.0.0.51:3310 ---------> 10.0.0.51:3308
1.7 开始配置
#shard1
#10.0.0.51:3307 <--------> 10.0.0.52:3307
#db02
mysql -S /data/3307/mysql.sock -e “grant replication slave on . to repl@‘10.0.0.%’ identified by ‘123’;”
mysql -S /data/3307/mysql.sock -e “grant all on . to root@‘10.0.0.%’ identified by ‘123’ with grant option”
#db01
mysql -S /data/3307/mysql.sock -e “change master to MASTER_HOST=‘10.0.0.52’,MASTER_PORT=3307,MASTER_AUTO_POSITION=1,MASTER_USER=‘repl’,MASTER_PASSWORD=‘123’;”
mysql -S /data/3307/mysql.sock -e “start slave;”
mysql -S /data/3307/mysql.sock -e “show slave status\G”
#db02
mysql -S /data/3307/mysql.sock -e “change master to MASTER_HOST=‘10.0.0.51’,MASTER_PORT=3307,MASTER_AUTO_POSITION=1,MASTER_USER=‘repl’,MASTER_PASSWORD=‘123’;”
mysql -S /data/3307/mysql.sock -e “start slave;”
mysql -S /data/3307/mysql.sock -e “show slave status\G”

#10.0.0.51:3309  --------->  10.0.0.51:3307
#db01
mysql -S /data/3309/mysql.sock -e "change master to MASTER_HOST='10.0.0.51',MASTER_PORT=3307,MASTER_AUTO_POSITION=1,MASTER_USER='repl',MASTER_PASSWORD='123';"
mysql -S /data/3309/mysql.sock -e "start slave;"
mysql -S /data/3309/mysql.sock -e "show slave status\G"

#10.0.0.52:3309  --------->  10.0.0.52:3307
#db02
mysql -S /data/3309/mysql.sock -e "change master to MASTER_HOST='10.0.0.52',MASTER_PORT=3307,MASTER_AUTO_POSITION=1,MASTER_USER='repl',MASTER_PASSWORD='123';"
mysql -S /data/3309/mysql.sock -e "start slave;"
mysql -S /data/3309/mysql.sock -e "show slave status\G"

#shard1
#10.0.0.52:3308  <-------->  10.0.0.51:3308
#db01
mysql -S /data/3308/mysql.sock -e "grant replication slave on *.* to repl@'10.0.0.%' identified by '123';"
mysql -S /data/3308/mysql.sock -e "grant all on *.* to root@'10.0.0.%' identified by '123' with grant option"
#db02
mysql -S /data/3308/mysql.sock -e "change master to MASTER_HOST='10.0.0.51',MASTER_PORT=3308,MASTER_AUTO_POSITION=1,MASTER_USER='repl',MASTER_PASSWORD='123';"
mysql -S /data/3308/mysql.sock -e "start slave;"
mysql -S /data/3308/mysql.sock -e "show slave status\G"
#db01
mysql -S /data/3308/mysql.sock -e "change master to MASTER_HOST='10.0.0.52',MASTER_PORT=3308,MASTER_AUTO_POSITION=1,MASTER_USER='repl',MASTER_PASSWORD='123';"
mysql -S /data/3308/mysql.sock -e "start slave;"
mysql -S /data/3308/mysql.sock -e "show slave status\G"

#10.0.0.51:3310  --------->  10.0.0.51:3308
#db01
mysql -S /data/3310/mysql.sock -e "change master to MASTER_HOST='10.0.0.51',MASTER_PORT=3308,MASTER_AUTO_POSITION=1,MASTER_USER='repl',MASTER_PASSWORD='123';"
mysql -S /data/3310/mysql.sock -e "start slave;"
mysql -S /data/3310/mysql.sock -e "show slave status\G"

#10.0.0.52:3310  --------->  10.0.0.52:3308
#db02
mysql -S /data/3310/mysql.sock -e "change master to MASTER_HOST='10.0.0.51',MASTER_PORT=3308,MASTER_AUTO_POSITION=1,MASTER_USER='repl',MASTER_PASSWORD='123';"
mysql -S /data/3310/mysql.sock -e "start slave;"
mysql -S /data/3310/mysql.sock -e "show slave status\G"

1.8 主从状态检测
mysql -S /data/3307/mysql.sock -e “select slave status\G”| grep Running:
mysql -S /data/3308/mysql.sock -e “select slave status\G”| grep Running:
mysql -S /data/3309/mysql.sock -e “select slave status\G”| grep Running:
mysql -S /data/3310/mysql.sock -e “select slave status\G”| grep Running:
1.9 如果中间出现错误,在每个节点执行一下命令,然后从1.7重新开始做
mysql -S /data/3307/mysql.sock -e “stop slave;reset slave all;”
mysql -S /data/3308/mysql.sock -e “stop slave;reset slave all;”
mysql -S /data/3309/mysql.sock -e “stop slave;reset slave all;”
mysql -S /data/3310/mysql.sock -e “stop slave;reset slave all;”

  1. 分布式架构介绍及演变
    数据库垂直拆分—>数据库的水平拆分—>数据库的应用拆分
  2. Mycat应用
  • 1
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值