MySQL 数据库
MySQL 数据库
本章内容
关系型数据库基础
安装MySQL
管理数据库和表
用户和权限管理
函数,存储过程,触发器和事件
MySQL架构
存储引擎
服务器选项,系统和状态变量
优化查询和索引管理
锁和事务管理
日志管理
备份还原
MySQL集群
压力测试
1 数据库原理
1.1 数据的分类
结构化的数据:即有固定格式和有限长度的数据。例如填的表格就是结构化的数据,国籍:中华人
民共和国,民族:汉,性别:男,这都叫结构化数据
非结构化的数据:非结构化的数据越来越多,就是不定长、无固定格式的数据,例如: 网页,图片文
件,有时候非常大,有时候很小;例如语音,视频都是非结构化的数据
半结构化数据:比如:XML或者HTML的格式的数据
1.2 数据库的发展史
数据库与芯片,操作系统并列为计算机技术的三大件,也是企业IT系统必不可少的核心技术
1.2.1 数据库系统发展阶段
萌芽阶段:文件系统
使用磁盘文件来存储数据
初级阶段:第一代数据库
出现了网状模型、层次模型的数据库
中级阶段:第二代数据库
关系型数据库和结构化查询语言
高级阶段:新一代数据库
"关系-对象"型数据库
1.2.2 文件管理系统的缺点
编写应用程序不方便
不支持对文件的并发访问
无安全控制功能
难以按用户视图表示数据
数据间联系弱
数据冗余不可避免
应用程序依赖性
1.3 数据库管理系统
1.3.1 相关概念
Database:数据库是数据的汇集,它以一定的组织形式存于存储介质上
DBMS:Database Management System, 是管理数据库的系统软件,它实现数据库系统的各种功
能。是数据库系统的核心
DBA:Database Administrator, 负责数据库的规划、设计、协调、维护和管理等工作
Application:应用程序,指以数据库为基础的应用程序
1.3.2 数据库管理系统的优点
程序与数据相互独立
保证数据的安全、可靠
最大限度地保证数据的正确性
数据可以并发使用并能同时保证一致性
相互关联的数据的集合
较少的数据冗余
1.3.3 数据库管理系统的基本功能
数据定义
数据处理
数据安全
数据备份
1.3.4 各种数据库管理系统
1.3.4.1 层次数据库
分层结构由IBM在20世纪60年代开发,并在早期大型机DBMS中使用。记录的关系形成了一个树状模
型。这种结构简单,但缺乏灵活性,因为这种关系仅限于一对多关系。
代表数据库:IBM IMS(信息管理系统)
1.3.4.2 网状数据库
1964年通用电气GE公司的 Charles Bachman 成功地开发出世界上第一个网状数据库IDS(集成数据存
储),IDS 具有数据模式和日志的特征,只能在GE主机运行
1.3.4.3 关系型数据库 RDBMS
Relational Database Management System,关系模型最初由IBM公司的英国计算机科学家埃德加·科德
(Edgar F. Codd)于1969年描述
1974年,IBM开始开发系统R,这是一个开发RDBMS原型的研究项目。
然而,第一个商业上可用的RDBMS是甲骨文,于1979年由关系软件(现为甲骨文oracle公司)发布
1.3.4.3.1 关系统型数据库相关概念
关系Relational :关系就是二维表,其中:表中的行、列次序并不重要
行row:表中的每一行,又称为一条记录record
列column:表中的每一列,称为属性,字段,域field
主键Primary key:PK ,一个或多个字段的组合, 用于惟一确定一个记录的字段,一张表只有一个主
键, 主键字段不能为空NULL
唯一键Unique key: 一个或多个字段的组合,用于惟一确定一个记录的字段,一张表可以有多个UK,而
且UK字段可以为NULL
域domain:属性的取值范围,如,性别只能是'男'和'女'两个值,人类的年龄只能0-150
1.3.4.3.2 常用关系数据库
MySQL: MySQL, MariaDB, Percona Server
PostgreSQL: 简称为pgsql,EnterpriseDB
Oracle
MSSQL Server
DB2
1.3.5 数据库排名
https://db-engines.com/en/ranking
1.4 关系型数据库理论
1.4.1 实体-联系模型E-R
E-R模型即实体-关系模型﹐E-R模型就是描述数据库存储数据的结构模型
对于大型公司开发项目﹐需要根据产品经理的设计﹐先使用建模工具,如:power designer ,db desinger
等这些软件来画出实体-关系模型(E-R模型)
实体Entity:客观存在并可以相互区分的客观事物或抽象事件称为实体即表,在E-R图中用矩形表示
实体,把实体名写在框内
属性Attribute:实体所具有的特征或性质,描述实体里面的单个信息, 使用椭圆形表示
联系Relationship:描述了实体的属性之间的关联规则
• 实体内部的联系:指组成同一个实体内的各属性之间的联系。如职工实体中,职工号和部门经理
号之间有一种关联关系
• 实体之间的联系:指不同实体之间的属性的联系。例:学生选课实体和学生基本信息实体之间
• 实体之间的联系用菱形框表示
E-R 模型范例:
1.4.2 联系类型
一对一联系(1:1): 在表A或表B中创建一个字段﹐存储另一个表的主键值 如: 一个人只有一个身份
证
一对多联系(1:n):外键, 如: 部门和员工
多对多联系(m:n):增加第三张表, 如: 学生和课程
1.4.3 数据的操作
开发工程师 CRUD (增加Create、查询Read或 Retrieve、更新Update、 删除Delete)
数据提取:在数据集合中提取感兴趣的内容。SELECT
数据更新:变更数据库中的数据。INSERT、DELETE、UPDATE
1.4.4 数据库的正规化分析
数据库规范化,又称数据库或资料库的正规化、标准化,是数据库设计中的一系列原理和技术,以减少
数据库中数据冗余,增进数据的一致性。关系模型的发明者埃德加·科德最早提出这一概念,并于1970年
代初定义了第一范式、第二范式和第三范式的概念
设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,不同的规范要求被称为不同范
式,各种范式呈递次规范,越高的范式数据库冗余越小
目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴德斯科范式
(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。满足最低要求的范式是第一范式
(1NF)。在第一范式的基础上进一步满足更多规范要求的称为第二范式(2NF),其余范式以次类
推。一般数据库只需满足第三范式(3NF)即可
规则是死的,人是活的,所以范式是否必须遵守,要看业务需要而定
掌握范式的目的是为了在合适的场景下违反范式
1.4.4.1 第一范式:1NF
无重复的列,每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有
多个值或者不能有重复的属性,确保每一列的原子性。除去同类型的字段,就是无重复的列
说明:第一范式(1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据
库
1.4.4.2 第二范式:2NF
第二范式必须先满足第一范式,属性完全依赖于主键,要求表中的每个行必须可以被唯一地区分,通常
为表加上每行的唯一标识主键PK,非PK的字段需要与整个PK有直接相关性,即非PK的字段不能依赖于部
分主键
1.4.4.3 第三范式:3NF
满足第三范式必须先满足第二范式属性,非主键属性不依赖于其它非主键属性。第三范式要求一个数据
表中不包含已在其它表中已包含的非主关键字信息,非PK的字段间不能有从属关系
1.4.5 SQL 结构化查询语言简介
SQL:Structure Query Language,结构化查询语言是1974年由Boyce和Chamberlin提出的一个通用
的、功能极强的关系性数据库语言
SQL解释器:将SQL语句解释成机器语言
数据存储协议:应用层协议,C/S
S:server, 监听于套接字,接收并处理客户端的应用请求
C:Client
客户端程序接口
CLI
GUI
应用编程接口
ODBC:Open Database Connectivity
JDBC:Java Data Base Connectivity
2 MySQL安装和基本使用
2.1 MySQL 介绍
2.1.1 MySQL 历史
MySQL的历史可以追溯到1979年,它的创始人叫作Michael Widenius,他在开发一个报表工具的时
候,设计了一套API,后来他的客户要求他的API支持sql语句,他直接借助于mSQL(当时比较牛)的代
码,将它集成到自己的存储引擎中。但是他总是感觉不满意,萌生了要自己做一套数据库的想法。
直到1996年,MySQL 1.0发布,Michael Widenius的大女儿的简称就是MY,Michael Widenius大概也
是把MySQL当成自己的女儿一样来对待.仅仅过了几个月的时间,1996年10月MySQL 3.11.1当时发布了
Solaris的版本,一个月后,linux的版本诞生,从那时候开始,MySQL慢慢的被人所接受。
1999年,Michael Widenius成立了MySQL AB公司,MySQL由个人开发转变为团队开发,2000年使用
GPL协议开源。
2001年,MySQL生命中的大事发生了,那就是存储引擎InnoDB的诞生!Oracle在2005年收购了
InnoDB,只不过InnoDB一直以来都只能作为第三方插件供用户选择。直到现在,MySQL可以选择的众
多存储引擎中,InnoDB依然是第一选择
2008年1月,MySQL AB公司被Sun公司以10亿美金收购,MySQL数据库进入Sun时代。Sun为MySQL
的发展提供了绝佳的环境,2008年11月,MySQL 5.1发布,MySQL成为了最受欢迎的小型数据库。
2009年4月,Oracle公司以74亿美元收购Sun公司,MySQL也随之进入Oracle时代。
2010年12月,MySQL 5.5发布,Oracle终于把InnoDB做成了MySQL默认的存储引擎,MySQL从此进入
了辉煌时代。
然而,从那之后,Oracle对MySQL的态度渐渐发生了变化,Oracle虽然宣称MySQL依然尊少GPL协议,
但却暗地里把开发人员全部换成了Oracle自己人,开源社区再也影响不了MySQL发展的脚步,真正有心
做贡献的人也被拒之门外,MySQL随时都有闭源的可能……
看着自己辛苦养大的MySQL被Oracle搞成这样,Michael Widenius非常失望,决定在MySQL走向闭源
前,将MySQL进行分支化,依然是使用了自己小女儿的名字MariaDB(玛莉亚DB)。
MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可 MariaDB的
目的是完全兼容MySQL,包括API和命令行,使之能轻松成为MySQL的代替品。在存储引擎方面,使用
XtraDB来代替MySQL的InnoDB。
MariaDB由MySQL的创始人Michael Widenius主导,由开源社区的大神们进行开发。因此,大家都认
为,MariaDB拥有比MySQL更纯正的MySQL血脉。
最初的版本更新与MySQL同步,相对MySQL5以后的版本,MariaDB也有相应的5.1~5.5的版本。后来
MariaDB终于摆脱了MySQL,它的版本号直接从10.0开始,以自己的步伐进行开发,当然,还是可以对
MySQL完全兼容。
MySQL大事记
1979年:TcX公司 Monty Widenius,Unireg
1996年:发布MySQL1.0,Solaris版本,Linux版本
1999年:MySQL AB公司,瑞典
2003年:MySQL 5.0版本,提供视图、存储过程等功能
2008年:Sun公司 以10亿美元收购MySQL
2009年:Oracle公司以 74 亿美元收购 sun 公司
2009年:Monty成立MariaDB
2.2.2 MySQL系列
2.2.2.1 MySQL 的三大主要分支
MySQL
Mariadb
Percona Server
2.2.2.2 官方网址
2.2.2.3 官方文档
https://www.percona.com/software/mysql-database/percona-server
2.2.2.4 版本演变
MySQL:5.1 --> 5.5 --> 5.6 --> 5.7 -->8.0
MariaDB:5.1 -->5.5 -->10.0--> 10.1 --> 10.2 --> 10.3 --> 10.4 --> 10.5
MySQL被Sun收购后,搞了个过渡的6.0版本,没多久就下线了,后来被Oracle收购后,终于迎来了像样的5.6
版本,之后就是5.7、8.0版本。由于6.0版本号已被用过,7.x系列版本专用于NDB Cluster,因而新版本
号从8.0开始。
2.2.3 MySQL的特性
开源免费
插件式存储引擎:也称为"表类型",存储管理器有多种实现版本,功能和特性可能均略有差别;用
户可根据需要灵活选择,Mysql5.5.5开始innoDB引擎是MYSQL默认引擎
MyISAM ==> Aria
InnoDB ==> XtraDB
单进程,多线程
诸多扩展和新特性
提供了较多测试组件
2.2 MySQL 安装方式介绍和快速安装
2.2.1 安装方式介绍
程序包管理器管理的程序包
源代码编译安装
二进制格式的程序包:展开至特定路径,并经过简单配置后即可使用
2.2.2 RPM包安装MySQL
CentOS 安装光盘
项目官方:https://downloads.mariadb.org/mariadb/repositories/
国内镜像:https://mirrors.tuna.tsinghua.edu.cn/mariadb/yum/
CentOS 8:安装光盘直接提供
mysql-server:8.0
mariadb-server : 10.3
CentOS 7:安装光盘直接提供
mariadb-server:5.5 服务器包
mariadb
客户端工具包
CentOS 6:
mysql-server:5.1 服务器包
mysql 客户端工具包
范例: CentOS 7 利用yum源安装MySQL5.7
[root@centos7 ~]#tee /etc/yum.repos.d/mysql.repo <<EOF
[mysql]
name=mysql5.7
baseurl=https://mirrors.tuna.tsinghua.edu.cn/mysql/yum/mysql-5.7-community-el7-
x86_64/
gpgcheck=0
EOF
[root@centos7 ~]#yum -y install mysql-community-server
[root@centos7 ~]#systemctl enable --now mysqld
[root@centos7 ~]#ss -ntl
State
Recv-Q Send-Q
Local Address:Port
*:22
Peer Address:Port
LISTEN
LISTEN
LISTEN
LISTEN
LISTEN
0
0
0
0
0
128
100
128
100
80
*:*
*:*
127.0.0.1:25
[::]:22
[::]:*
[::]:*
[::]:*
[::1]:25
[::]:3306
[root@centos7 ~]#mysql
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password:
NO)
[root@centos7 ~]#grep password /var/log/mysqld.log
2021-01-27T00:45:09.953242Z 1 [Note] A temporary password is generated for
root@localhost: pe%b#S8ah)j-
2021-01-27T00:46:09.491494Z 2 [Note] Access denied for user 'root'@'localhost'
(using password: NO)
#修改初始密码方法1
[root@centos7 ~]#mysql -uroot -p'pe%b#S8ah)j-'
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.7.33
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
#使用初始密码登录无法执行操作,需要修改密码后才可以
mysql> status
ERROR 1820 (HY000): You must reset your password using ALTER USER statement
before executing this statement.
#修改简单密码不符合密码策略
mysql> alter user root@'localhost' identified by 'Magedu2021';
ERROR 1819 (HY000): Your password does not satisfy the current policy
requirements
#修改为复杂密码
mysql> alter user root@'localhost' identified by 'Magedu0!';
Query OK, 0 rows affected (0.00 sec)
mysql> status
mysql Ver 14.14 Distrib 5.7.33, for Linux (x86_64) using EditLine wrapper
Connection id:
Current database:
Current user:
4
root@localhost
SSL:
Not in use
Current pager:
Using outfile:
Using delimiter:
Server version:
stdout
''
;
5.7.33
Protocol version: 10
Connection:
Localhost via UNIX socket
Server characterset:
latin1
Db
characterset:
latin1
Client characterset:
Conn. characterset:
UNIX socket:
utf8
utf8
/var/lib/mysql/mysql.sock
Uptime:
3 min 38 sec
Threads: 1 Questions: 8 Slow queries: 0 Opens: 106 Flush tables: 1 Open
tables: 99 Queries per second avg: 0.036
mysql> exit
#修改初始密码方法2
[root@centos7 ~]#mysqladmin -uroot -p'pe%b#S8ah)j-' password 'Magedu0!'
mysqladmin: [Warning] Using a password on the command line interface can be
insecure.
Warning: Since password will be sent to server in plain text, use ssl connection
to ensure password safety.
范例: CentOS 7 利用yum源安装Mariadb
https://mariadb.org/download/#mariadb-repositories
参考网站信息,配置yum源
#创建yum仓库配置文件
[root@centos7 ~]#cat /etc/yum.repos.d/mariadb.repo
# MariaDB 10.5 CentOS repository list - created 2021-01-27 07:45 UTC
# https://mariadb.org/download/
[mariadb]
name = MariaDB
baseurl = https://mirrors.nju.edu.cn/mariadb/yum/10.5/centos7-amd64
gpgkey=https://mirrors.nju.edu.cn/mariadb/yum/RPM-GPG-KEY-MariaDB
gpgcheck=1
[root@centos7 ~]#yum install MariaDB-server -y
[root@centos7 ~]#systemctl enable --now mariadb.service
[root@centos7 ~]#mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 4
Server version: 10.5.8-MariaDB MariaDB Server
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> status
mysql Ver 15.1 Distrib 10.5.8-MariaDB, for Linux (x86_64) using readline 5.1
Connection id:
Current database:
Current user:
4
root@localhost
SSL:
Not in use
Current pager:
Using outfile:
Using delimiter:
Server:
stdout
''
;
MariaDB
Server version:
Protocol version:
10.5.8-MariaDB MariaDB Server
10
Connection:
Server characterset:
Db characterset:
Localhost via UNIX socket
latin1
latin1
Client characterset:
Conn. characterset:
UNIX socket:
utf8
utf8
/var/lib/mysql/mysql.sock
Uptime:
2 min 43 sec
Threads: 2 Questions: 8 Slow queries: 0 Opens: 16 Open tables: 10 Queries
per second avg: 0.049
MariaDB [(none)]>
范例: Ubuntu 利用默认仓库安装 MySQL 5.7
[root@ubuntu1804 ~]#apt install mysql-server
[root@ubuntu1804 ~]#systemctl status mysql.service
● mysql.service - MySQL Community Server
Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset:
enabled)
Active: active (running) since Wed 2021-01-27 15:41:33 CST; 10min ago
Main PID: 2115 (mysqld)
Tasks: 28 (limit: 2290)
CGroup: /system.slice/mysql.service
└─2115 /usr/sbin/mysqld --daemonize --pid-file=/run/mysqld/mysqld.pid
Jan 27 15:41:33 ubuntu1804.magedu.org systemd[1]: Starting MySQL Community
Server...
Jan 27 15:41:33 ubuntu1804.magedu.org systemd[1]: Started MySQL Community
Server.
[root@ubuntu1804 ~]#mysql
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.32-0ubuntu0.18.04.1 (Ubuntu)
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> status
mysql Ver 14.14 Distrib 5.7.32, for Linux (x86_64) using EditLine wrapper
Connection id:
Current database:
Current user:
3
root@localhost
SSL:
Not in use
Current pager:
Using outfile:
Using delimiter:
Server version:
Protocol version:
stdout
''
;
5.7.32-0ubuntu0.18.04.1 (Ubuntu)
10
Connection:
Server characterset:
Db characterset:
Localhost via UNIX socket
latin1
latin1
Client characterset:
Conn. characterset:
UNIX socket:
utf8
utf8
/var/run/mysqld/mysqld.sock
Uptime:
10 min 43 sec
Threads: 1 Questions: 10 Slow queries: 0 Opens: 105 Flush tables: 1 Open
tables: 98 Queries per second avg: 0.015
2.2.3 初始化脚本提高安全性
运行脚本:mysql_secure_installation
设置数据库管理员root口令
禁止root远程登录
删除anonymous用户帐号
删除test数据库
范例: 针对MySQL5.6前版本进行安全加固
root@centos7 ~]#mysql
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.6.51 MySQL Community Server (GPL)
Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database
|
+--------------------+
| information_schema |
| mysql
|
| performance_schema |
+--------------------+
3 rows in set (0.00 sec)
mysql> select user,host from mysql.user;
+------+--------------------------+
| user | host
|
+------+--------------------------+
| root | 127.0.0.1
| root | ::1
|
|
|
| centos7.wangxiaochun.com |
| root | centos7.wangxiaochun.com |
|
| localhost
|
|
| root | localhost
+------+--------------------------+
6 rows in set (0.00 sec)
mysql> exit
Bye
[root@centos7 ~]#
[root@centos7 ~]#mysql -uxxx
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.6.51 MySQL Community Server (GPL)
Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> status
mysql Ver 14.14 Distrib 5.6.51, for Linux (x86_64) using EditLine wrapper
Connection id:
Current database:
Current user:
3
xxx@localhost
SSL:
Not in use
Current pager:
Using outfile:
Using delimiter:
Server version:
stdout
''
;
5.6.51 MySQL Community Server (GPL)
Protocol version: 10
Connection:
Localhost via UNIX socket
Server characterset:
latin1
Db
characterset:
latin1
Client characterset:
Conn. characterset:
UNIX socket:
utf8
utf8
/var/lib/mysql/mysql.sock
Uptime:
5 min 2 sec
Threads: 1 Questions: 11 Slow queries: 0 Opens: 67 Flush tables: 1 Open
tables: 60 Queries per second avg: 0.036
mysql> exit
Bye
[root@centos7 ~]#file `which mysql_secure_installation `
/usr/bin/mysql_secure_installation: Perl script, ASCII text executable
[root@centos7 ~]#mysql_secure_installation
NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MySQL
SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY!
In order to log into MySQL to secure it, we'll need the current
password for the root user. If you've just installed MySQL, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.
Enter current password for root (enter for none):
OK, successfully used password, moving on...
Setting the root password ensures that nobody can log into the MySQL
root user without the proper authorisation.
Set root password? [Y/n] y
New password:
Re-enter new password:
Password updated successfully!
Reloading privilege tables..
... Success!
By default, a MySQL installation has an anonymous user, allowing anyone
to log into MySQL without having to have a user account created for
them. This is intended only for testing, and to make the installation
go a bit smoother. You should remove them before moving into a
production environment.
Remove anonymous users? [Y/n] y
... Success!
Normally, root should only be allowed to connect from 'localhost'. This
ensures that someone cannot guess at the root password from the network.
Disallow root login remotely? [Y/n] y
... Success!
By default, MySQL comes with a database named 'test' that anyone can
access. This is also intended only for testing, and should be removed
before moving into a production environment.
Remove test database and access to it? [Y/n] y
- Dropping test database...
ERROR 1008 (HY000) at line 1: Can't drop database 'test'; database doesn't exist
... Failed! Not critical, keep moving...
- Removing privileges on test database...
... Success!
Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.
Reload privilege tables now? [Y/n] y
... Success!
All done! If you've completed all of the above steps, your MySQL
installation should now be secure.
Thanks for using MySQL!
Cleaning up...
[root@centos7 ~]#
2.3 MySQL 组成和常用工具
2.3.1 客户端程序
mysql: 基于mysql协议交互式或非交互式的CLI工具
mysqldump:备份工具,基于mysql协议向mysqld发起查询请求,并将查得的所有数据转换成
insert等写操作语句保存文本文件中
mysqladmin:基于mysql协议管理mysqld
mysqlimport:数据导入工具
MyISAM存储引擎的管理工具:
myisamchk:检查MyISAM库
myisampack:打包MyISAM表,只读
2.3.2 服务器端程序
mysqld_safe
mysqld
mysqld_multi
多实例 ,示例:mysqld_multi --example
2.3.3 用户账号
mysql用户账号由两部分组成:
'USERNAME'@'HOST'
wang@'10.0.0.100'
wang@'10.0.0.%'
wang@'%'
说明:
HOST限制此用户可通过哪些远程主机连接mysql服务器
支持使用通配符:
% 匹配任意长度的任意字符,相当于shell中*, 示例: 172.16.0.0/255.255.0.0 或 172.16.%.%
匹配任意单个字符,相当于shell中?
_
2.3.4 mysql 客户端命令
2.3.4.1 mysql 运行命令类型
客户端命令:本地执行,每个命令都完整形式和简写格式
范例: 查看版本
[root@centos8 ~]#mysql -V
mysql Ver 8.0.21 for Linux on x86_64 (Source distribution)
范例:
mysql> \h, help
mysql> \u,use
mysql> \s,status
mysql> \,system
服务端命令:通过mysql协议发往服务器执行并取回结果,命令末尾都必须使用命令结束符号,默
认为分号
#示例:
mysql>SELECT VERSION();
2.3.4.2 mysql 使用模式
交互模式
脚本模式:
mysql -uUSERNAME -pPASSWORD < /path/somefile.sql
cat /path/somefile.sql | mysql -uUSERNAME -pPASSWORD
mysql>source
/path/from/somefile.sql
2.3.4.3 mysql命令使用格式
mysql [OPTIONS] [database]
mysql客户端常用选项:
-A, --no-auto-rehash 禁止补全
-u, --user=
-h, --host=
用户名,默认为root
服务器主机,默认为localhost
-p, --passowrd= 用户密码,建议使用-p,默认为空密码
-P, --port=
服务器端口
-S, --socket=
-D, --database=
指定连接socket文件路径
指定默认数据库
-C, --compress 启用压缩
-e "SQL" 执行SQL命令
-V, --version
-v --verbose
--print-defaults
显示版本
显示详细信息
获取程序默认使用的配置
登录系统:
#默认空密码登录
mysql -uroot -p
范例: 运行mysql命令
mysql>use mysql
#切换数据库
mysql> select database();
mysql>select user();
#查看当前数据库
#查看当前用户
mysql>SELECT User,Host,Password FROM user;
mysql>system clear
#清屏
mysql> ^DBye
#ctrl+d 退出
范例:客户端 mysql 的配置文件,修改提示符
#查看mysql版本
[root@centos8 ~]#mysql -V
mysql Ver 15.1 Distrib 10.3.11-MariaDB, for Linux (x86_64) using readline 5.1
#临时修改mysql提示符
[root@centos8 ~]#mysql -uroot -pcentos --prompt="\r:\m:\s(\u@\h) [\d]>\_"
#临时修改mysql提示符
[root@centos8 ~]#export MYSQL_PS1="\r:\m:\s(\u@\h) [\d]>\_"
#持久修改mysql提示符
[root@centos8 ~]#vim /etc/my.cnf.d/mysql-clients.cnf
[mysql]
prompt="\r:\m:\s(\u@\h) [\d]>\_"
[root@centos8 ~]#mysql --print-defaults -v
mysql would have been started with the following arguments:
--prompt=\r:\m:\s(\u@\h) [\d]>\ -v
[root@centos8 ~]#mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 11
Server version: 10.3.11-MariaDB MariaDB Server
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
10:29:30(root@localhost) [(none)]> use mysql
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
10:29:34(root@localhost) [mysql]> exit
范例:配置所有MySQL 客户端的自动登录
vim /etc/my.cnf.d/client.cnf
[client]
user=wang
password=123456
[mysql]
prompt=(\u@\h) [\d]>\_
2.3.4.4 mysqladmin命令
mysqladmin 命令格式
mysqladmin [OPTIONS] command command....
范例:
#查看mysql服务是否正常,如果正常提示mysqld is alive
mysqladmin -uroot -pcentos
ping
#关闭mysql服务,但mysqladmin命令无法开启
mysqladmin -uroot -pcentos shutdown
#创建数据库testdb
mysqladmin -uroot -pcentos
#删除数据库testdb
create testdb
mysqladmin -uroot -pcentos
#修改root密码
drop testdb
mysqladmin -uroot -pcentos password 'magedu'
#日志滚动,生成新文件/var/lib/mysql/mariadb-bin.00000N
mysqladmin -uroot -pcentos flush-logs
2.3.4.5 mycli
MyCLI 是基于Python开发的MySQL的命令行工具,具有自动完成和语法突出显示功能
安装
#CentOS8安装
[root@centos8 ~]#yum install python3-pip -y
[root@centos8 ~]#pip3 install mycli
#ubuntu安装
[root@ubuntu1804 ~]#apt -y install mycli
[root@ubuntu1804 ~]#mycli -u root -S /var/run/mysqld/mysqld.sock
使用Mycli
2.3.5 服务器端配置
2.3.5.1 服务器端配置文件
服务器端(mysqld):工作特性有多种配置方式
1、命令行选项:
2、配置文件:类ini格式,集中式的配置,能够为mysql的各应用程序提供配置信息
服务器端配置文件:
/etc/my.cnf
#Global选项
/etc/mysql/my.cnf
~/.my.cnf
#Global选项
#User-specific 选项
配置文件格式:
[mysqld]
[mysqld_safe]
[mysqld_multi]
[mysql]
[mysqladmin]
[mysqldump]
[server]
[client]
格式:
parameter = value
说明:
_和- 相同
1,ON,TRUE意义相同, 0,OFF,FALSE意义相同,无区分大小写
2.3.5.2 socket 连接说明
官方说明
https://dev.mysql.com/doc/mysql-port-reference/en/mysql-ports-reference-
tables.html#mysql-client-server-ports
服务器监听的两种 socket 地址:
ip socket: 监听在tcp的3306端口,支持远程通信 ,侦听3306/tcp端口可以在绑定有一个或全部接
口IP上
unix sock: 监听在sock文件上,仅支持本机通信, 如:/var/lib/mysql/mysql.sock)
说明:host为localhost 时自动使用unix sock
范例: MySQL的端口
mysql> SHOW VARIABLES LIKE 'port';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| port
| 3306
|
+---------------+-------+
1 row in set (0.01 sec)
#MySQL8.0增加了一个33060/tcp端口
#Port 33060 is the default port for the MySQL Database Extended Interface (the
MySQL X Protocol).
mysql> SHOW VARIABLES LIKE 'mysqlx_port';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| mysqlx_port
| 33060 |
+---------------+-------+
1 row in set (0.00 sec)
2.3.5.3 关闭mysqld网络连接
只侦听本地客户端, 所有客户端和服务器的交互都通过一个socket文件实现,socket的配置存放
在/var/lib/mysql/mysql.sock) 可在/etc/my.cnf修改
范例:
vim /etc/my.cnf
[mysqld]
skip-networking=1
bind_address=127.0.0.1
2.5 通用二进制格式安装 MySQL
2.5.1 实战案例:通用二进制格式安装 MySQL 5.6
2.5.1.1 准备用户
groupadd -r -g 306 mysql
useradd -r -g 306 -u 306 -d /data/mysql mysql
2.5.1.2 准备数据目录,建议使用逻辑卷
#可选做,后面的脚本mysql_install_db可自动生成此目录
mkdir -p /data/mysql
chown mysql:mysql /data/mysql
2.5.1.3 准备二进制程序
tar xf mysql-VERSION-linux-x86_64.tar.gz -C /usr/local
cd /usr/local
ln -sv mysql-VERSION mysql
chown -R root:root /usr/local/mysql/
2.5.1.4 准备配置文件
cd /usr/local/mysql
cp -b support-files/my-default.cnf
vim /etc/my.cnf
/etc/my.cnf
#mysql语句块中添加以下三个选项
[mysqld]
datadir = /data/mysql
innodb_file_per_table = on #在mariadb5.5以上版的是默认值,可不加
skip_name_resolve = on
#禁止主机名解析,建议使用
2.5.1.5 创建数据库文件
cd /usr/local/mysql/
./scripts/mysql_install_db --datadir=/data/mysql --user=mysql
[root@centos8 mysql]#ls /data/mysql/ -l
total 110604
-rw-rw---- 1 mysql mysql 12582912 Jun 1 16:44 ibdata1
-rw-rw---- 1 mysql mysql 50331648 Jun 1 16:44 ib_logfile0
-rw-rw---- 1 mysql mysql 50331648 Jun 1 16:44 ib_logfile1
drwx------ 2 mysql mysql
drwx------ 2 mysql mysql
drwx------ 2 mysql mysql
4096 Jun 1 16:44 mysql
4096 Jun 1 16:44 performance_schema
4096 Jun 1 16:44 test
2.5.1.6 准备服务脚本,并启动服务
cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
chkconfig --add mysqld
service mysqld start
#如果有对应的service 文件可以执行下面
cp /usr/local/mysql/support-files/systemd/mariadb.service
/usr/lib/systemd/system/
systemctl daemon-reload
systemctl enable --now mariadb
2.5.1.7 PATH路径
echo 'PATH=/usr/local/mysql/bin:$PATH' > /etc/profile.d/mysql.sh
.
/etc/profile.d/mysql.sh
2.5.1.8 安全初始化
/usr/local/mysql/bin/mysql_secure_installation
2.5.2 实战案例:一键安装mysql-5.6二进制包的脚本
2.5.2.1 离线安装mysql-5.6二进制包的脚本
[root@centos8 ~]#vim install_mysql5.6.sh
#!/bin/bash
DIR=`pwd`
NAME="mysql-5.6.47-linux-glibc2.12-x86_64.tar.gz"
FULL_NAME=$/$
DATA_DIR="/data/mysql"
yum install -y libaio perl-Data-Dumper
if [ -f $ ];then
echo "安装文件存在"
else
echo "安装文件不存在"
exit 3
fi
if [ -h /usr/local/mysql ];then
echo "Mysql 已经安装"
exit 3
else
tar xvf $
-C /usr/local/src
ln -sv /usr/local/src/mysql-5.6.47-linux-glibc2.12-x86_64 /usr/local/mysql
if id mysql;then
echo "mysql 用户已经存在,跳过创建用户过程"
else
useradd -r
-s /sbin/nologin mysql
fi
if id mysql;then
chown -R mysql.mysql /usr/local/mysql/*
if [ ! -d /data/mysql ];then
mkdir -pv /data/mysql && chown -R mysql.mysql /data
-R
/usr/local/mysql/scripts/mysql_install_db --user=mysql --
datadir=/data/mysql --basedir=/usr/local/mysql/
cp /usr/local/src/mysql-5.6.47-linux-glibc2.12-x86_64/support-
files/mysql.server /etc/init.d/mysqld
chmod a+x /etc/init.d/mysqld
cp $/my.cnf
/etc/my.cnf
ln -sv /usr/local/mysql/bin/mysql /usr/bin/mysql
/etc/init.d/mysqld start
chkconfig --add mysqld
else
echo "MySQL数据目录已经存在,"
exit 3
fi
fi
fi
[root@centos8 ~]#cat /etc/my.cnf
[mysqld]
socket=/data/mysql.sock
user=mysql
symbolic-links=0
datadir=/data/mysql
innodb_file_per_table=1
[client]
port=3306
socket=/data/mysql.sock
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/tmp/mysql.sock
[root@centos8 ~]#ls
install_mysql5.6.sh my.cnf mysql-5.6.47-linux-glibc2.12-x86_64.tar.gz
2.5.2.2 在线安装mysql-5.6二进制包的脚本
#!/bin/bash
#
#********************************************************************
#Author:
wangxiaochun
#QQ:
29308620
#Date:
2021-01-26
#FileName:
#URL:
install_online_mysql5.6_for_centos.sh
The test script
#Description:
#Copyright (C):
2021 All rights reserved
#********************************************************************
. /etc/init.d/functions
DIR=`pwd`
MYSQL_VERSION=5.6.51
NAME="mysql-$-linux-glibc2.12-x86_64.tar.gz"
FULL_NAME=$/$
URL=http://mirrors.163.com/mysql/Downloads/MySQL-5.6
DATA_DIR="/data/mysql"
rpm -q wget || yum -y -q install wget
wget $URL/$NAME || { action "下载失败,异常退出" false;exit 10; }
yum install -y -q libaio perl-Data-Dumper autoconf
if [ -f $ ];then
action "安装文件存在"
else
action "安装文件不存在" false
exit 3
fi
if [ -e /usr/local/mysql ];then
action "Mysql 已经安装" false
exit 3
else
tar xf $ -C /usr/local/src
ln -sv /usr/local/src/mysql-$-linux-glibc2.12-x86_64
/usr/local/mysql
if id mysql;then
action "mysql 用户已经存在,跳过创建用户过程"
else
useradd -r -s /sbin/nologin mysql
fi
if id mysql;then
chown -R mysql.mysql /usr/local/mysql/*
if [ ! -d /data/mysql ];then
mkdir -pv /data/mysql && chown -R mysql.mysql /data
/usr/local/mysql/scripts/mysql_install_db --user=mysql --
datadir=/data/mysql --basedir=/usr/local/mysql/
cp /usr/local/src/mysql-$-linux-glibc2.12-
x86_64/support-files/mysql.server /etc/init.d/mysqld
chmod a+x /etc/init.d/mysqld
cat > /etc/my.cnf <<EOF
[mysqld]
socket=/data/mysql/mysql.sock
user=mysql
symbolic-links=0
datadir=/data/mysql
innodb_file_per_table=1
[client]
port=3306
socket=/data/mysql/mysql.sock
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/tmp/mysql.sock
EOF
ln -sv /usr/local/mysql/bin/mysql /usr/bin/mysql
/etc/init.d/mysqld start
chkconfig --add mysqld
else
fi
action "MySQL数据目录已经存在" false
exit 3
fi
fi
2.5.3 实战案例:通用二进制安装安装MySQL 5.7 和 MySQL8.0
2.5.3.1 安装相关包
yum -y install libaio numactl-libs
2.5.3.2 用户和组
groupadd mysql
useradd -r -g mysql -s /bin/false mysql
2.5.3.3 准备程序文件
wget http://mirrors.163.com/mysql/Downloads/MySQL-5.7/mysql-5.7.31-linux-
glibc2.12-x86_64.tar.gz
tar xf mysql-5.7.31-linux-glibc2.12-x86_64.tar.gz -C /usr/local
cd /usr/local/
ln -s mysql-5.7.31-linux-glibc2.12-x86_64/ mysql
chown -R root.root /usr/local/mysql/
2.5.3.4 准备环境变量
echo 'PATH=/usr/local/mysql/bin:$PATH' > /etc/profile.d/mysql.sh
. /etc/profile.d/mysql.sh
2.5.3.5 准备配置文件
cp /etc/my.cnf{,.bak}
vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
skip_name_resolve=1
socket=/data/mysql/mysql.sock
log-error=/data/mysql/mysql.log
pid-file=/data/mysql/mysql.pid
[client]
socket=/data/mysql/mysql.sock
2.5.3.6 初始化数据库文件并提取root密码
#/data/mysql
会自动生成,但是/data/必须事先存在
mkdir -pv /data/mysql
2.5.3.6.1 方式1: 生成随机密码
mysqld --initialize --user=mysql --datadir=/data/mysql
...省略...
2019-07-04T13:03:54.258140Z 1 [Note] A temporary password is generated for
root@localhost: LufavlMka6,! #注意生成root的初始密码
grep password /data/mysql/mysql.log
2019-12-26T13:31:30.458826Z 1 [Note] A temporary password is generated for
root@localhost: LufavlMka6,!
awk '/temporary password/{print $NF}' /data/mysql/mysql.log
LufavlMka6,!
2.5.3.6.2 方式2: 生成 root 空密码
mysqld --initialize-insecure --user=mysql --datadir=/data/mysql
2.5.3.7 准备服务脚本和启动
cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
chkconfig --add mysqld
service mysqld start
2.5.3.8 修改口令
#修改前面生成的随机密码为指定密码
mysqladmin -uroot -p'LufavlMka6,!' password magedu
#修改前面生成的空密码为指定密码
mysqladmin -uroot password magedu
2.5.3.9 测试登录
mysql -uroot -pmagedu
2.5.4 实战案例:一键安装MySQL5.7 和 MySQL8.0 二进制包的脚本
2.5.4.1 离线安装脚本
#!/bin/bash
#
#********************************************************************
#Author:
#QQ:
wangxiaochun
29308620
#Date:
2020-02-12
#FileName:
#URL:
install_offline_mysql5.7or8.0_for_centos
The test script
#Description:
#Copyright (C):
2020 All rights reserved
#********************************************************************
#MySQL5.7 Download URL: https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-
5.7.29-linux-glibc2.12-x86_64.tar.gz
#http://mirrors.163.com/mysql/Downloads/MySQL-5.7/mysql-5.7.31-linux-glibc2.12-
x86_64.tar.gz
#MySQL8.0 Download URL: https://downloads.mysql.com/archives/get/p/23/file/mysql-
8.0.19-linux-glibc2.12-x86_64.tar.xz
#http://mirrors.163.com/mysql/Downloads/MySQL-8.0/mysql-8.0.23-linux-glibc2.12-
x86_64.tar.xz
. /etc/init.d/functions
SRC_DIR=`pwd`
#MYSQL='mysql-5.7.29-linux-glibc2.12-x86_64.tar.gz'
MYSQL='mysql-8.0.19-linux-glibc2.12-x86_64.tar.xz'
COLOR='echo -e \E[01;31m'
END='\E[0m'
MYSQL_ROOT_PASSWORD=magedu
check (){
if [ $UID -ne 0 ]; then
action "当前用户不是root,安装失败" false
exit 1
fi
cd $SRC_DIR
if [ ! -e $MYSQL ];then
$COLOR"缺少$文件"$END
$COLOR"请将相关软件放在$目录下"$END
exit
elif [ -e /usr/local/mysql ];then
action "数据库已存在,安装失败" false
exit
else
return
fi
}
install_mysql(){
$COLOR"开始安装MySQL数据库..."$END
yum -y -q install libaio numactl-libs
cd $SRC_DIR
tar xf $MYSQL -C /usr/local/
MYSQL_DIR=`echo $MYSQL| sed -nr 's/^(.*[0-9]).*/\1/p'`
ln -s /usr/local/$MYSQL_DIR /usr/local/mysql
chown -R root.root /usr/local/mysql/
id mysql &> /dev/null || { useradd -s /sbin/nologin -r mysql ; action "创建
mysql用户"; }
echo 'PATH=/usr/local/mysql/bin/:$PATH' > /etc/profile.d/mysql.sh
.
/etc/profile.d/mysql.sh
ln -s /usr/local/mysql/bin/* /usr/bin/
cat > /etc/my.cnf <<-EOF
[mysqld]
server-id=1
log-bin
datadir=/data/mysql
socket=/data/mysql/mysql.sock
log-error=/data/mysql/mysql.log
pid-file=/data/mysql/mysql.pid
[client]
socket=/data/mysql/mysql.sock
EOF
[ -d /data ] || mkdir /data
mysqld --initialize --user=mysql --datadir=/data/mysql
cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
chkconfig --add mysqld
chkconfig mysqld on
service mysqld start
[ $? -ne 0 ] && { $COLOR"数据库启动失败,退出!"$END;exit; }
sleep 3
MYSQL_OLDPASSWORD=`awk '/A temporary password/{print $NF}'
/data/mysql/mysql.log`
mysqladmin -uroot -p$MYSQL_OLDPASSWORD password $MYSQL_ROOT_PASSWORD
&>/dev/null
action "数据库安装完成"
}
check
install_mysql
2.5.4.2 在线安装脚本
[root@centos7 ~]#cat install_online_mysql5.7or8.0_for_centos.sh
#!/bin/bash
#
#********************************************************************
#Author:
wangxiaochun
#QQ:
29308620
#Date:
2020-02-12
#FileName:
#URL:
install_online_mysql5.7or8.0_for_centos
The test script
#Description:
#Copyright (C):
2020 All rights reserved
#********************************************************************
#MySQL Download URL: https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.29-
linux-glibc2.12-x86_64.tar.gz
#http://mirrors.163.com/mysql/Downloads/MySQL-5.7/mysql-5.7.31-linux-glibc2.12-
x86_64.tar.gz
#http://mirrors.163.com/mysql/Downloads/MySQL-8.0/mysql-8.0.23-linux-glibc2.12-
x86_64.tar.xz
. /etc/init.d/functions
SRC_DIR=`pwd`
MYSQL='mysql-5.7.33-linux-glibc2.12-x86_64.tar.gz'
URL=http://mirrors.163.com/mysql/Downloads/MySQL-5.7
#MYSQL='mysql-8.0.23-linux-glibc2.12-x86_64.tar.xz'
#URL=http://mirrors.163.com/mysql/Downloads/MySQL-8.0
COLOR='echo -e \E[01;31m'
END='\E[0m'
MYSQL_ROOT_PASSWORD=magedu
check (){
if [ $UID -ne 0 ]; then
action "当前用户不是root,安装失败" false
exit 1
fi
cd $SRC_DIR
rpm -q wget || yum -y -q install wget
wget $URL/$MYSQL
if [ ! -e $MYSQL ];then
$COLOR"缺少$文件"$END
$COLOR"请将相关软件放在$目录下"$END
exit
elif [ -e /usr/local/mysql ];then
action "数据库已存在,安装失败" false
exit
else
return
fi
}
install_mysql(){
$COLOR"开始安装MySQL数据库..."$END
yum -y -q install libaio numactl-libs
cd $SRC_DIR
tar xf $MYSQL -C /usr/local/
MYSQL_DIR=`echo $MYSQL| sed -nr 's/^(.*[0-9]).*/\1/p'`
ln -s /usr/local/$MYSQL_DIR /usr/local/mysql
chown -R root.root /usr/local/mysql/
id mysql &> /dev/null || { useradd -s /sbin/nologin -r mysql ; action "创建
mysql用户"; }
echo 'PATH=/usr/local/mysql/bin/:$PATH' > /etc/profile.d/mysql.sh
.
/etc/profile.d/mysql.sh
ln -s /usr/local/mysql/bin/* /usr/bin/
cat > /etc/my.cnf <<-EOF
[mysqld]
server-id=`hostname -I|cut -d. -f4`
log-bin
datadir=/data/mysql
socket=/data/mysql/mysql.sock
log-error=/data/mysql/mysql.log
pid-file=/data/mysql/mysql.pid
[client]
socket=/data/mysql/mysql.sock
EOF
[ -d /data ] || mkdir /data
mysqld --initialize --user=mysql --datadir=/data/mysql
cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
chkconfig --add mysqld
chkconfig mysqld on
service mysqld start
[ $? -ne 0 ] && { $COLOR"数据库启动失败,退出!"$END;exit; }
sleep 3
MYSQL_OLDPASSWORD=`awk '/A temporary password/{print $NF}'
/data/mysql/mysql.log`
mysqladmin -uroot -p$MYSQL_OLDPASSWORD password $MYSQL_ROOT_PASSWORD
&>/dev/null
action "数据库安装完成"
}
check
install_mysql
2.6 源码编译安装 MySQL
建议:内存6G以上,否则可能会编译出错,CPU 核数越多越好
2022年1月21日M48期8C,16G花了3分钟
说明:本操作过程适用于以下版本
mysql-5.6.51.tar.gz
mariadb-10.2.18.tar.gz
CentOS 7
2.6.1 安装相关依赖包
yum -y install gcc gcc-c++ cmake bison bison-devel zlib-devel libcurl-devel
libarchive-devel boost-devel
ncurses-devel gnutls-devel libxml2-devel
openssl-devel libevent-devel libaio-devel perl-Data-Dumper
2.6.2 做准备用户和数据目录
useradd -r -s /sbin/nologin -d /data/mysql mysql
2.6.3 准备数据库目录
mkdir
/data/mysql
chown mysql.mysql /data/mysql
2.6.4 源码编译安装
编译安装说明
利用cmake编译,而利用传统方法,cmake的重要特性之一是其独立于源码(out-of-source)的编译功能,
即编译工作可以在另一个指定的目录中而非源码目录中进行,这可以保证源码目录不受任何一次编译的
影响,因此在同一个源码树上可以进行多次不同的编译,如针对于不同平台编译
编译选项:
https://dev.mysql.com/doc/refman/5.7/en/source-configuration-options.html
2.6.4.1 下载并解压缩源码包
tar xvf
mysql-5.6.51.tar.gz -C /usr/local/src
#mariadb-10.2.18.tar.gz
2.6.4.2 源码编译安装 MySQL
cd mysql-5.6.51/
cmake . \
-DCMAKE_INSTALL_PREFIX=/apps/mysql \
-DMYSQL_DATADIR=/data/mysql/ \
-DSYSCONFDIR=/etc/
\
-DMYSQL_USER=mysql \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DWITH_ARCHIVE_STORAGE_ENGINE=1 \
-DWITH_BLACKHOLE_STORAGE_ENGINE=1 \
-DWITH_PARTITION_STORAGE_ENGINE=1
\
-DWITHOUT_MROONGA_STORAGE_ENGINE=1 \
-DWITH_DEBUG=0 \
-DWITH_READLINE=1 \
-DWITH_SSL=system \
-DWITH_ZLIB=system \
-DWITH_LIBWRAP=0 \
-DENABLED_LOCAL_INFILE=1
\
-DMYSQL_UNIX_ADDR=/data/mysql/mysql.sock \
-DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci
make -j 8 && make install
提示:如果出错,执行rm -f CMakeCache.txt
2.6.5 准备环境变量
echo 'PATH=/apps/mysql/bin:$PATH' > /etc/profile.d/mysql.sh
.
/etc/profile.d/mysql.sh
2.6.6 生成数据库文件
cd
/apps/mysql/
scripts/mysql_install_db --datadir=/data/mysql/ --user=mysql
2.6.7 准备配置文件
cp -b /apps/mysql/support-files/my-default.cnf /etc/my.cnf
#针对旧版本或mariadb-10.2.18.tar.gz
cp /apps/mysql/support-files/my-huge.cnf
/etc/my.cnf
2.6.8 准备启动脚本,并启动服务
cp /apps/mysql/support-files/mysql.server /etc/init.d/mysqld
chkconfig --add mysqld
service mysqld start
2.6.9 安全初始化
mysql_secure_installation
2.7 基于 docker 容器创建 MySQL
范例:
[root@ubuntu1804 ~]#docker run --name mysql -d -p 3306:3306 -e
MYSQL_ROOT_PASSWORD=123456 mysql:5.7.30
[root@ubuntu1804 ~]#mysql -uroot -p123456 -h127.0.0.1
2.8 MySQL多实例
2.8.1 多实例介绍和方案
2.8.1.1 多实例介绍
什么是数据库多实例
多实例类似微信双开,端口号类比微信账号,数据库类比聊天窗口,表类比聊天记录(N50期张柏杰
语录)
MySQL多实例就是在一台服务器上同时开启多个不同的服务端口(如:3306、3307等),同时运
行多个MySQL服务进程,这些服务进程通过不同的Socket监听不同的服务端口来提供服务。
多实例可能是MySQL的不同版本,也可能是MySQL的同一版本实现
多实例的好处
可有效利用服务器资源。当单个服务器资源有剩余时,可以充分利用剩余资源提供更多的服务,且
可以实现资源的逻辑隔离节约服务器资源。例如公司服务器资源紧张,但是数据库又需要各自尽量
独立的提供服务,并且还需要到主从复制等技术,多实例就是最佳选择
多实例弊端
存在资源互相抢占的问题。比如:当某个数据库实例并发很高或者SQL查询慢时,整个实例会消耗
大量的CPU、磁盘I/O等资源,导致服务器上面其他的数据库实例在提供服务的质量也会下降,所以
具体的需求要根据自己的实际情况而定。
2.8.1.2 MySQL多实例常见的配置方案
单一的配置文件、单一启动程序多实例部署方式
MySQL官方文档提到的单一配置文件、单一启动程序多实例部署方式
耦合度太高,一个配置文件不好管理。不是很推荐。
多配置文件、多启动程序部署方式
多配置文件、多启动程序部署方式是针对每个实例都有独立的配置文件和目录,管理灵活,此方案耦
合度较低
工作开发和运维的统一原则:降低耦合度。所以建议的此方式。
2.8.2 实战案例 :CentOS 8 实现mariadb的yum安装的多实例
2.8.2.1 实战目的
CentOS 8 yum安装mariadb-10.3.17并实现三个实例
2.8.2.2 环境要求
一台系统CentOS 8.X主机
2.8.2.3 前提准备
关闭SElinux
关闭防火墙
时间同步
2.8.2.4 实现步骤
2.8.2.4.1 安装mariadb
[root@centos8 ~]#yum -y install mariadb-server
2.8.2.4.2 准备三个实例的目录
[root@centos8 ~]#mkdir -pv
/mysql/{3306,3307,3308}/{data,etc,socket,log,bin,pid}
[root@centos8 ~]#chown -R mysql.mysql /mysql
[root@centos8 ~]#tree -d /mysql/
/mysql/
├── 3306
│
│
│
│
│
│
├── bin
├── data
├── etc
├── log
├── pid
└── socket
├── 3307
│
│
│
│
│
│
├── bin
├── data
├── etc
├── log
├── pid
└── socket
└── 3308
├── bin
├── data
├── etc
├── log
├── pid
└── socket
21 directories
2.8.3.4.3 生成数据库文件
[root@centos8 ~]#mysql_install_db --user=mysql --datadir=/mysql/3306/data
[root@centos8 ~]#mysql_install_db --user=mysql --datadir=/mysql/3307/data
[root@centos8 ~]#mysql_install_db --user=mysql --datadir=/mysql/3308/data
2.8.2.4.4 准备配置文件
[root@centos8 ~]#vim /mysql/3306/etc/my.cnf
[mysqld]
port=3306
datadir=/mysql/3306/data
socket=/mysql/3306/socket/mysql.sock
log-error=/mysql/3306/log/mysql.log
pid-file=/mysql/3306/pid/mysql.pid
#重复上面步骤设置3307,3308
[root@centos8 ~]#sed 's/3306/3307/' /mysql/3306/etc/my.cnf >
/mysql/3307/etc/my.cnf
[root@centos8 ~]#sed 's/3306/3308/' /mysql/3306/etc/my.cnf >
/mysql/3308/etc/my.cnf
2.8.2.4.5 准备启动脚本
[root@centos8 ~]#vim /mysql/3306/bin/mysqld
#!/bin/bash
port=3306
mysql_user="root"
mysql_pwd="magedu"
cmd_path="/usr/bin"
mysql_basedir="/mysql"
mysql_sock="$/$/socket/mysql.sock"
function_start_mysql()
{
if [ ! -e "$mysql_sock" ];then
printf "Starting MySQL...\n"
$/mysqld_safe --defaults-
file=$/$/etc/my.cnf &> /dev/null &
else
printf "MySQL is running...\n"
exit
fi
}
function_stop_mysql()
{
if [ ! -e "$mysql_sock" ];then
printf "MySQL is stopped...\n"
exit
else
printf "Stoping MySQL...\n"
$/mysqladmin -u $ -p$ -S $
shutdown
fi
}
function_restart_mysql()
{
printf "Restarting MySQL...\n"
function_stop_mysql
sleep 2
function_start_mysql
}
case $1 in
start)
function_start_mysql
;;
stop)
function_stop_mysql
;;
restart)
function_restart_mysql
;;
*)
printf "Usage: $/$/bin/mysqld {start|stop|restart}\n"
esac
[root@centos8 ~]#chmod +x /mysql/3306/bin/mysqld
#重复上述过程,分别建立3307,3308的启动脚本
2.8.2.4.6 启动服务
[root@centos8 ~]#/mysql/3306/bin/mysqld start
[root@centos8 ~]#/mysql/3307/bin/mysqld start
[root@centos8 ~]#/mysql/3308/bin/mysqld start
[root@centos8 ~]#ss -ntl
State
Recv-Q
Send-Q
128
128
80
Local Address:Port
0.0.0.0:22
[::]:22
Peer
Address:Port
LISTEN
0.0.0.0:*
LISTEN
[::]:*
LISTEN
*:*
0
0
0
0
0
*:3306
LISTEN
*:*
80
*:3307
LISTEN
*:*
80
*:3308
2.8.2.4.7 登录实例
[root@centos8 ~]#/mysql/3308/bin/mysqld start
#两种连接方法
[root@centos8 ~]#mysql -h127.0.0.1 -P3308
[root@centos8 ~]#mysql -uroot -S /mysqldb/3306/socket/mysql.sock
#确认连接的端口
MariaDB [(none)]> show variables like 'port';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| port | 3308
|
+---------------+-------+
1 row in set (0.001 sec)
MariaDB [(none)]>
#关闭数据库,需要手动输入root的密码
[root@centos8 ~]#/mysql/3308/bin/mysqld stop
Stoping MySQL...
Enter password:
[root@centos8 ~]#/mysql/3308/bin/mysqld start
Starting MySQL...
2.8.2.4.8 修改root密码
#加上root的口令
[root@centos8 ~]#mysqladmin -uroot -S /mysql/3306/socket/mysql.sock password
'magedu'
[root@centos8 ~]#mysqladmin -uroot -S /mysql/3307/socket/mysql.sock password
'magedu'
[root@centos8 ~]#mysqladmin -uroot -S /mysql/3308/socket/mysql.sock password
'magedu'
#或者登录mysql,执行下面也可以
Mariadb>update mysql.user set password=password("centos") where user='root';
Mariadb>flush privileges;
#重复步骤,分别修改别外两个实例3307,3308对应root口令
2.8.2.4.9 测试连接
[root@centos8 ~]#mysql -uroot -p -S /mysql/3306/socket/mysql.sock #提示输入口令才
能登录
2.8.2.4.10 开机启动
[root@centos8 ~]#vi /etc/rc.d/rc.local
#在最后一行加下面内容
for i in {3306..3308};do /mysql/$i/bin/mysqld start;done
[root@centos8 ~]#chmod +x /etc/rc.d/rc.local
3 SQL 语言
3.1 关系型数据库的常见组件
数据库:database 表的集合,物理上表现为一个目录
表:table,行:row 列:column
索引:index
视图:view,虚拟的表
存储过程:procedure
存储函数:function
触发器:trigger
事件调度器:event scheduler,任务计划
用户:user
权限:privilege
3.2 SQL语言的兴起与语法标准
SQL Structured Query Language 结构化查询语言是对IBM公司San Jose,California研究实验室的埃德
加·科德的关系模型的第一个商业化语言实现,这一模型在其1970年的一篇具有影响力的论文《一个对于
大型共享型数据库的关系模型》中被描述。尽管SQL并非完全按照科德的关系模型设计,但其依然成为
最为广泛运用的数据库语言
1970年代初,由埃德加·科德发表将资料组成表格的应用原则(Codd's Relational Algebra)
1974年,同一实验室的D.D.Chamberlin和R.F. Boyce对Codd's Relational Algebra在研制关系数据库管
理系统System R中,研制出一套规范语言-SEQUEL(Structured English Query Language)
1976年11月的IBM Journal of R&D上公布新版本的SQL(叫SEQUEL/2)。1980年改名为SQL
1979年ORACLE公司首先提供商用的SQL,IBM公司在DB2和SQL/DS数据库系统中也实现了SQL
1986年10月美国国家标准学会ANSI采用SQL作为关系数据库管理系统的标准语言(ANSI X3. 135-
1986)
1987年成为国际标准化组织(ISO)采纳为国际标准
1989年美国ANSI采纳在ANSI X3.135-1989报告中定义的关系数据库管理系统的SQL标准语言,称为
ANSI SQL 89
后续SQL标准经过了一系列的增订,加入了大量新特性,有各种版本: ANSI SQL,SQL-1986, SQL-1989,
SQL-1992, SQL-1999, SQL-2003,SQL-2008, SQL-2011
目前,所有主要的关系数据库管理系统支持某些形式的SQL,大部分数据库至少遵守ANSI SQL89标准
虽然有这一标准的存在,但大部分的SQL代码在不同的数据库系统中并不具有完全的跨平台性
业内标准微软和Sybase的T-SQL,Oracle的PL/SQL
3.2.1 SQL 语言规范
在数据库系统中,SQL 语句不区分大小写,建议用大写
SQL语句可单行或多行书写,默认以 " ; " 结尾
关键词不能跨多行或简写
用空格和TAB 缩进来提高语句的可读性
子句通常位于独立行,便于编辑,提高可读性
注释:
SQL标准:
#单行注释,注意有空格
-- 注释内容
#多行注释
/*注释内容
注释内容
注释内容*/
MySQL注释:
# 注释内容
3.2.2 数据库对象和命名
数据库的组件(对象):
数据库、表、索引、视图、用户、存储过程、函数、触发器、事件调度器等
命名规则:
必须以字母开头,后续可以包括字母,数字和三个特殊字符(# _ $)
不要使用MySQL的保留字
3.2.3 SQL语句分类
DDL: Data Defination Language 数据定义语言
CREATE,DROP,ALTER
DML: Data Manipulation Language 数据操纵语言
INSERT,DELETE,UPDATE
软件开发:CRUD
DQL:Data Query Language 数据查询语言
SELECT
DCL:Data Control Language 数据控制语言
GRANT,REVOKE
TCL:Transaction Control Language 事务控制语言
COMMIT,ROLLBACK,SAVEPOINT
3.2.4 SQL语句构成
关健字Keyword组成子句clause,多条clause组成语句
示例:
SELECT *
#SELECT子句
#FROM子句
FROM products
WHERE price>666
#WHERE子句
说明:一组SQL语句由三个子句构成,SELECT,FROM和WHERE是关键字
获取SQL 命令使用帮助:
官方帮助:
https://dev.mysql.com/doc/refman/8.0/en/sql-statements.html
范例: 查看SQL帮助
MariaDB [mysql]> help contents
You asked for help about help category: "Contents"
For more information, type 'help <item>', where <item> is one of the following
categories:
Account Management
Administration
Compound Statements
Data Definition
Data Manipulation
Data Types
Functions
Functions and Modifiers for Use with GROUP BY
Geographic Features
Help Metadata
Language Structure
Plugins
Procedures
Table Maintenance
Transactions
User-Defined Functions
Utility
MySQL [(none)]> help Data Types
You asked for help about help category: "Data Types"
For more information, type 'help <item>', where <item> is one of the following
topics:
AUTO_INCREMENT
BIGINT
BINARY
BIT
BLOB
BLOB DATA TYPE
MySQL [(none)]> help bit
Name: 'BIT'
Description:
BIT[(M)]
A bit-value type. M indicates the number of bits per value, from 1 to
64. The default is 1 if M is omitted.
URL: https://dev.mysql.com/doc/refman/5.7/en/numeric-type-syntax.html
查看SQL帮助
mysql> HELP KEYWORD
3.2.5 字符集和排序
早期MySQL版本默认为 latin1,从MySQL8.0开始默认字符集已经为 utf8mb4
查看支持所有字符集:
SHOW CHARACTER SET;
SHOW CHARSET;
查看支持所有排序规则:
SHOW COLLATION;
#注意
utf8_general_ci不区分大小写
utf8_bin 区分大小写
查看当前使用的排序规则
SHOW VARIABLES LIKE 'collation%';
设置服务器默认的字符集,
vim /etc/my.cnf
[mysqld]
character-set-server=utf8mb4
设置mysql客户端默认的字符集
vim /etc/my.cnf
#针对mysql客户端
[mysql]
default-character-set=utf8mb4
#针对所有MySQL客户端
[client]
default-character-set=utf8mb4
范例:字符集和相关文件
mysql> SHOW CHARACTER SET;
+----------+---------------------------------+---------------------+--------+
| Charset | Description
| Default collation
| Maxlen |
+----------+---------------------------------+---------------------+--------+
| armscii8 | ARMSCII-8 Armenian
| armscii8_general_ci |
1 |
1 |
2 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
| ascii
| big5
| US ASCII
| ascii_general_ci
| big5_chinese_ci
| binary
|
|
|
|
|
|
|
|
|
| Big5 Traditional Chinese
| Binary pseudo charset
| Windows Central European
| Windows Cyrillic
| Windows Arabic
| binary
| cp1250
| cp1251
| cp1256
| cp1257
| cp850
| cp852
| cp1250_general_ci
| cp1251_general_ci
| cp1256_general_ci
| cp1257_general_ci
| cp850_general_ci
| cp852_general_ci
| Windows Baltic
| DOS West European
| DOS Central European
| cp866
| cp932
| dec8
| DOS Russian
| cp866_general_ci
| cp932_japanese_ci
| dec8_swedish_ci
|
|
|
1 |
2 |
1 |
3 |
2 |
4 |
2 |
2 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
2 |
1 |
1 |
2 |
3 |
4 |
4 |
4 |
3 |
4 |
| SJIS for Windows Japanese
| DEC West European
| eucjpms | UJIS for Windows Japanese
| euckr | EUC-KR Korean
| gb18030 | China National Standard GB18030 | gb18030_chinese_ci
| eucjpms_japanese_ci |
| euckr_korean_ci
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| gb2312
| gbk
| GB2312 Simplified Chinese
| GBK Simplified Chinese
| gb2312_chinese_ci
| gbk_chinese_ci
| geostd8 | GEOSTD8 Georgian
| geostd8_general_ci
| greek_general_ci
| hebrew_general_ci
| hp8_english_ci
| greek
| hebrew
| hp8
| ISO 8859-7 Greek
| ISO 8859-8 Hebrew
| HP West European
| keybcs2 | DOS Kamenicky Czech-Slovak
| keybcs2_general_ci
| koi8r_general_ci
| koi8u_general_ci
| latin1_swedish_ci
| latin2_general_ci
| latin5_turkish_ci
| latin7_general_ci
| macce_general_ci
| koi8r
| koi8u
| latin1
| latin2
| latin5
| latin7
| macce
| KOI8-R Relcom Russian
| KOI8-U Ukrainian
| cp1252 West European
| ISO 8859-2 Central European
| ISO 8859-9 Turkish
| ISO 8859-13 Baltic
| Mac Central European
| macroman | Mac West European
| macroman_general_ci |
| sjis
| swe7
| tis620
| ucs2
| ujis
| utf16
| Shift-JIS Japanese
| 7bit Swedish
| sjis_japanese_ci
| swe7_swedish_ci
| tis620_thai_ci
|
|
|
|
|
|
|
|
|
|
| TIS620 Thai
| UCS-2 Unicode
| EUC-JP Japanese
| UTF-16 Unicode
| ucs2_general_ci
| ujis_japanese_ci
| utf16_general_ci
| utf16le_general_ci
| utf32_general_ci
| utf8_general_ci
| utf8mb4_0900_ai_ci
| utf16le | UTF-16LE Unicode
| utf32
| utf8
| UTF-32 Unicode
| UTF-8 Unicode
| utf8mb4 | UTF-8 Unicode
+----------+---------------------------------+---------------------+--------+
41 rows in set (0.00 sec)
[root@centos8 ~]#ll /usr/share/mysql/charsets/
total 240
-rw-r--r-- 1 root root 5939 Jun 25 2019 armscii8.xml
-rw-r--r-- 1 root root 5925 Jun 25 2019 ascii.xml
-rw-r--r-- 1 root root 8654 Jun 25 2019 cp1250.xml
-rw-r--r-- 1 root root 8783 Jun 25 2019 cp1251.xml
-rw-r--r-- 1 root root 5982 Jun 25 2019 cp1256.xml
-rw-r--r-- 1 root root 9315 Jun 25 2019 cp1257.xml
-rw-r--r-- 1 root root 5919 Jun 25 2019 cp850.xml
-rw-r--r-- 1 root root 5941 Jun 25 2019 cp852.xml
-rw-r--r-- 1 root root 6026 Jun 25 2019 cp866.xml
-rw-r--r-- 1 root root 6942 Jun 25 2019 dec8.xml
-rw-r--r-- 1 root root 5929 Jun 25 2019 geostd8.xml
-rw-r--r-- 1 root root 6141 Jun 25 2019 greek.xml
-rw-r--r-- 1 root root 5930 Jun 25 2019 hebrew.xml
-rw-r--r-- 1 root root 5915 Jun 25 2019 hp8.xml
-rw-r--r-- 1 root root 19495 Jun 25 2019 Index.xml
-rw-r--r-- 1 root root 5942 Jun 25 2019 keybcs2.xml
-rw-r--r-- 1 root root 5923 Jun 25 2019 koi8r.xml
-rw-r--r-- 1 root root 6945 Jun 25 2019 koi8u.xml
-rw-r--r-- 1 root root 10229 Jun 25 2019 latin1.xml
-rw-r--r-- 1 root root 7651 Jun 25 2019 latin2.xml
-rw-r--r-- 1 root root 5928 Jun 25 2019 latin5.xml
-rw-r--r-- 1 root root 7851 Jun 25 2019 latin7.xml
-rw-r--r-- 1 root root 8460 Jun 25 2019 macce.xml
-rw-r--r-- 1 root root 8471 Jun 25 2019 macroman.xml
-rw-r--r-- 1 root root 1749 Jun 25 2019 README
-rw-r--r-- 1 root root 6943 Jun 25 2019 swe7.xml
查看当前字符集的使用情况
MariaDB [(none)]> show variables like 'character%';
+--------------------------+------------------------------+
| Variable_name
| Value
|
+--------------------------+------------------------------+
| character_set_client
| utf8
|
|
|
|
|
|
|
| character_set_connection | utf8
| character_set_database
| latin1
| character_set_filesystem | binary
| character_set_results
| character_set_server
| character_set_system
| character_sets_dir
| utf8
| latin1
| utf8
| /usr/share/mariadb/charsets/ |
+--------------------------+------------------------------+
8 rows in set (0.001 sec)
范例:Mariadb10.3 默认的字符集和排序规则
MariaDB [(none)]> SELECT VERSION();
+-----------------+
| VERSION()
|
+-----------------+
| 10.3.17-MariaDB |
+-----------------+
1 row in set (0.000 sec)
MariaDB [(none)]> show variables like 'character%';
+--------------------------+------------------------------+
| Variable_name
| Value
|
+--------------------------+------------------------------+
| character_set_client
| utf8
|
|
|
|
|
|
|
| character_set_connection | utf8
| character_set_database
| latin1
| character_set_filesystem | binary
| character_set_results
| character_set_server
| character_set_system
| character_sets_dir
| utf8
| latin1
| utf8
| /usr/share/mariadb/charsets/ |
+--------------------------+------------------------------+
8 rows in set (0.003 sec)
MariaDB [(none)]> SHOW VARIABLES LIKE 'collation%';
+----------------------+-------------------+
| Variable_name
+----------------------+-------------------+
| collation_connection | utf8_general_ci
| collation_database | latin1_swedish_ci |
| Value
|
|
| collation_server
| latin1_swedish_ci |
+----------------------+-------------------+
3 rows in set (0.001 sec)
范例:MySQL 8.0 默认的字符集和排序规则
mysql> SELECT VERSION();
+-----------+
| VERSION() |
+-----------+
| 8.0.17
|
+-----------+
1 row in set (0.00 sec)
mysql> show variables like 'character%';
+--------------------------+----------------------------+
| Variable_name
| Value
|
+--------------------------+----------------------------+
| character_set_client
| utf8mb4
|
|
|
|
|
|
|
| character_set_connection | utf8mb4
| character_set_database | utf8mb4
| character_set_filesystem | binary
| character_set_results
| character_set_server
| character_set_system
| character_sets_dir
| utf8mb4
| utf8mb4
| utf8
| /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.01 sec)
mysql> show variables like 'collation%';
+----------------------+--------------------+
| Variable_name
| Value
|
+----------------------+--------------------+
| collation_connection | utf8mb4_0900_ai_ci |
| collation_database | utf8mb4_0900_ai_ci |
| collation_server
| utf8mb4_0900_ai_ci |
+----------------------+--------------------+
3 rows in set (0.00 sec)
3.3 管理数据库
3.3.1 创建数据库
CREATE DATABASE|SCHEMA [IF NOT EXISTS] 'DB_NAME'
CHARACTER SET 'character set name'
COLLATE 'collate name';
范例:
MariaDB [(none)]> create database db1;
Query OK, 1 row affected (0.001 sec)
MariaDB [(none)]> show create database db1;
+----------+----------------------------------------------------------------+
| Database | Create Database
+----------+----------------------------------------------------------------+
| db1 | CREATE DATABASE `db1` /*!40100 DEFAULT CHARACTER SET latin1 */ |
|
+----------+----------------------------------------------------------------+
1 row in set (0.000 sec)
[root@centos8 ~]#cat /var/lib/mysql/db1/db.opt
default-character-set=latin1
default-collation=latin1_swedish_ci
MariaDB [(none)]> create database db1;
ERROR 1007 (HY000): Can't create database 'db1'; database exists
MariaDB [(none)]> create database IF NOT EXISTS db1;
Query OK, 0 rows affected, 1 warning (0.001 sec)
MariaDB [(none)]> show warnings;
+-------+------+----------------------------------------------+
| Level | Code | Message
|
+-------+------+----------------------------------------------+
| Note | 1007 | Can't create database 'db1'; database exists |
+-------+------+----------------------------------------------+
1 row in set (0.000 sec)
范例:指定字符集创建新数据库
MariaDB [(none)]> create database IF NOT EXISTS db2 CHARACTER SET 'utf8';
Query OK, 1 row affected (0.000 sec)
MariaDB [(none)]> SHOW CREATE DATABASE db2;
+----------+--------------------------------------------------------------+
| Database | Create Database
+----------+--------------------------------------------------------------+
| db2 | CREATE DATABASE `db2` /*!40100 DEFAULT CHARACTER SET utf8 */ |
|
+----------+--------------------------------------------------------------+
1 row in set (0.000 sec)
MariaDB [(none)]>
[root@centos8 ~]#cat /mysql/3306/data/db2/db.opt
default-character-set=utf8
default-collation=utf8_general_ci
#可以用以下简写
mysql> create database test charset=utf8;
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> show create database test;
+----------+--------------------------------------------------------------------
| Database | Create Database
|
+----------+--------------------------------------------------------------------
| test
| CREATE DATABASE `test` /*!40100 DEFAULT CHARACTER SET utf8 */
/*!80016 DEFAULT ENCRYPTION='N' */ |
+----------+--------------------------------------------------------------------
1 row in set (0.00 sec)
范例: 手动创建数据库
mysql> create database zabbix character set utf8 collate utf8_bin;
范例: 以容器方式启动并创建数据库
[root@centos8 ~]#docker run --name mysql-server -t \
-e MYSQL_DATABASE="zabbix" \
-e MYSQL_USER="zabbix" \
-e MYSQL_PASSWORD="zabbix_pwd" \
-e MYSQL_ROOT_PASSWORD="root_pwd" \
-d mysql:5.7 \
--character-set-server=utf8 --collation-server=utf8_bin
[root@centos8 ~]#docker run -d -p 3306:3306 --name mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-e MYSQL_DATABASE=jumpserver
-e MYSQL_USER=jumpserver
-e MYSQL_PASSWORD=123456
-v /data/mysql:/var/lib/mysql
-v
/etc/mysql/mysql.conf.d/mysqld.cnf:/etc/mysql/mysql.conf.d/mysqld.cnf \
-v /etc/mysql/conf.d/mysql.cnf:/etc/mysql/conf.d/mysql.cnf
mysql:5.7.30
3.3.2 修改数据库
ALTER DATABASE DB_NAME character set utf8;
范例:
MariaDB [(none)]> ALTER DATABASE db1 character set utf8 COLLATE utf8_bin;
Query OK, 1 row affected (0.001 sec)
MariaDB [(none)]> show create database db1;
+----------+--------------------------------------------------------------------
| Database | Create Database
|
+----------+--------------------------------------------------------------------
| db1
| CREATE DATABASE `db1` /*!40100 DEFAULT CHARACTER SET utf8 COLLATE
utf8_bin */ |
+----------+--------------------------------------------------------------------
1 row in set (0.000 sec)
[root@centos8 ~]#cat /var/lib/mysql/db1/db.opt
default-character-set=utf8
default-collation=utf8_general_ci
3.3.3 删除数据库
DROP DATABASE|SCHEMA [IF EXISTS] 'DB_NAME';
MariaDB [(none)]> drop database db1;
Query OK, 0 rows affected (0.002 sec)
MariaDB [(none)]> show databases;
+--------------------+
| Database
|
+--------------------+
| information_schema |
| mysql
|
| performance_schema |
+--------------------+
3 rows in set (0.000 sec)
MariaDB [(none)]>
[root@centos8 ~]#ls /var/lib/mysql/
aria_log.00000001 ib_buffer_pool ib_logfile0 ibtmp1
mysql_upgrade_info tc.log
mysql
aria_log_control ibdata1
performance_schema
ib_logfile1 multi-master.info mysql.sock
3.3.4 查看数据库列表
SHOW DATABASES;
范例:
MariaDB [(none)]> show databases;
+--------------------+
| Database
|
+--------------------+
| information_schema |
| mysql
|
| performance_schema |
+--------------------+
3 rows in set (0.000 sec)
3.4 数据类型
数据类型:
数据长什么样
数据需要多少空间来存放
数据类型
系统内置数据类型
用户定义数据类型
MySQL支持多种内置数据类型
数值类型
日期/时间类型
字符串(字符)类型
数据类型参考链接
https://dev.mysql.com/doc/refman/8.0/en/data-types.html
选择正确的数据类型对于获得高性能至关重要,三大原则:
1. 更小的通常更好,尽量使用可正确存储数据的最小数据类型
2. 简单就好,简单数据类型的操作通常需要更少的CPU周期
3. 尽量避免NULL,包含为NULL的列,对MySQL更难优化
3.4.1 整数型
tinyint(m)
1个字节 范围(-128~127)
smallint(m)
2个字节 范围(-32768~32767)
mediumint(m) 3个字节 范围(-8388608~8388607)
int(m)
4个字节 范围(-2147483648~2147483647)
8个字节 范围(+-9.22*10的18次方)
bigint(m)
上述数据类型,如果加修饰符unsigned后,则最大值翻倍
如:tinyint unsigned的取值范围为(0~255)
int(m)里的m是表示SELECT查询结果集中的显示宽度,并不影响实际的取值范围,规定了MySQL的一些
交互工具(例如MySQL命令行客户端)用来显示字符的个数。对于存储和计算来说,Int(1)和Int(20)是
相同的
BOOL,BOOLEAN:布尔型,是TINYINT(1)的同义词。zero值被视为假,非zero值视为真
3.4.2 浮点型(float和double),近似值
float(m,d) 单精度浮点型 8位精度(4字节) m总个数,d小数位, 注意: 小数点不占用总个数
double(m,d) 双精度浮点型16位精度(8字节) m总个数,d小数位, 注意: 小数点不占用总个数
设一个字段定义为float(6,3),如果插入一个数123.45678,实际数据库里存的是123.457,但总个数还以
实际为准,即6位
3.4.3 定点数
在数据库中存放的是精确值,存为十进制
格式 decimal(m,d) 表示 最多 m 位数字,其中 d 个小数,小数点不算在长度内
比如: DECIMAL(6,2) 总共能存6位数字,末尾2位是小数,字段最大值 9999.99 (小数点不算在长度内)
参数m<65 是总个数,d<30且 d<m 是小数位
MySQL5.0和更高版本将数字打包保存到一个二进制字符串中(每4个字节存9个数字)。
例如: decimal(18,9)小数点两边将各存储9个数字,一共使用9个字节:其中,小数点前的9个数字用4个
字节,小数点后的9个数字用4个字节,小数点本身占1个字节
浮点类型在存储同样范围的值时,通常比decimal使用更少的空间。float使用4个字节存储。double占用
8个字节
因为需要额外的空间和计算开销,所以应该尽量只在对小数进行精确计算时才使用decimal,例如存储
财务数据。但在数据量比较大的时候,可以考虑使用bigint代替decimal
3.4.4 字符串(char,varchar,text)
char(n)
固定长度,最多255个字符,注意不是字节
varchar(n) 可变长度,最多65535个字符
tinytext 可变长度,最多255个字符
text 可变长度,最多65535个字符
mediumtext 可变长度,最多2的24次方-1个字符
longtext 可变长度,最多2的32次方-1个字符
BINARY(M) 固定长度,可存二进制或字符,长度为0-M字节
VARBINARY(M) 可变长度,可存二进制或字符,允许长度为0-M字节
内建类型:ENUM枚举, SET集合
char和varchar的比较:
参考:https://dev.mysql.com/doc/refman/8.0/en/char.html
Value
''
CHAR(4)
' '
Storage Required
4 bytes
VARCHAR(4)
Storage Required
1 byte
''
'ab'
'ab '
4 bytes
'ab'
3 bytes
'abcd'
'abcdefgh'
'abcd'
'abcd'
4 bytes
'abcd'
'abcd'
5 bytes
4 bytes
5 bytes
1.char(n) 若存入字符数小于n,则以空格补于其后,查询之时再将空格去掉,所以char类型存储的字符
串末尾不能有空格,varchar不限于此
2.char(n) 固定长度,char(4)不管是存入几个字符,都将占用4个字节,varchar是存入的实际字符数+1
个字节(n< n>255),所以varchar(4),存入3个字符将占用4个字节
3.char类型的字符串检索速度要比varchar类型的快
varchar 和 text:
1.varchar可指定n,text不能指定,内部存储varchar是存入的实际字符数+1个字节(n< n>255),text
是实际字符数+2个字节。
2.text类型不能有默认值
3.varchar可直接创建索引,text创建索引要指定前多少个字符。varchar查询速度快于text
面试题: VARCHAR(50) 能存放几个 UTF8 编码的汉字?
存放的汉字个数与版本相关。
mysql 4.0以下版本,varchar(50) 指的是 50 字节,如果存放 UTF8 格式编码的汉字时(每个汉字3字
节),只能存放16 个。
mysql 5.0以上版本,varchar(50) 指的是 50 字符,无论存放的是数字、字母还是 UTF8 编码的汉字,
都可以存放 50 个。
3.4.5 二进制数据BLOB
BLOB和text存储方式不同,TEXT以文本方式存储,英文存储区分大小写,而Blob以二进制方式存储,
不分大小写
BLOB存储的数据只能整体读出
TEXT可以指定字符集,BLOB不用指定字符集
3.4.6 日期时间类型
date 日期 '2008-12-2'
time 时间 '12:25:36'
datetime 日期时间 '2008-12-2 22:06:44'
timestamp自动存储记录修改时间
YEAR(2), YEAR(4):年份
timestamp 此字段里的时间数据会随其他字段修改的时候自动刷新,这个数据类型的字段可以存放这
条记录最后被修改的时间
3.4.7 修饰符
适用所有类型的修饰符:
NULL
数据列可包含NULL值,默认值
NOT NULL
DEFAULT
数据列不允许包含NULL值,相当于网站注册表中的 * 为必填选项
默认值
PRIMARY KEY
UNIQUE KEY
主键,所有记录中此字段的值不能重复,且不能为NULL
唯一键,所有记录中此字段的值不能重复,但可以为NULL
CHARACTER SET name 指定一个字符集
适用数值型的修饰符:
AUTO_INCREMENT
UNSIGNED
自动递增,适用于整数类型, 必须作用于某个 key 的字段,比如primary key
无符号
范例:关于AUTO_INCREMENT
MariaDB [hellodb]> SHOW VARIABLES LIKE 'auto_inc%';
+--------------------------+-------+
| Variable_name
| Value |
+--------------------------+-------+
| auto_increment_increment | 1
| auto_increment_offset | 1
|
|
+--------------------------+-------+
2 rows in set (0.001 sec)
# auto_increment_offset
定义初始值
# auto_increment_increment 定义步进
范例:
mysql> create database test;
Query OK, 1 row affected (0.00 sec)
mysql> use test
Database changed
mysql> create table t1(id int unsigned auto_increment primary key)
auto_increment = 4294967294;
Query OK, 0 rows affected (0.01 sec)
MariaDB [db1]> show table status from db1 like "t1" \G
*************************** 1. row ***************************
Name: t1
Engine: InnoDB
Version: 10
Row_format: Dynamic
Rows: 0
Avg_row_length: 0
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: 4294967294
Create_time: 2021-01-29 16:22:00
Update_time: NULL
Check_time: NULL
Collation: latin1_swedish_ci
Checksum: NULL
Create_options:
Comment:
Max_index_length: 0
Temporary: N
1 row in set (0.000 sec)
MariaDB [db1]>
mysql> insert into t1 values(null);
Query OK, 1 row affected (0.01 sec)
mysql> select * from t1;
+------------+
| id
|
+------------+
| 4294967294 |
+------------+
1 row in set (0.00 sec)
mysql> insert into t1 values(null);
Query OK, 1 row affected (0.00 sec)
mysql> select * from t1;
+------------+
| id
|
+------------+
| 4294967294 |
| 4294967295 |
+------------+
2 rows in set (0.00 sec)
mysql> insert into t1 values(null);
ERROR 1062 (23000): Duplicate entry '4294967295' for key 'PRIMARY'
MariaDB [testdb]> insert t1 value(null);
ERROR 167 (22003): Out of range value for column 'id' at row 1
#上面表的数据类型无法存放所有数据,修改过数据类型实现
MariaDB [db1]> alter table t1 modify id bigint auto_increment ;
Query OK, 2 rows affected (0.023 sec)
Records: 2 Duplicates: 0 Warnings: 0
MariaDB [db1]> desc t1;
+-------+------------+------+-----+---------+----------------+
| Field | Type
+-------+------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| Null | Key | Default | Extra
|
+-------+------------+------+-----+---------+----------------+
1 row in set (0.001 sec)
MariaDB [db1]> insert t1 values(null);
Query OK, 1 row affected (0.001 sec)
MariaDB [db1]> select * from t1;
+------------+
| id
|
+------------+
| 4294967294 |
| 4294967295 |
| 4294967296 |
+------------+
3 rows in set (0.000 sec)
3.5 DDL 语句
表:二维关系
设计表:遵循规范
定义:字段,索引
字段:字段名,字段数据类型,修饰符
约束,索引:应该创建在经常用作查询条件的字段上
3.5.1 创建表
参考文档:
https://dev.mysql.com/doc/refman/8.0/en/create-table.html
创建表:
CREATE TABLE
获取帮助:
HELP CREATE TABLE
外键管理参考文档
https://dev.mysql.com/doc/refman/8.0/en/create-table-foreign-keys.html
创建表的方法
(1) 直接创建
CREATE TABLE [IF NOT EXISTS] 'tbl_name' (col1 type1 修饰符, col2 type2 修饰符, ...)
#字段信息
col type1
PRIMARY KEY(col1,...)
INDEX(col1, ...)
UNIQUE KEY(col1, ...)
#表选项:
ENGINE [=] engine_name
ROW_FORMAT [=] {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT}
注意:
Storage Engine是指表类型,也即在表创建时指明其使用的存储引擎
同一库中不同表可以使用不同的存储引擎
同一个库中表建议要使用同一种存储引擎类型
范例:创建表
CREATE TABLE student (
id int UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20) NOT NULL,
age tinyint UNSIGNED,
#height DECIMAL(5,2),
gender ENUM('M','F') default 'M'
)ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
#id字段以10初始值
DESC student;
+--------+---------------------+------+-----+---------+----------------+
| Field | Type
+--------+---------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(20)
| age | tinyint(3) unsigned | YES |
| gender | enum('M','F') | YES |
| Null | Key | Default | Extra
|
| NO |
| NULL
| NULL
| M
|
|
|
|
|
|
+--------+---------------------+------+-----+---------+----------------+
MariaDB [testdb]> insert student (name,age)values('xiaoming',20);
Query OK, 1 row affected (0.002 sec)
MariaDB [testdb]> select * from student;
+----+----------+------+--------+
| id | name
+----+----------+------+--------+
| 10 | xiaoming | 20 | M
| age | gender |
|
+----+----------+------+--------+
1 row in set (0.001 sec)
MariaDB [testdb]> insert student (name,age,gender)values('xiaohong',18,'f');
Query OK, 1 row affected (0.001 sec)
MariaDB [testdb]> select * from student;
+----+----------+------+--------+
| id | name
| age | gender |
+----+----------+------+--------+
| 10 | xiaoming | 20 | M
| 11 | xiaohong | 18 | F
|
|
+----+----------+------+--------+
2 rows in set (0.001 sec)
CREATE TABLE employee (id int UNSIGNED NOT NULL ,name VARCHAR(20) NOT NULL,age
tinyint UNSIGNED,PRIMARY KEY(id,name));
范例:auto_increment 属性
MariaDB [hellodb]> SHOW VARIABLES LIKE 'auto_inc%';
+--------------------------+-------+
| Variable_name
| Value |
+--------------------------+-------+
| auto_increment_increment | 1
| auto_increment_offset | 1
|
|
+--------------------------+-------+
2 rows in set (0.001 sec)
MariaDB [hellodb]> SET @@auto_increment_increment=10;
Query OK, 0 rows affected (0.001 sec)
MariaDB [hellodb]> SET @@auto_increment_offset=3;
Query OK, 0 rows affected (0.000 sec)
MariaDB [hellodb]> SHOW VARIABLES LIKE 'auto_inc%';
+--------------------------+-------+
| Variable_name
| Value |
+--------------------------+-------+
| auto_increment_increment | 10
| auto_increment_offset | 3
|
|
+--------------------------+-------+
2 rows in set (0.001 sec)
MariaDB [hellodb]> CREATE TABLE autoinc1 (col INT NOT NULL AUTO_INCREMENT
PRIMARY KEY);
Query OK, 0 rows affected (0.004 sec)
MariaDB [hellodb]> INSERT INTO autoinc1 VALUES (NULL), (NULL), (NULL), (NULL);
Query OK, 4 rows affected (0.001 sec)
Records: 4 Duplicates: 0 Warnings: 0
MariaDB [hellodb]> SELECT col FROM autoinc1;
+-----+
| col |
+-----+
| 3 |
| 13 |
| 23 |
| 33 |
+-----+
4 rows in set (0.000 sec)
范例:时间类型
MariaDB [testdb1]> create table testdate (id int auto_increment primary key,date
timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL);
MariaDB [testdb1]> insert testdate ()values()()();
MariaDB [testdb1]> select * from testdate;
+----+---------------------+
| id | date
|
+----+---------------------+
| 1 | 2020-09-23 08:41:43 |
| 2 | 2020-09-23 08:41:43 |
| 3 | 2020-09-23 08:41:43 |
+----+---------------------+
3 row in set (0.000 sec)
(2) 通过查询现存表创建;新表会被直接插入查询而来的数据
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
[table_options]
[(create_definition,...)]
[partition_options]
select_statement
范例:
MariaDB [db1]> create table user select user,host,password from mysql.user;
Query OK, 4 rows affected (0.008 sec)
Records: 4 Duplicates: 0 Warnings: 0
MariaDB [db1]> show tables;
+---------------+
| Tables_in_db1 |
+---------------+
| student
| user
|
|
+---------------+
2 rows in set (0.000 sec)
MariaDB [db1]> desc user;
+----------+----------+------+-----+---------+-------+
| Field
| Type
| Null | Key | Default | Extra |
+----------+----------+------+-----+---------+-------+
| user
| host
| char(80) | NO
| char(60) | NO
|
|
|
|
|
|
|
|
|
|
|
|
| password | char(41) | NO
+----------+----------+------+-----+---------+-------+
(3) 通过复制现存的表的表结构创建,但不复制数据
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name { LIKE old_tbl_name | (LIKE
old_tbl_name) }
范例:
MariaDB [db1]> desc student;
+--------+---------------------+------+-----+---------+----------------+
| Field | Type
| Null | Key | Default | Extra
|
+--------+---------------------+------+-----+---------+----------------+
| id
| int(10) unsigned
| varchar(20)
| NO
| NO
| PRI | NULL
| auto_increment |
| name
| age
|
|
|
| NULL
| NULL
| M
|
|
|
|
|
|
| tinyint(3) unsigned | YES
| YES
| gender | enum('M','F')
+--------+---------------------+------+-----+---------+----------------+
4 rows in set (0.001 sec)
MariaDB [db1]> create table teacher like student;
Query OK, 0 rows affected (0.006 sec)
MariaDB [db1]> desc teacher;
+--------+---------------------+------+-----+---------+----------------+
| Field | Type
| Null | Key | Default | Extra
|
+--------+---------------------+------+-----+---------+----------------+
| id
| int(10) unsigned
| varchar(20)
| NO
| NO
| PRI | NULL
| auto_increment |
| name
| age
|
|
|
| NULL
| NULL
| M
|
|
|
|
|
|
| tinyint(3) unsigned | YES
| YES
| gender | enum('M','F')
+--------+---------------------+------+-----+---------+----------------+
4 rows in set (0.001 sec)
范例: 创建外键表
mysql> create table school ( id int primary key auto_increment,name
varchar(10));
mysql> create table teacher(id int primary key auto_increment,name varchar(10),
school_id int,foreign key(school_id) references school(id));
mysql> desc school;
+-------+-------------+------+-----+---------+----------------+
| Field | Type
+-------+-------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(10) | YES | | NULL
| Null | Key | Default | Extra
|
|
|
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
mysql> desc teacher;
+-----------+-------------+------+-----+---------+----------------+
| Field
| Type
| Null | Key | Default | Extra
|
+-----------+-------------+------+-----+---------+----------------+
| id
| int
| NO | PRI | NULL
| auto_increment |
| name
| varchar(10) | YES |
| NULL
|
|
|
|
| school_id | int
| YES | MUL | NULL
+-----------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
mysql> show create table teacher;
+---------+----------------------------------------------------------------------
| Table | Create Table
-------------------------------------------------------+
| teacher | CREATE TABLE `teacher` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(10) DEFAULT NULL,
`school_id` int DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `school_id` (`school_id`),
CONSTRAINT `teacher_ibfk_1` FOREIGN KEY (`school_id`) REFERENCES `school`
(`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 |
+---------+----------------------------------------------------------------------
--------+
1 row in set (0.01 sec)
mysql> insert school values(0,'magedu'),(0,'wangedu');
mysql> select * from school;
+----+---------+
| id | name
|
+----+---------+
| 1 | magedu |
| 2 | wangedu |
+----+---------+
2 rows in set (0.00 sec)
mysql> insert teacher values(0,'xiaoming',1);
mysql> insert teacher values(0,'xiaohong',2);
Query OK, 1 row affected (0.00 sec)
mysql> select * from teacher;
+----+----------+-----------+
| id | name
| school_id |
+----+----------+-----------+
| 1 | xiaoming |
| 2 | xiaohong |
1 |
2 |
+----+----------+-----------+
2 rows in set (0.00 sec)
mysql> insert teacher values(0,'xiaobai',3);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint
fails (`hellodb`.`teacher`, CONSTRAINT `teacher_ibfk_1` FOREIGN KEY
(`school_id`) REFERENCES `school` (`id`))
范例: 生产表结构
范例: 生产表
3.5.2 表查看
查看表:
SHOW TABLES [FROM db_name]
查看表创建命令:
SHOW CREATE TABLE tbl_name
查看表结构:
DESC [db_name.]tb_name
SHOW COLUMNS FROM [db_name.]tb_name
查看表状态:
SHOW TABLE STATUS LIKE 'tbl_name'
查看支持的engine类型
SHOW ENGINES;
范例:
MariaDB [db1]> show tables;
+---------------+
| Tables_in_db1 |
+---------------+
| student
|
+---------------+
1 row in set (0.000 sec)
范例:
MariaDB [db1]> desc student;
+--------+---------------------+------+-----+---------+----------------+
| Field | Type
| Null | Key | Default | Extra
|
+--------+---------------------+------+-----+---------+----------------+
| id
| int(10) unsigned
| varchar(20)
| NO
| NO
| PRI | NULL
| auto_increment |
| name
| age
|
|
|
| NULL
| NULL
| M
|
|
|
|
|
|
| tinyint(3) unsigned | YES
| YES
| gender | enum('M','F')
+--------+---------------------+------+-----+---------+----------------+
4 rows in set (0.001 sec)
MariaDB [db1]> SHOW COLUMNS FROM student;
+--------+---------------------+------+-----+---------+----------------+
| Field | Type
| Null | Key | Default | Extra
|
+--------+---------------------+------+-----+---------+----------------+
| id
| int(10) unsigned
| varchar(20)
| NO
| NO
| PRI | NULL
| auto_increment |
| name
| age
|
|
|
| NULL
| NULL
| M
|
|
|
|
|
|
| tinyint(3) unsigned | YES
| gender | enum('M','F')
| YES
+--------+---------------------+------+-----+---------+----------------+
4 rows in set (0.001 sec)
范例:
MariaDB [db1]>show create table student;
+---------+----------------------------------------------------------------------
--------------------------------+
| Table | Create Table
|
+---------+----------------------------------------------------------------------
--------------------------------+
| student | CREATE TABLE `student` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
`age` tinyint(3) unsigned DEFAULT NULL,
`gender` enum('M','F') DEFAULT 'M',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=latin1 |
+---------+----------------------------------------------------------------------
--------------------------------+
1 row in set (0.001 sec)
范例:
MariaDB [db1]> SHOW TABLE STATUS LIKE 'student'\G
*************************** 1. row ***************************
Name: student
Engine: InnoDB
Version: 10
Row_format: Dynamic
Rows: 0
Avg_row_length: 0
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: 10
Create_time: 2020-02-17 11:35:29
Update_time: NULL
Check_time: NULL
Collation: latin1_swedish_ci
Checksum: NULL
Create_options:
Comment:
Max_index_length: 0
Temporary: N
1 row in set (0.001 sec)
查看库中所有表状态
SHOW TABLE STATUS FROM db_name
范例:
MariaDB [db1]> SHOW TABLE STATUS FROM db1\G
*************************** 1. row ***************************
Name: employee
Engine: InnoDB
Version: 10
Row_format: Dynamic
Rows: 0
Avg_row_length: 0
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: NULL
Create_time: 2020-02-17 11:43:21
Update_time: NULL
Check_time: NULL
Collation: latin1_swedish_ci
Checksum: NULL
Create_options:
Comment:
Max_index_length: 0
Temporary: N
*************************** 2. row ***************************
Name: student
Engine: InnoDB
Version: 10
Row_format: Dynamic
Rows: 0
Avg_row_length: 0
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: 10
Create_time: 2020-02-17 11:35:29
Update_time: NULL
Check_time: NULL
Collation: latin1_swedish_ci
Checksum: NULL
Create_options:
Comment:
Max_index_length: 0
Temporary: N
2 rows in set (0.001 sec)
MariaDB [db1]>
3.5.3 修改和删除表
修改表
ALTER TABLE 'tbl_name'
#字段:
#添加字段:add
ADD col1 data_type [FIRST|AFTER col_name]
#删除字段:drop
#修改字段:
alter(默认值), change(字段名), modify(字段属性)
查看修改表帮助
Help ALTER TABLE
删除表
DROP TABLE [IF EXISTS] 'tbl_name';
修改表范例
#修改表名
ALTER TABLE students RENAME s1;
#添加字段
ALTER TABLE s1 ADD phone varchar(11) AFTER name;
#修改字段类型
ALTER TABLE s1 MODIFY phone int;
#修改字段名称和类型
ALTER TABLE s1 CHANGE COLUMN phone mobile char(11);
#删除字段
ALTER TABLE s1 DROP COLUMN mobile;
#修改字符集
ALTER TABLE s1 character set utf8;
#修改数据类型和字符集
ALTER TABLE s1 change name name varchar(20) character set utf8;
#添加字段
ALTER TABLE students ADD gender ENUM('m','f');
alter table student modify is_del bool default false;
#修改字段名和类型
ALETR TABLE students CHANGE id sid int UNSIGNED NOT NULL PRIMARY KEY;
#删除字段
ALTER TABLE students DROP age;
#查看表结构
DESC students;
#新建表无主键,添加和删除主键
CREATE TABLE t1 SELECT * FROM students;
ALTER TABLE t1 add primary key (stuid);
ALTER TABLE t1 drop primary key ;
#添加外键
ALTER TABLE students add foreign key(TeacherID) references teachers(tid);
#删除外键
SHOW CREATE TABLE students #查看外键名
ALTER TABLE students drop foreign key <外键名>;
3.6 DML 语句
DML: INSERT, DELETE, UPDATE
3.6.1 INSERT 语句
功能:一次插入一行或多行数据
语法
INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name [(col_name,...)]
{VALUES | VALUE} ({expr | DEFAULT},...),(...),...
[ ON DUPLICATE KEY UPDATE #如果重复更新之
col_name=expr
[, col_name=expr] ... ]
INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
SET col_name={expr | DEFAULT}, ...
[ ON DUPLICATE KEY UPDATE
col_name=expr
[, col_name=expr] ... ]
INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name [(col_name,...)]
SELECT ...
[ ON DUPLICATE KEY UPDATE
col_name=expr
[, col_name=expr] ... ]
简化写法:
INSERT tbl_name [(col1,...)] VALUES (val1,...), (val21,...)
范例: 全值插入
mysql> insert student values(0,'wang',18,default);
Query OK, 1 row affected (0.01 sec)
mysql> select * from student;
+----+------+------+--------+
| id | name | age | gender |
+----+------+------+--------+
|
1 | wang |
18 | M
|
+----+------+------+--------+
1 row in set (0.00 sec)
范例: 部分列插入
mysql> insert student(name,age)values('zhang',20);
Query OK, 1 row affected (0.01 sec)
mysql> insert student(id,name,age)values(default,'li',19);
Query OK, 1 row affected (0.00 sec)
mysql> insert student(id,name,gender)values(null,'zhao','F');
Query OK, 1 row affected (0.00 sec)
mysql> select * from student;
+----+-------+------+--------+
| id | name | age | gender |
+----+-------+------+--------+
|
|
|
|
1 | wang
2 | zhang |
3 | li
|
18 | M
20 | M
19 | M
|
|
|
|
|
4 | zhao | NULL | F
+----+-------+------+--------+
4 rows in set (0.00 sec)
3.6.2 UPDATE 语句
语法:
UPDATE [LOW_PRIORITY] [IGNORE] table_reference
SET col_name1={expr1|DEFAULT} [, col_name2={expr2|DEFAULT}] ...
[WHERE where_condition]
[ORDER BY ...]
[LIMIT row_count]
注意:一定要有限制条件,否则将修改所有行的指定字段
可利用mysql 选项避免此错误:
mysql -U | --safe-updates| --i-am-a-dummy
[root@centos8 ~]#vim /etc/my.cnf
[mysql]
safe-updates
3.6.3 DELETE 语句
删除表中数据,但不会自动缩减数据文件的大小。
语法:
DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name
[WHERE where_condition]
[ORDER BY ...]
[LIMIT row_count]
#可先排序再指定删除的行数
注意:一定要有限制条件,否则将清空表中的所有数据
如果想清空表,保留表结构,也可以使用下面语句,此语句会自动缩减数据文件的大小。
TRUNCATE TABLE tbl_name;
缩减表大小
OPTIMIZE TABLE tb_name
范例: 删除数据可以使用逻辑删除,添加一个标识字段实现,删除数据即修改标识字段
mysql> alter table student add is_del bool default false;
#mysql> alter table student add is_del tinyint(1) default 0;
mysql> desc student;
+--------+------------------+------+-----+---------+----------------+
| Field | Type
+--------+------------------+------+-----+---------+----------------+
| id | int unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(20)
| age | tinyint unsigned | YES |
| Null | Key | Default | Extra
|
| NO |
| NULL
| NULL
| M
|
|
|
|
|
|
|
|
| gender | enum('M','F')
| is_del | tinyint(1)
| YES |
| YES |
| 0
+--------+------------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
3.7 DQL 语句
3.7.1 单表操作
语法:
SELECT
[ALL | DISTINCT | DISTINCTROW ]
[SQL_CACHE | SQL_NO_CACHE]
select_expr [, select_expr ...]
[FROM table_references
[WHERE where_condition]
[GROUP BY {col_name | expr | position}
[ASC | DESC], ... [WITH ROLLUP]]
[HAVING where_condition]
[ORDER BY {col_name | expr | position}
[ASC | DESC], ...]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
[FOR UPDATE | LOCK IN SHARE MODE]
说明:
字段显示可以使用别名:
col1 AS alias1, col2 AS alias2, ...
WHERE子句:指明过滤条件以实现"选择"的功能:
过滤条件:布尔型表达式
算术操作符:+, -, *, /, %
比较操作符:=,<=>(相等或都为空), <>, !=(非标准SQL), >, >=, <, <=
范例查询: BETWEEN min_num AND max_num
不连续的查询: IN (element1, element2, ...)
空查询: IS NULL, IS NOT NULL
DISTINCT 去除重复行,范例:SELECT DISTINCT gender FROM students;
模糊查询: LIKE 使用 % 表示任意长度的任意字符 _ 表示任意单个字符
RLIKE:正则表达式,索引失效,不建议使用
REGEXP:匹配字符串可用正则表达式书写模式,同上
逻辑操作符:NOT,AND,OR,XOR
GROUP BY:根据指定的条件把查询结果进行"分组"以用于做"聚合"运算
常见聚合函数: count(), sum(), max(), min(), avg(),注意:聚合函数不对null统计
HAVING: 对分组聚合运算后的结果指定过滤条件
一旦分组 group by ,select语句后只跟分组的字段,聚合函数
ORDER BY: 根据指定的字段对查询结果进行排序
升序:ASC
降序:DESC
LIMIT [[offset,]row_count]:对查询的结果进行输出行数数量限制,跳过offset,显示row_count
行,offset默为值为0
对查询结果中的数据请求施加"锁"
FOR UPDATE: 写锁,独占或排它锁,只有一个读和写操作
LOCK IN SHARE MODE: 读锁,共享锁,同时多个读操作
范例:
MariaDB [hellodb]> select password("hello world") ;
+-------------------------------------------+
| password("hello world")
|
+-------------------------------------------+
| *67BECF85308ACF0261750DA1075681EE5C412F05 |
+-------------------------------------------+
1 row in set (0.000 sec)
MariaDB [hellodb]> select md5("hello world") ;
+----------------------------------+
| md5("hello world")
|
+----------------------------------+
| 5eb63bbbe01eeed093cb22bb8f5acdc3 |
+----------------------------------+
1 row in set (0.000 sec)
范例:字段别名
MariaDB [hellodb]> select stuid 学员ID,name as 姓名,gender 性别 from students;
+----------+---------------+--------+
| 学员ID
| 姓名
| 性别
|
+----------+---------------+--------+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 | Shi Zhongyu
2 | Shi Potian
3 | Xie Yanke
4 | Ding Dian
5 | Yu Yutong
6 | Shi Qing
7 | Xi Ren
| M
| M
| M
| M
| M
| M
| F
| F
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 | Lin Daiyu
9 | Ren Yingying | F
10 | Yue Lingshan | F
11 | Yuan Chengzhi | M
12 | Wen Qingqing | F
13 | Tian Boguang | M
14 | Lu Wushuang
15 | Duan Yu
| F
| M
| M
| M
| M
| F
| F
16 | Xu Zhu
17 | Lin Chong
18 | Hua Rong
19 | Xue Baochai
20 | Diao Chan
21 | Huang Yueying | F
22 | Xiao Qiao
23 | Ma Chao
| F
| M
| M
| M
24 | Xu Xian
25 | Sun Dasheng
+----------+---------------+--------+
25 rows in set (0.000 sec)
范例:简单查询
DESC students;
INSERT INTO students VALUES(1,'tom','m'),(2,'alice','f');
INSERT INTO students(id,name) VALUES(3,'jack'),(4,'allen');
SELECT * FROM students WHERE id < 3;
SELECT * FROM students WHERE gender='m';
SELECT * FROM students WHERE gender IS NULL;
SELECT * FROM students WHERE gender IS NOT NULL;
SELECT * FROM students ORDER BY name DESC LIMIT 2;
SELECT * FROM students ORDER BY name DESC LIMIT 1,2;
SELECT * FROM students WHERE id >=2 and id <=4
SELECT * FROM students WHERE BETWEEN 2 AND 4
SELECT * FROM students WHERE name LIKE 't%'
SELECT * FROM students WHERE name RLIKE '.*[lo].*';
SELECT id stuid,name as stuname FROM students
select * from students where classid in (1,3,5);
select * from students where classid not in (1,3,5);
范例:判断是否为NULL
MariaDB [hellodb]> select * from students where classid is null;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name
| Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
|
|
24 | Xu Xian
|
27 | M
|
|
NULL |
NULL |
NULL |
NULL |
25 | Sun Dasheng | 100 | M
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (0.002 sec)
MariaDB [hellodb]> select * from students where classid <=> null;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name
| Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
|
|
24 | Xu Xian
|
27 | M
|
|
NULL |
NULL |
NULL |
NULL |
25 | Sun Dasheng | 100 | M
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (0.000 sec)
MariaDB [hellodb]> select * from students where classid is not null;
#ifnull函数判断指定的字段是否为空值,如果空值则使用指定默认值
mysql> select stuid,name,ifnull(classID,'无班级') from students where classid is
null;
+-------+-------------+-----------------------------+
| stuid | name
| ifnull(classID,'无班级')
|
+-------+-------------+-----------------------------+
|
|
24 | Xu Xian
| 无班级
|
|
25 | Sun Dasheng | 无班级
+-------+-------------+-----------------------------+
2 rows in set (0.00 sec)
范例: 记录去重
MariaDB [hellodb]> select distinct gender from students ;
+--------+
| gender |
+--------+
| M
| F
|
|
+--------+
2 rows in set (0.001 sec)
#将age和gender多个字段重复的记录去重
mysql> select distinct age,gender from students;
范例:SQL 注入攻击
select * from user where name='admin' and password='' or '1'='1';
select * from user where name='admin' and password='' or '1=1';
select * from user where name='admin'; -- ' and password='magedu123';
select * from user where name='admin'; # ' and password='magedu123';
范例: 分页查询
#只取前3个
mysql> select * from students limit 0,3;
mysql> select * from students limit 3;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name
| Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
|
|
|
1 | Shi Zhongyu | 22 | M
2 | Shi Potian | 22 | M
3 | Xie Yanke | 53 | M
|
|
|
2 |
1 |
2 |
3 |
7 |
16 |
+-------+-------------+-----+--------+---------+-----------+
3 rows in set (0.00 sec)
mysql> select * from students limit 1,3;
+-------+------------+-----+--------+---------+-----------+
| StuID | Name
| Age | Gender | ClassID | TeacherID |
+-------+------------+-----+--------+---------+-----------+
|
|
|
2 | Shi Potian | 22 | M
3 | Xie Yanke | 53 | M
4 | Ding Dian | 32 | M
|
|
|
1 |
2 |
4 |
7 |
16 |
4 |
+-------+------------+-----+--------+---------+-----------+
3 rows in set (0.00 sec)
# 查询第n页的数据,每页显示m条记录
mysql> select * from students limit (n-1) * m,m;
范例: 聚合函数
mysql> select sum(age)/count(*) from students where gender ='M';
+-------------------+
| sum(age)/count(*) |
+-------------------+
|
33.0000 |
+-------------------+
1 row in set (0.00 sec)
mysql> select sum(age)/count(*) from students where gender ='F';
+-------------------+
| sum(age)/count(*) |
+-------------------+
|
19.0000 |
+-------------------+
1 row in set (0.00 sec)
范例:分组统计
mysql> select classid, count(*) 数量 from students group by classid;
+---------+--------+
| classid | 数量
|
+---------+--------+
|
|
|
|
|
|
|
|
2 |
1 |
3 |
4 |
4 |
4 |
1 |
3 |
4 |
2 |
4 |
3 |
5 |
7 |
6 |
NULL |
+---------+--------+
8 rows in set (0.00 sec)
MariaDB [hellodb]> select classid,gender, count(*)
classid,gender;
数量 from students group by
+---------+--------+--------+
| classid | gender | 数量
|
+---------+--------+--------+
|
|
|
|
|
|
|
|
|
|
|
|
NULL | M
1 | F
1 | M
2 | M
3 | F
3 | M
4 | M
5 | M
6 | F
6 | M
7 | F
7 | M
|
|
|
|
|
|
|
|
|
|
|
|
2 |
2 |
2 |
3 |
3 |
1 |
4 |
1 |
3 |
1 |
2 |
1 |
+---------+--------+--------+
12 rows in set (0.001 sec)
#分组统计
select classid,avg(age) as 平均年龄 from students where classid > 3 group by
classid having 平均年龄 >30 ;
select gender,avg(age) 平均年龄 from students group by gender having gender='M';
#多个字段分组统计
select classid,gender,count(*) 数量 from students group by classid,gender;
select classid,gender,count(*) 数量 from students group by gender,classid;
范例: group_concat函数实现分组信息的集合
mysql> select gender,group_concat(name) from students group by gender;
+--------+-----------------------------------------------------------------------
+
| gender | group_concat(name)
|
+--------+-----------------------------------------------------------------------
+
| F
| Xiao Qiao,Huang Yueying,Xi Ren,Lin Daiyu,Ren Yingying,Yue
Lingshan,Diao Chan,Wen Qingqing,Xue Baochai,Lu Wushuang
|
| M
| Tian Boguang,Sun Dasheng,Xu Xian,Ma Chao,Hua Rong,Lin Chong,Xu
Zhu,Duan Yu,Shi Zhongyu,Yuan Chengzhi,Shi Qing,Yu Yutong,Ding Dian,Xie Yanke,Shi
Potian |
+--------+-----------------------------------------------------------------------
+
2 rows in set (0.00 sec)
范例: 分组统计
# with rollup 分组后聚合函数统计后再做汇总
mysql> select gender,count(*) from students group by gender with rollup;
+--------+----------+
| gender | count(*) |
+--------+----------+
| F
| M
|
|
10 |
15 |
25 |
| NULL |
+--------+----------+
3 rows in set (0.00 sec)
mysql> select gender,group_concat(name) from students group by gender with
rollup;
范例: 分组统计
#注意:一旦使用分组group by,在select 后面的只能采用分组的列和聚合函数,其它的列不能放在select
后面,否则根据系统变量SQL_MODE的值不同而不同的结果
#以下为MySQL8.0.17 的执行结果
mysql> use hellodb
mysql> select classid,count(*) 数量 from students group by classid;
+---------+--------+
| classid | 数量 |
+---------+--------+
|
2 |
3 |
|
|
|
|
|
|
|
1 |
4 |
4 |
4 |
4 |
1 |
3 |
4 |
2 |
3 |
5 |
7 |
6 |
NULL |
+---------+--------+
8 rows in set (0.00 sec)
mysql> select classid,count(*),stuid 数量 from students group by classid;
ERROR 1055 (42000): Expression #3 of SELECT list is not in GROUP BY clause and
contains nonaggregated column 'hellodb.students.StuID' which is not functionally
dependent on columns in GROUP BY clause; this is incompatible with
sql_mode=only_full_group_by
mysql> select @@sql_mode;
+--------------------------------------------------------------------------------
| @@sql_mode
|
+--------------------------------------------------------------------------------
|
ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DI
VISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+--------------------------------------------------------------------------------
1 row in set (0.00 sec)
#以下是Mariadb10.3.17的执行结果
MariaDB [hellodb]> select classid, count(*), stuid from students group by
classid;
+---------+----------+-------+
| classid | count(*) | stuid |
+---------+----------+-------+
|
|
|
|
|
|
|
|
NULL |
1 |
2 |
4 |
3 |
4 |
4 |
1 |
4 |
3 |
24 |
2 |
1 |
5 |
4 |
6 |
9 |
8 |
2 |
3 |
4 |
5 |
6 |
7 |
+---------+----------+-------+
8 rows in set (0.001 sec)
MariaDB [hellodb]> select @@sql_mode;
+--------------------------------------------------------------------------------
| @@sql_mode
|
+--------------------------------------------------------------------------------
|
STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUB
STITUTION |
+--------------------------------------------------------------------------------
1 row in set (0.000 sec)
范例: 排序
#只取前3个
mysql> select * from students order by age desc limit 3;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name
| Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
|
|
|
25 | Sun Dasheng | 100 | M
3 | Xie Yanke | 53 | M
|
|
|
NULL |
2 |
NULL |
16 |
6 | Shi Qing
| 46 | M
5 |
NULL |
+-------+-------------+-----+--------+---------+-----------+
3 rows in set (0.00 sec)
#跳过前3个只显示后续的2个
mysql> select * from students order by age desc limit 3,2;
+-------+--------------+-----+--------+---------+-----------+
| StuID | Name
| Age | Gender | ClassID | TeacherID |
+-------+--------------+-----+--------+---------+-----------+
|
|
13 | Tian Boguang | 33 | M
4 | Ding Dian | 32 | M
|
|
2 |
4 |
NULL |
4 |
+-------+--------------+-----+--------+---------+-----------+
2 rows in set (0.00 sec)
范例:排序
select classid,sum(age) from students where classid is not null group by
classid order by classid;
select classid,sum(age) from students group by classid having classid is not
null order by classid;
select classid,sum(age) from students where classid is not null group by
classid order by classid limit 2,3;
#必须先过滤,再排序
select * from students where classid is not null order by gender desc, age asc ;
#多列排序
select * from students order by gender desc, age asc;
范例:正序排序时将NULL记录排在最后
#对classid 正序排序,NULL记录排在最后
select * from students order by -classid desc ;
范例:分组和排序
mysql> select classid,count(*) 数量 from students group by classid order by 数量
;
+---------+--------+
| classid | 数量 |
+---------+--------+
|
|
|
|
|
|
|
|
5 |
NULL |
2 |
1 |
2 |
3 |
3 |
4 |
4 |
4 |
4 |
7 |
1 |
4 |
3 |
6 |
+---------+--------+
8 rows in set (0.00 sec)
#分组后再排序
MariaDB [hellodb]> select gender,classid,avg(age) from students where classid is
not null group by gender,classid order by gender,classid;
+--------+---------+----------+
| gender | classid | avg(age) |
+--------+---------+----------+
| F
| F
| F
| F
| F
| F
| M
| M
| M
| M
| M
| M
| M
| M
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 | 19.0000 |
3 | 18.3333 |
6 | 20.0000 |
7 | 18.0000 |
77 | 18.0000 |
93 | 18.0000 |
1 | 21.5000 |
2 | 35.2000 |
3 | 23.0000 |
4 | 23.6000 |
5 | 46.0000 |
6 | 23.0000 |
7 | 23.0000 |
94 | 18.0000 |
+--------+---------+----------+
14 rows in set (0.001 sec)
MariaDB [hellodb]> select * from students order by age limit 10;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name
| Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
|
|
|
|
|
|
|
|
|
|
14 | Lu Wushuang
8 | Lin Daiyu
|
|
17 | F
17 | F
|
|
|
|
|
|
|
|
|
|
3 |
7 |
NULL |
NULL |
NULL |
NULL |
NULL |
NULL |
NULL |
NULL |
NULL |
NULL |
33 | Miejue Shitai | 18 | F
32 | Zhang Sanfeng | 18 | M
77 |
94 |
1 |
27 | liudehua
|
|
|
|
|
|
18 | F
18 | F
18 | F
19 | F
19 | F
19 | F
34 | Lin Chaoying
19 | Xue Baochai
7 | Xi Ren
93 |
6 |
3 |
12 | Wen Qingqing
20 | Diao Chan
1 |
7 |
+-------+---------------+-----+--------+---------+-----------+
10 rows in set (0.001 sec)
MariaDB [hellodb]> select * from students order by age limit 3,10;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name
| Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
|
|
|
|
|
|
|
|
|
|
34 | Lin Chaoying | 18 | F
19 | Xue Baochai | 18 | F
32 | Zhang Sanfeng | 18 | M
|
|
|
|
|
|
|
|
|
|
93 |
6 |
94 |
1 |
7 |
1 |
3 |
4 |
3 |
4 |
NULL |
NULL |
NULL |
NULL |
NULL |
NULL |
NULL |
NULL |
NULL |
NULL |
27 | liudehua
20 | Diao Chan
| 18 | F
| 19 | F
12 | Wen Qingqing | 19 | F
10 | Yue Lingshan | 19 | F
15 | Duan Yu
7 | Xi Ren
| 19 | M
| 19 | F
| 19 | M
29 | wuyanzu
+-------+---------------+-----+--------+---------+-----------+
10 rows in set (0.000 sec)
MariaDB [hellodb]> select distinct age from students order by age limit 3 ;
+-----+
| age |
+-----+
| 17 |
| 18 |
| 19 |
+-----+
3 rows in set (0.001 sec)
MariaDB [hellodb]> select distinct age from students order by age limit 3,5 ;
+-----+
| age |
+-----+
| 20 |
| 21 |
| 22 |
| 23 |
| 25 |
+-----+
5 rows in set (0.001 sec)
范例: 分组和排序的次序
#顺序: group by,having,order by
mysql> select classid,count(*) from students group by classid having classid is
not null order by classid;
+---------+----------+
| classid | count(*) |
+---------+----------+
|
|
|
|
|
|
|
1 |
2 |
3 |
4 |
5 |
6 |
7 |
4 |
3 |
4 |
4 |
1 |
4 |
3 |
+---------+----------+
7 rows in set (0.00 sec)
#以下顺序会出错,group by,order by,having
mysql> select classid,count(*) from students group by classid order by classid
having classid is not null;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use near
'having classid is not null' at line 1
#以下顺序会出错,order by,group by,having
mysql> select classid,count(*) from students order by classid group by classid
having classid is not null;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use near 'group
by classid having classid is not null' at line 1
范例:时间字段进行过滤查询,并且timestamp可以随其它字段的更新自动更新
MariaDB [testdb]> create table testdate (id int auto_increment primary key,date
timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP);
MariaDB [testdb]> insert testdate () values();
MariaDB [testdb]> insert testdate values(),(),();
MariaDB [testdb]> select * from testdate;
+----+---------------------+
| id | date
|
+----+---------------------+
| 1 | 2020-06-03 15:21:03 |
| 2 | 2020-06-03 15:21:12 |
| 3 | 2020-06-03 15:21:14 |
| 4 | 2020-06-03 15:21:17 |
| 5 | 2020-06-03 18:27:39 |
| 6 | 2020-06-03 18:27:44 |
+----+---------------------+
6 rows in set (0.001 sec)
MariaDB [testdb]> select * from testdate where date between '2020-06-03
15:21:12' and '2020-06-03 18:27:40';
+----+---------------------+
| id | date
|
+----+---------------------+
| 2 | 2020-06-03 15:21:12 |
| 3 | 2020-06-03 15:21:14 |
| 4 | 2020-06-03 15:21:17 |
| 5 | 2020-06-03 18:27:39 |
+----+---------------------+
4 rows in set (0.000 sec)
MariaDB [testdb]> select * from testdate where date >= '2020-06-03 15:21:12'
and date <= '2020-06-03 18:27:40';
+----+---------------------+
| id | date
|
+----+---------------------+
| 2 | 2020-06-03 15:21:12 |
| 3 | 2020-06-03 15:21:14 |
| 4 | 2020-06-03 15:21:17 |
| 5 | 2020-06-03 18:27:39 |
+----+---------------------+
4 rows in set (0.001 sec)
#修改其它字段,会自动更新timestamp字段
mysql> update testdate set id=10 where id=1;
mysql> select * from testdate3;
+----+---------------------+
| id | date
|
+----+---------------------+
| 2 | 2020-06-03 15:21:12 |
| 3 | 2020-06-03 15:21:14 |
| 4 | 2020-06-03 15:21:17 |
| 5 | 2020-06-03 18:27:39 |
| 6 | 2020-06-03 18:27:44 |
| 10 | 2020-06-03 18:34:51 |
+----+---------------------+
6 rows in set (0.001 sec)
3.7.2 多表查询
多表查询,即查询结果来自于多张表
子查询:在SQL语句嵌套着查询语句,性能较差,基于某语句的查询结果再次进行的查询
联合查询:UNION
交叉连接:笛卡尔乘积 CROSS JOIN
内连接:
等值连接:让表之间的字段以"等值"建立连接关系
不等值连接
自然连接:去掉重复列的等值连接 , 语法: FROM table1 NATURAL JOIN table2;
外连接:
左外连接:FROM tb1 LEFT JOIN tb2 ON tb1.col=tb2.col
右外连接:FROM tb1 RIGHT JOIN tb2 ON tb1.col=tb2.col
完全外连接: FROM tb1 FULL OUTER JOIN tb2 ON tb1.col=tb2.col
注意:MySQL 不支持此SQL
语法
自连接:本表和本表进行连接查询
3.7.2.1 子查询
子查询 subquery 即SQL语句调用另一个SELECT子句,可以是对同一张表,也可以是对不同表,主要有以下
四种常见的用法.
1. 用于比较表达式中的子查询;子查询仅能返回单个值
SELECT Name,Age FROM students WHERE Age>(SELECT avg(Age) FROM teachers);
update students set Age=(SELECT avg(Age) FROM teachers) where stuid=25;
2. 用于IN中的子查询:子查询应该单独查询并返回一个或多个值重新构成列表
SELECT Name,Age FROM students WHERE Age IN (SELECT Age FROM teachers);
3. 用于EXISTS 和 Not EXISTS
参考链接:https://dev.mysql.com/doc/refman/8.0/en/exists-and-not-exists-subqueries.html
EXISTS(包括 NOT EXISTS )子句的返回值是一个BOOL值。 EXISTS 内部有一个子查询语句(SELECT
... FROM...), 将其称为EXIST的内查询语句。其内查询语句返回一个结果集。 EXISTS子句根据其内
查询语句的结果集空或者非空,返回一个布尔值。将外查询表的每一行,代入内查询作为检验,如
果内查询返回的结果为非空值,则EXISTS子句返回TRUE,外查询的这一行数据便可作为外查询的
结果行返回,否则不能作为结果
MariaDB [hellodb]> select * from students s where EXISTS (select * from
teachers t where s.teacherid=t.tid);
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name
| Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
|
|
|
1 | Shi Zhongyu | 22 | M
4 | Ding Dian | 32 | M
5 | Yu Yutong | 26 | M
|
|
|
2 |
4 |
3 |
3 |
4 |
1 |
+-------+-------------+-----+--------+---------+-----------+
#说明:
1、EXISTS (或 NOT EXISTS) 用在 where之后,且后面紧跟子查询语句(带括号)
2、EXISTS (或 NOT EXISTS) 只关心子查询有没有结果,并不关心子查询的结果具体是什么
3、上述语句把students的记录逐条代入到Exists后面的子查询中,如果子查询结果集不为空,即说明
存在,那么这条students的记录出现在最终结果集,否则被排除
MariaDB [hellodb]> select * from students s where NOT EXISTS (select * from
teachers t where s.teacherid=t.tid);
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name
| Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
|
|
|
|
|
|
2 | Shi Potian
3 | Xie Yanke
6 | Shi Qing
7 | Xi Ren
| 22 | M
| 53 | M
| 46 | M
| 19 | F
| 17 | F
|
|
|
|
|
|
1 |
2 |
5 |
3 |
7 |
6 |
7 |
16 |
NULL |
NULL |
NULL |
NULL |
8 | Lin Daiyu
9 | Ren Yingying | 20 | F
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 | Yue Lingshan | 19 | F
11 | Yuan Chengzhi | 23 | M
12 | Wen Qingqing | 19 | F
13 | Tian Boguang | 33 | M
14 | Lu Wushuang | 17 | F
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
6 |
NULL |
NULL |
NULL |
NULL |
NULL |
NULL |
NULL |
NULL |
NULL |
NULL |
NULL |
NULL |
NULL |
NULL |
NULL |
NULL |
1 |
2 |
3 |
15 | Duan Yu
16 | Xu Zhu
| 19 | M
| 21 | M
| 25 | M
| 23 | M
4 |
1 |
17 | Lin Chong
18 | Hua Rong
4 |
7 |
19 | Xue Baochai | 18 | F
20 | Diao Chan | 19 | F
21 | Huang Yueying | 22 | F
6 |
7 |
6 |
22 | Xiao Qiao
23 | Ma Chao
24 | Xu Xian
| 20 | F
| 23 | M
| 27 | M
1 |
4 |
NULL |
NULL |
25 | Sun Dasheng | 100 | M
+-------+---------------+-----+--------+---------+-----------+
22 rows in set (0.001 sec)
4. 用于FROM子句中的子查询
使用格式:
SELECT tb_alias.col1,... FROM (SELECT clause) AS tb_alias WHERE Clause;
范例:
SELECT s.ClassID,s.aage FROM (SELECT ClassID,avg(Age) AS aage FROM students
WHERE ClassID IS NOT NULL GROUP BY ClassID) AS s WHERE s.aage>30;
范例:子查询
#子查询:select 的执行结果,被其它SQL调用
MariaDB [hellodb]> select stuid,name,age from students where age > (select
avg(age) from students);
+-------+--------------+-----+
| stuid | name
| age |
+-------+--------------+-----+
|
|
|
|
|
3 | Xie Yanke
4 | Ding Dian
6 | Shi Qing
| 53 |
| 32 |
| 46 |
13 | Tian Boguang | 33 |
25 | Sun Dasheng | 100 |
+-------+--------------+-----+
5 rows in set (0.00 sec)
范例:子查询用于更新表
MariaDB [hellodb]> update teachers set age=(select avg(age) from students) where
tid=4;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MariaDB [hellodb]> select * from teachers;
+-----+---------------+-----+--------+
| TID | Name
| Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang
| 45 | M
|
|
|
|
| 2 | Zhang Sanfeng | 94 | M
| 3 | Miejue Shitai | 77 | F
| 4 | Lin Chaoying | 27 | F
+-----+---------------+-----+--------+
4 rows in set (0.00 sec)
子查询优化
子查询可以一次性完成很多逻辑上需要多个步骤才能完成的SQL操作。子查询虽然可以使查询语句很灵活,但
执行效率不高。执行子查询时,需要为内层查询语句的查询结果建立一个临时表。然后外层查询语句从临时表
中查询记录。查询完毕后,再撤销这些临时表。因此,子查询的速度会受到一定的影响。如果查询的数据量比
较大,这种影响就会随之增大。
可以使用连接(JOIN)查询来替代子查询。连接查询不需要建立临时表,其速度比子查询要快,如果查询中使用
到索引的话,性能会更好。
3.7.2.2 联合查询
联合查询 Union 实现的条件,多个表的字段数量相同,字段名和数据类型可以不同,但一般数据类型是相同
的.
SELECT Name,Age FROM students UNION SELECT Name,Age FROM teachers;
范例:联合查询
#多表纵向合并union
MariaDB [hellodb]> select * from teachers union select * from students;
MariaDB [hellodb]> select tid as id,name,age,gender from teachers union select
stuid,name,age,gender from students;
+----+---------------+-----+--------+
| id | name
+----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M
| age | gender |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 | Zhang Sanfeng | 94 | M
| 3 | Miejue Shitai | 77 | F
| 4 | Lin Chaoying | 26 | F
| 1 | Shi Zhongyu | 22 | M
| 2 | Shi Potian
| 3 | Xie Yanke
| 4 | Ding Dian
| 5 | Yu Yutong
| 6 | Shi Qing
| 7 | Xi Ren
| 22 | M
| 53 | M
| 32 | M
| 26 | M
| 46 | M
| 19 | F
| 17 | F
| 8 | Lin Daiyu
| 9 | Ren Yingying | 20 | F
| 10 | Yue Lingshan | 19 | F
| 11 | Yuan Chengzhi | 23 | M
| 12 | Wen Qingqing | 19 | F
| 13 | Tian Boguang | 33 | M
| 14 | Lu Wushuang | 17 | F
| 15 | Duan Yu
| 16 | Xu Zhu
| 19 | M
| 21 | M
| 25 | M
| 23 | M
| 17 | Lin Chong
| 18 | Hua Rong
| 19 | Xue Baochai | 18 | F
| 20 | Diao Chan
|
19 | F
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 | Huang Yueying | 22 | F
| 22 | Xiao Qiao
| 23 | Ma Chao
|
|
|
20 | F
23 | M
27 | M
| 24 | Xu Xian
| 25 | Sun Dasheng
| 26 | xietingfeng
| 27 | liudehua
| 28 | mahuateng
| 29 | wuyanzu
| 100 | M
|
|
|
|
|
|
23 | M
18 | F
20 | M
19 | M
21 | M
45 | M
| 30 | wuxin
| 31 | Song Jiang
| 32 | Zhang Sanfeng | 18 | M
| 33 | Miejue Shitai | 18 | F
| 34 | Lin Chaoying
| 35 | 巴西可
|
18 | F
20 | M
20 | M
|
|
| 36 | abc
|
|
+----+---------------+-----+--------+
40 rows in set (0.001 sec)
MariaDB [hellodb]> select * from teachers union select * from teachers;
+-----+---------------+-----+--------+
| TID | Name
| Age | Gender |
+-----+---------------+-----+--------+
|
|
|
|
1 | Song Jiang
|
45 | M
|
|
|
|
2 | Zhang Sanfeng | 94 | M
3 | Miejue Shitai | 77 | F
4 | Lin Chaoying
|
93 | F
+-----+---------------+-----+--------+
4 rows in set (0.00 sec)
MariaDB [hellodb]> select * from teachers union all select *from teachers;
+-----+---------------+-----+--------+
| TID | Name
| Age | Gender |
+-----+---------------+-----+--------+
|
|
|
|
|
|
|
|
1 | Song Jiang
|
45 | M
|
|
|
|
|
|
|
|
2 | Zhang Sanfeng | 94 | M
3 | Miejue Shitai | 77 | F
4 | Lin Chaoying
1 | Song Jiang
|
|
93 | F
45 | M
2 | Zhang Sanfeng | 94 | M
3 | Miejue Shitai | 77 | F
4 | Lin Chaoying
|
93 | F
MariaDB [hellodb]> select * from user union select * from user;
+------+----------+----------+
| id
| username | password |
+------+----------+----------+
|
|
|
1 | admin
2 | mage
3 | wang
| magedu
| magedu
| centos
|
|
|
+------+----------+----------+
3 rows in set (0.00 sec)
MariaDB [hellodb]> select distinct * from user ;
+------+----------+----------+
| id
| username | password |
+------+----------+----------+
|
|
|
1 | admin
2 | mage
3 | wang
| magedu |
| magedu |
| centos |
+------+----------+----------+
3 rows in set (0.00 sec)
范例: 去重记录
mysql> select * from emp;
+-----+---------------+-----+--------+
| TID | Name
| Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang
| 45 | M
|
|
|
|
|
| 2 | Zhang Sanfeng | 94 | M
| 3 | mage
| 4 | li
| 20 | M
| 22 | F
| 20 | M
| 3 | mage
+-----+---------------+-----+--------+
5 rows in set (0.00 sec)
mysql> select distinct * from emp;
+-----+---------------+-----+--------+
| TID | Name
| Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang
| 45 | M
|
|
|
|
| 2 | Zhang Sanfeng | 94 | M
| 3 | mage
| 4 | li
| 20 | M
| 22 | F
+-----+---------------+-----+--------+
4 rows in set (0.00 sec)
mysql> select * from emp union select * from emp;
+-----+---------------+-----+--------+
| TID | Name
| Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang
| 45 | M
|
|
|
|
| 2 | Zhang Sanfeng | 94 | M
| 3 | mage
| 4 | li
| 20 | M
| 22 | F
+-----+---------------+-----+--------+
4 rows in set (0.00 sec)
#union all 不去重
mysql> select * from emp union all select * from emp;
+-----+---------------+-----+--------+
| TID | Name
| Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang
| 45 | M
|
|
|
|
|
|
|
|
|
| 2 | Zhang Sanfeng | 94 | M
| 3 | mage
| 4 | li
| 20 | M
| 22 | F
| 20 | M
| 45 | M
| 3 | mage
| 1 | Song Jiang
| 2 | Zhang Sanfeng | 94 | M
| 3 | mage
| 4 | li
| 20 | M
| 22 | F
| 3 | mage
| 20 | M
|
+-----+---------------+-----+--------+
10 rows in set (0.00 sec)
3.7.2.3 交叉连接
cross join 即多表的记录之间做笛卡尔乘积组合,并且多个表的列横向合并相加, "雨露均沾"
比如: 第一个表3行4列,第二个表5行6列,cross join后的结果为3*5=15行,4+6=10列
交叉连接生成的记录可能会非常多,建议慎用
范例:交叉连接
#横向合并,交叉连接(横向笛卡尔)
MariaDB [hellodb]> select * from students cross join teachers;
MariaDB [hellodb]> select * from teachers , students;
+-----+---------------+-----+--------+-------+---------------+-----+--------+----
-----+-----------+
| TID | Name
| Age | Gender | StuID | Name
| Age | Gender |
ClassID | TeacherID |
+-----+---------------+-----+--------+-------+---------------+-----+--------+----
-----+-----------+
| 1 | Song Jiang
2 | 3 |
| 2 | Zhang Sanfeng | 94 | M
2 | 3 |
| 3 | Miejue Shitai | 77 | F
2 | 3 |
| 4 | Lin Chaoying | 26 | F
2 | 3 |
| 1 | Song Jiang
1 | 7 |
| 2 | Zhang Sanfeng | 94 | M
1 | 7 |
| 3 | Miejue Shitai | 77 | F
1 | 7 |
| 4 | Lin Chaoying | 26 | F
1 | 7 |
| 1 | Song Jiang
2 | 16 |
| 2 | Zhang Sanfeng | 94 | M
2 | 16 |
| 3 | Miejue Shitai | 77 | F
2 | 16 |
| 4 | Lin Chaoying | 26 | F
2 | 16 |
| 1 | Song Jiang
4 | 4 |
| 2 | Zhang Sanfeng | 94 | M
4 | 4 |
| 3 | Miejue Shitai | 77 | F
4 | 4 |
| 4 | Lin Chaoying | 26 | F
4 | 4 |
| 45 | M
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 | Shi Zhongyu | 22 | M
1 | Shi Zhongyu | 22 | M
1 | Shi Zhongyu | 22 | M
1 | Shi Zhongyu | 22 | M
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 | M
2 | Shi Potian
2 | Shi Potian
2 | Shi Potian
2 | Shi Potian
3 | Xie Yanke
3 | Xie Yanke
3 | Xie Yanke
3 | Xie Yanke
4 | Ding Dian
4 | Ding Dian
4 | Ding Dian
4 | Ding Dian
| 22 | M
| 22 | M
| 22 | M
| 22 | M
| 53 | M
| 53 | M
| 53 | M
| 53 | M
| 32 | M
| 32 | M
| 32 | M
| 32 | M
| 45 | M
| 45 | M
| 1 | Song Jiang
3 | 1 |
| 2 | Zhang Sanfeng | 94 | M
3 | 1 |
| 3 | Miejue Shitai | 77 | F
3 | 1 |
| 4 | Lin Chaoying | 26 | F
3 | 1 |
| 1 | Song Jiang
5 | NULL |
| 2 | Zhang Sanfeng | 94 | M
5 | NULL |
| 3 | Miejue Shitai | 77 | F
5 | NULL |
| 4 | Lin Chaoying | 26 | F
5 | NULL |
| 1 | Song Jiang
3 | NULL |
| 2 | Zhang Sanfeng | 94 | M
3 | NULL |
| 3 | Miejue Shitai | 77 | F
3 | NULL |
| 4 | Lin Chaoying | 26 | F
3 | NULL |
| 1 | Song Jiang
7 | NULL |
| 2 | Zhang Sanfeng | 94 | M
7 | NULL |
| 3 | Miejue Shitai | 77 | F
7 | NULL |
| 4 | Lin Chaoying | 26 | F
7 | NULL |
| 1 | Song Jiang
6 | NULL |
| 2 | Zhang Sanfeng | 94 | M
6 | NULL |
| 3 | Miejue Shitai | 77 | F
6 | NULL |
| 4 | Lin Chaoying | 26 | F
6 | NULL |
| 1 | Song Jiang
3 | NULL |
| 2 | Zhang Sanfeng | 94 | M
3 | NULL |
| 3 | Miejue Shitai | 77 | F
3 | NULL |
| 4 | Lin Chaoying | 26 | F
3 | NULL |
| 1 | Song Jiang
6 | NULL |
| 2 | Zhang Sanfeng | 94 | M
6 | NULL |
| 3 | Miejue Shitai | 77 | F
6 | NULL |
| 4 | Lin Chaoying | 26 | F
6 | NULL |
| 1 | Song Jiang
1 | NULL |
| 45 | M
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 | Yu Yutong
5 | Yu Yutong
5 | Yu Yutong
5 | Yu Yutong
6 | Shi Qing
6 | Shi Qing
6 | Shi Qing
6 | Shi Qing
7 | Xi Ren
| 26 | M
| 26 | M
| 26 | M
| 26 | M
| 46 | M
| 46 | M
| 46 | M
| 46 | M
| 19 | F
| 19 | F
| 19 | F
| 19 | F
| 17 | F
| 17 | F
| 17 | F
| 17 | F
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 | M
| 45 | M
7 | Xi Ren
7 | Xi Ren
7 | Xi Ren
| 45 | M
8 | Lin Daiyu
8 | Lin Daiyu
8 | Lin Daiyu
8 | Lin Daiyu
| 45 | M
9 | Ren Yingying | 20 | F
9 | Ren Yingying | 20 | F
9 | Ren Yingying | 20 | F
9 | Ren Yingying | 20 | F
10 | Yue Lingshan | 19 | F
10 | Yue Lingshan | 19 | F
10 | Yue Lingshan | 19 | F
10 | Yue Lingshan | 19 | F
11 | Yuan Chengzhi | 23 | M
11 | Yuan Chengzhi | 23 | M
11 | Yuan Chengzhi | 23 | M
11 | Yuan Chengzhi | 23 | M
12 | Wen Qingqing | 19 | F
| 45 | M
| 45 | M
| 45 | M
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 | Zhang Sanfeng | 94 | M
1 | NULL |
3 | Miejue Shitai | 77 | F
1 | NULL |
4 | Lin Chaoying
1 | NULL |
1 | Song Jiang
2 | NULL |
2 | Zhang Sanfeng | 94 | M
2 | NULL |
3 | Miejue Shitai | 77 | F
2 | NULL |
4 | Lin Chaoying
2 | NULL |
1 | Song Jiang
3 | NULL |
2 | Zhang Sanfeng | 94 | M
3 | NULL |
3 | Miejue Shitai | 77 | F
3 | NULL |
4 | Lin Chaoying
3 | NULL |
1 | Song Jiang
4 | NULL |
2 | Zhang Sanfeng | 94 | M
4 | NULL |
3 | Miejue Shitai | 77 | F
4 | NULL |
4 | Lin Chaoying
4 | NULL |
1 | Song Jiang
1 | NULL |
2 | Zhang Sanfeng | 94 | M
1 | NULL |
3 | Miejue Shitai | 77 | F
1 | NULL |
4 | Lin Chaoying
1 | NULL |
1 | Song Jiang
4 | NULL |
2 | Zhang Sanfeng | 94 | M
4 | NULL |
3 | Miejue Shitai | 77 | F
4 | NULL |
4 | Lin Chaoying
4 | NULL |
1 | Song Jiang
7 | NULL |
2 | Zhang Sanfeng | 94 | M
7 | NULL |
3 | Miejue Shitai | 77 | F
7 | NULL |
4 | Lin Chaoying
7 | NULL |
1 | Song Jiang
6 | NULL |
2 | Zhang Sanfeng | 94 | M
6 | NULL |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 | Wen Qingqing
12 | Wen Qingqing
12 | Wen Qingqing
13 | Tian Boguang
13 | Tian Boguang
13 | Tian Boguang
13 | Tian Boguang
14 | Lu Wushuang
14 | Lu Wushuang
14 | Lu Wushuang
14 | Lu Wushuang
15 | Duan Yu
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 | F
19 | F
19 | F
33 | M
33 | M
33 | M
33 | M
17 | F
17 | F
17 | F
17 | F
19 | M
19 | M
19 | M
19 | M
21 | M
21 | M
21 | M
21 | M
25 | M
25 | M
25 | M
25 | M
23 | M
23 | M
23 | M
23 | M
18 | F
18 | F
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 | F
45 | M
|
|
26 | F
45 | M
|
|
26 | F
45 | M
15 | Duan Yu
15 | Duan Yu
|
|
26 | F
45 | M
15 | Duan Yu
16 | Xu Zhu
16 | Xu Zhu
16 | Xu Zhu
|
|
26 | F
45 | M
16 | Xu Zhu
17 | Lin Chong
17 | Lin Chong
17 | Lin Chong
17 | Lin Chong
18 | Hua Rong
|
|
26 | F
45 | M
18 | Hua Rong
18 | Hua Rong
|
|
26 | F
45 | M
18 | Hua Rong
19 | Xue Baochai
19 | Xue Baochai
| 3 | Miejue Shitai | 77 | F
6 | NULL |
| 4 | Lin Chaoying | 26 | F
6 | NULL |
| 1 | Song Jiang
7 | NULL |
| 2 | Zhang Sanfeng | 94 | M
7 | NULL |
| 3 | Miejue Shitai | 77 | F
7 | NULL |
| 4 | Lin Chaoying | 26 | F
7 | NULL |
| 1 | Song Jiang
6 | NULL |
| 2 | Zhang Sanfeng | 94 | M
6 | NULL |
| 3 | Miejue Shitai | 77 | F
6 | NULL |
| 4 | Lin Chaoying | 26 | F
6 | NULL |
| 1 | Song Jiang
1 | NULL |
| 2 | Zhang Sanfeng | 94 | M
1 | NULL |
| 3 | Miejue Shitai | 77 | F
1 | NULL |
| 4 | Lin Chaoying | 26 | F
1 | NULL |
| 1 | Song Jiang
4 | NULL |
| 2 | Zhang Sanfeng | 94 | M
4 | NULL |
| 3 | Miejue Shitai | 77 | F
4 | NULL |
| 4 | Lin Chaoying | 26 | F
4 | NULL |
| 1 | Song Jiang
NULL | NULL |
| 2 | Zhang Sanfeng | 94 | M
NULL | NULL |
| 3 | Miejue Shitai | 77 | F
NULL | NULL |
| 4 | Lin Chaoying | 26 | F
NULL | NULL |
| 1 | Song Jiang
NULL | NULL |
| 2 | Zhang Sanfeng | 94 | M
NULL | NULL |
| 3 | Miejue Shitai | 77 | F
NULL | NULL |
| 4 | Lin Chaoying | 26 | F
NULL | NULL |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 | Xue Baochai | 18 | F
19 | Xue Baochai | 18 | F
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 | M
20 | Diao Chan
20 | Diao Chan
20 | Diao Chan
20 | Diao Chan
| 19 | F
| 19 | F
| 19 | F
| 19 | F
| 45 | M
21 | Huang Yueying | 22 | F
21 | Huang Yueying | 22 | F
21 | Huang Yueying | 22 | F
21 | Huang Yueying | 22 | F
| 45 | M
22 | Xiao Qiao
22 | Xiao Qiao
22 | Xiao Qiao
22 | Xiao Qiao
23 | Ma Chao
23 | Ma Chao
23 | Ma Chao
23 | Ma Chao
24 | Xu Xian
24 | Xu Xian
24 | Xu Xian
24 | Xu Xian
| 20 | F
| 20 | F
| 20 | F
| 20 | F
| 23 | M
| 23 | M
| 23 | M
| 23 | M
| 27 | M
| 27 | M
| 27 | M
| 27 | M
| 45 | M
| 45 | M
| 45 | M
25 | Sun Dasheng | 100 | M
25 | Sun Dasheng | 100 | M
25 | Sun Dasheng | 100 | M
25 | Sun Dasheng | 100 | M
+-----+---------------+-----+--------+-------+---------------+-----+--------+----
-----+-----------+
100 rows in set (0.001 sec)
MariaDB [hellodb]> select stuid,students.name
student_name,students.age,tid,teachers.name teacher_name,teachers.age from
teachers cross join students ;
+-------+---------------+-----+-----+---------------+-----+
| stuid | student_name | age | tid | teacher_name | age |
+-------+---------------+-----+-----+---------------+-----+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 | Shi Zhongyu | 22 | 1 | Song Jiang
| 45 |
1 | Shi Zhongyu | 22 | 2 | Zhang Sanfeng | 94 |
1 | Shi Zhongyu | 22 | 3 | Miejue Shitai | 77 |
1 | Shi Zhongyu | 22 | 4 | Lin Chaoying | 26 |
2 | Shi Potian
2 | Shi Potian
2 | Shi Potian
2 | Shi Potian
3 | Xie Yanke
3 | Xie Yanke
3 | Xie Yanke
3 | Xie Yanke
4 | Ding Dian
4 | Ding Dian
4 | Ding Dian
4 | Ding Dian
5 | Yu Yutong
5 | Yu Yutong
5 | Yu Yutong
5 | Yu Yutong
6 | Shi Qing
6 | Shi Qing
6 | Shi Qing
6 | Shi Qing
7 | Xi Ren
| 22 | 1 | Song Jiang
| 45 |
| 22 | 2 | Zhang Sanfeng | 94 |
| 22 | 3 | Miejue Shitai | 77 |
| 22 | 4 | Lin Chaoying | 26 |
| 53 | 1 | Song Jiang
| 45 |
| 53 | 2 | Zhang Sanfeng | 94 |
| 53 | 3 | Miejue Shitai | 77 |
| 53 | 4 | Lin Chaoying | 26 |
| 32 | 1 | Song Jiang
| 45 |
| 32 | 2 | Zhang Sanfeng | 94 |
| 32 | 3 | Miejue Shitai | 77 |
| 32 | 4 | Lin Chaoying | 26 |
| 26 | 1 | Song Jiang
| 45 |
| 26 | 2 | Zhang Sanfeng | 94 |
| 26 | 3 | Miejue Shitai | 77 |
| 26 | 4 | Lin Chaoying | 26 |
| 46 | 1 | Song Jiang
| 45 |
| 46 | 2 | Zhang Sanfeng | 94 |
| 46 | 3 | Miejue Shitai | 77 |
| 46 | 4 | Lin Chaoying | 26 |
| 19 | 1 | Song Jiang
| 45 |
7 | Xi Ren
| 19 | 2 | Zhang Sanfeng | 94 |
| 19 | 3 | Miejue Shitai | 77 |
| 19 | 4 | Lin Chaoying | 26 |
7 | Xi Ren
7 | Xi Ren
8 | Lin Daiyu
8 | Lin Daiyu
8 | Lin Daiyu
8 | Lin Daiyu
| 17 | 1 | Song Jiang
| 45 |
| 17 | 2 | Zhang Sanfeng | 94 |
| 17 | 3 | Miejue Shitai | 77 |
| 17 | 4 | Lin Chaoying | 26 |
9 | Ren Yingying | 20 | 1 | Song Jiang
| 45 |
9 | Ren Yingying | 20 | 2 | Zhang Sanfeng | 94 |
9 | Ren Yingying | 20 | 3 | Miejue Shitai | 77 |
9 | Ren Yingying | 20 | 4 | Lin Chaoying | 26 |
10 | Yue Lingshan | 19 | 1 | Song Jiang
| 45 |
10 | Yue Lingshan | 19 | 2 | Zhang Sanfeng | 94 |
10 | Yue Lingshan | 19 | 3 | Miejue Shitai | 77 |
10 | Yue Lingshan | 19 | 4 | Lin Chaoying | 26 |
11 | Yuan Chengzhi | 23 | 1 | Song Jiang
| 45 |
11 | Yuan Chengzhi | 23 | 2 | Zhang Sanfeng | 94 |
11 | Yuan Chengzhi | 23 | 3 | Miejue Shitai | 77 |
11 | Yuan Chengzhi | 23 | 4 | Lin Chaoying | 26 |
12 | Wen Qingqing | 19 | 1 | Song Jiang
| 45 |
12 | Wen Qingqing | 19 | 2 | Zhang Sanfeng | 94 |
12 | Wen Qingqing | 19 | 3 | Miejue Shitai | 77 |
12 | Wen Qingqing | 19 | 4 | Lin Chaoying | 26 |
13 | Tian Boguang | 33 | 1 | Song Jiang
| 45 |
13 | Tian Boguang | 33 | 2 | Zhang Sanfeng | 94 |
13 | Tian Boguang | 33 | 3 | Miejue Shitai | 77 |
13 | Tian Boguang | 33 | 4 | Lin Chaoying | 26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 | Lu Wushuang | 17 | 1 | Song Jiang
| 45 |
14 | Lu Wushuang | 17 | 2 | Zhang Sanfeng | 94 |
14 | Lu Wushuang | 17 | 3 | Miejue Shitai | 77 |
14 | Lu Wushuang | 17 | 4 | Lin Chaoying | 26 |
15 | Duan Yu
15 | Duan Yu
15 | Duan Yu
15 | Duan Yu
16 | Xu Zhu
| 19 | 1 | Song Jiang
| 45 |
| 19 | 2 | Zhang Sanfeng | 94 |
| 19 | 3 | Miejue Shitai | 77 |
| 19 | 4 | Lin Chaoying | 26 |
| 21 | 1 | Song Jiang
| 45 |
16 | Xu Zhu
| 21 | 2 | Zhang Sanfeng | 94 |
| 21 | 3 | Miejue Shitai | 77 |
| 21 | 4 | Lin Chaoying | 26 |
16 | Xu Zhu
16 | Xu Zhu
17 | Lin Chong
17 | Lin Chong
17 | Lin Chong
17 | Lin Chong
18 | Hua Rong
18 | Hua Rong
18 | Hua Rong
18 | Hua Rong
| 25 | 1 | Song Jiang
| 45 |
| 25 | 2 | Zhang Sanfeng | 94 |
| 25 | 3 | Miejue Shitai | 77 |
| 25 | 4 | Lin Chaoying | 26 |
| 23 | 1 | Song Jiang
| 45 |
| 23 | 2 | Zhang Sanfeng | 94 |
| 23 | 3 | Miejue Shitai | 77 |
| 23 | 4 | Lin Chaoying | 26 |
19 | Xue Baochai | 18 | 1 | Song Jiang
| 45 |
19 | Xue Baochai | 18 | 2 | Zhang Sanfeng | 94 |
19 | Xue Baochai | 18 | 3 | Miejue Shitai | 77 |
19 | Xue Baochai | 18 | 4 | Lin Chaoying | 26 |
20 | Diao Chan
20 | Diao Chan
20 | Diao Chan
20 | Diao Chan
| 19 | 1 | Song Jiang
| 45 |
| 19 | 2 | Zhang Sanfeng | 94 |
| 19 | 3 | Miejue Shitai | 77 |
| 19 | 4 | Lin Chaoying | 26 |
21 | Huang Yueying | 22 | 1 | Song Jiang
| 45 |
21 | Huang Yueying | 22 | 2 | Zhang Sanfeng | 94 |
21 | Huang Yueying | 22 | 3 | Miejue Shitai | 77 |
21 | Huang Yueying | 22 | 4 | Lin Chaoying | 26 |
22 | Xiao Qiao
22 | Xiao Qiao
22 | Xiao Qiao
22 | Xiao Qiao
23 | Ma Chao
23 | Ma Chao
23 | Ma Chao
23 | Ma Chao
24 | Xu Xian
24 | Xu Xian
24 | Xu Xian
24 | Xu Xian
| 20 | 1 | Song Jiang
| 45 |
| 20 | 2 | Zhang Sanfeng | 94 |
| 20 | 3 | Miejue Shitai | 77 |
| 20 | 4 | Lin Chaoying | 26 |
| 23 | 1 | Song Jiang
| 45 |
| 23 | 2 | Zhang Sanfeng | 94 |
| 23 | 3 | Miejue Shitai | 77 |
| 23 | 4 | Lin Chaoying | 26 |
| 27 | 1 | Song Jiang
| 45 |
| 27 | 2 | Zhang Sanfeng | 94 |
| 27 | 3 | Miejue Shitai | 77 |
| 27 | 4 | Lin Chaoying | 26 |
25 | Sun Dasheng | 100 | 1 | Song Jiang
| 45 |
25 | Sun Dasheng | 100 | 2 | Zhang Sanfeng | 94 |
25 | Sun Dasheng | 100 | 3 | Miejue Shitai | 77 |
25 | Sun Dasheng | 100 | 4 | Lin Chaoying | 26 |
+-------+---------------+-----+-----+---------------+-----+
100 rows in set (0.001 sec)
MariaDB [hellodb]> select stuid,s.name student_name,s.age
student_age,tid,t.name teacher_name,t.age teacher_age from teachers t cross
join students s ;
+-------+---------------+-------------+-----+---------------+-------------+
| stuid | student_name | student_age | tid | teacher_name | teacher_age |
+-------+---------------+-------------+-----+---------------+-------------+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 | Shi Zhongyu |
1 | Shi Zhongyu |
1 | Shi Zhongyu |
1 | Shi Zhongyu |
22 | 1 | Song Jiang
|
45 |
94 |
77 |
26 |
45 |
94 |
77 |
26 |
45 |
94 |
77 |
26 |
45 |
94 |
77 |
26 |
45 |
94 |
77 |
26 |
45 |
94 |
77 |
26 |
45 |
94 |
77 |
26 |
45 |
94 |
77 |
26 |
45 |
94 |
77 |
26 |
45 |
94 |
77 |
26 |
45 |
94 |
77 |
26 |
45 |
94 |
77 |
26 |
45 |
94 |
77 |
26 |
45 |
94 |
77 |
26 |
45 |
94 |
22 | 2 | Zhang Sanfeng |
22 | 3 | Miejue Shitai |
22 | 4 | Lin Chaoying |
2 | Shi Potian
2 | Shi Potian
2 | Shi Potian
2 | Shi Potian
3 | Xie Yanke
3 | Xie Yanke
3 | Xie Yanke
3 | Xie Yanke
4 | Ding Dian
4 | Ding Dian
4 | Ding Dian
4 | Ding Dian
5 | Yu Yutong
5 | Yu Yutong
5 | Yu Yutong
5 | Yu Yutong
6 | Shi Qing
6 | Shi Qing
6 | Shi Qing
6 | Shi Qing
7 | Xi Ren
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 | 1 | Song Jiang
|
22 | 2 | Zhang Sanfeng |
22 | 3 | Miejue Shitai |
22 | 4 | Lin Chaoying |
53 | 1 | Song Jiang
|
53 | 2 | Zhang Sanfeng |
53 | 3 | Miejue Shitai |
53 | 4 | Lin Chaoying |
32 | 1 | Song Jiang
|
32 | 2 | Zhang Sanfeng |
32 | 3 | Miejue Shitai |
32 | 4 | Lin Chaoying |
26 | 1 | Song Jiang
|
26 | 2 | Zhang Sanfeng |
26 | 3 | Miejue Shitai |
26 | 4 | Lin Chaoying |
46 | 1 | Song Jiang
|
46 | 2 | Zhang Sanfeng |
46 | 3 | Miejue Shitai |
46 | 4 | Lin Chaoying |
19 | 1 | Song Jiang
|
7 | Xi Ren
19 | 2 | Zhang Sanfeng |
19 | 3 | Miejue Shitai |
19 | 4 | Lin Chaoying |
7 | Xi Ren
7 | Xi Ren
8 | Lin Daiyu
8 | Lin Daiyu
8 | Lin Daiyu
8 | Lin Daiyu
17 | 1 | Song Jiang
|
17 | 2 | Zhang Sanfeng |
17 | 3 | Miejue Shitai |
17 | 4 | Lin Chaoying |
9 | Ren Yingying |
9 | Ren Yingying |
9 | Ren Yingying |
9 | Ren Yingying |
10 | Yue Lingshan |
10 | Yue Lingshan |
10 | Yue Lingshan |
10 | Yue Lingshan |
11 | Yuan Chengzhi |
11 | Yuan Chengzhi |
11 | Yuan Chengzhi |
11 | Yuan Chengzhi |
12 | Wen Qingqing |
12 | Wen Qingqing |
12 | Wen Qingqing |
12 | Wen Qingqing |
13 | Tian Boguang |
13 | Tian Boguang |
13 | Tian Boguang |
13 | Tian Boguang |
14 | Lu Wushuang |
14 | Lu Wushuang |
14 | Lu Wushuang |
14 | Lu Wushuang |
20 | 1 | Song Jiang
|
20 | 2 | Zhang Sanfeng |
20 | 3 | Miejue Shitai |
20 | 4 | Lin Chaoying |
19 | 1 | Song Jiang
|
19 | 2 | Zhang Sanfeng |
19 | 3 | Miejue Shitai |
19 | 4 | Lin Chaoying |
23 | 1 | Song Jiang
|
23 | 2 | Zhang Sanfeng |
23 | 3 | Miejue Shitai |
23 | 4 | Lin Chaoying |
19 | 1 | Song Jiang
|
19 | 2 | Zhang Sanfeng |
19 | 3 | Miejue Shitai |
19 | 4 | Lin Chaoying |
33 | 1 | Song Jiang
|
33 | 2 | Zhang Sanfeng |
33 | 3 | Miejue Shitai |
33 | 4 | Lin Chaoying |
17 | 1 | Song Jiang
|
17 | 2 | Zhang Sanfeng |
17 | 3 | Miejue Shitai |
17 | 4 | Lin Chaoying |
15 | Duan Yu
15 | Duan Yu
|
|
19 | 1 | Song Jiang
|
19 | 2 | Zhang Sanfeng |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 | Duan Yu
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
19 |
21 |
21 |
21 |
21 |
25 |
25 |
25 |
25 |
23 |
23 |
23 |
23 |
18 |
18 |
18 |
18 |
19 |
19 |
19 |
19 |
22 |
22 |
22 |
22 |
20 |
20 |
20 |
20 |
23 |
23 |
23 |
23 |
27 |
27 |
27 |
27 |
100 |
100 |
100 |
100 |
3 | Miejue Shitai |
77 |
26 |
45 |
94 |
77 |
26 |
45 |
94 |
77 |
26 |
45 |
94 |
77 |
26 |
45 |
94 |
77 |
26 |
45 |
94 |
77 |
26 |
45 |
94 |
77 |
26 |
45 |
94 |
77 |
26 |
45 |
94 |
77 |
26 |
45 |
94 |
77 |
26 |
45 |
94 |
77 |
26 |
15 | Duan Yu
4 | Lin Chaoying
1 | Song Jiang
|
|
16 | Xu Zhu
16 | Xu Zhu
2 | Zhang Sanfeng |
3 | Miejue Shitai |
16 | Xu Zhu
16 | Xu Zhu
4 | Lin Chaoying
1 | Song Jiang
|
|
17 | Lin Chong
17 | Lin Chong
17 | Lin Chong
17 | Lin Chong
18 | Hua Rong
18 | Hua Rong
18 | Hua Rong
18 | Hua Rong
19 | Xue Baochai
19 | Xue Baochai
19 | Xue Baochai
19 | Xue Baochai
20 | Diao Chan
20 | Diao Chan
20 | Diao Chan
20 | Diao Chan
2 | Zhang Sanfeng |
3 | Miejue Shitai |
4 | Lin Chaoying
1 | Song Jiang
|
|
2 | Zhang Sanfeng |
3 | Miejue Shitai |
4 | Lin Chaoying
1 | Song Jiang
|
|
2 | Zhang Sanfeng |
3 | Miejue Shitai |
4 | Lin Chaoying
1 | Song Jiang
|
|
2 | Zhang Sanfeng |
3 | Miejue Shitai |
4 | Lin Chaoying
1 | Song Jiang
|
|
21 | Huang Yueying |
21 | Huang Yueying |
21 | Huang Yueying |
21 | Huang Yueying |
2 | Zhang Sanfeng |
3 | Miejue Shitai |
4 | Lin Chaoying
1 | Song Jiang
|
|
22 | Xiao Qiao
22 | Xiao Qiao
22 | Xiao Qiao
22 | Xiao Qiao
23 | Ma Chao
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 | Zhang Sanfeng |
3 | Miejue Shitai |
4 | Lin Chaoying
1 | Song Jiang
|
|
23 | Ma Chao
2 | Zhang Sanfeng |
3 | Miejue Shitai |
23 | Ma Chao
23 | Ma Chao
4 | Lin Chaoying
1 | Song Jiang
|
|
24 | Xu Xian
24 | Xu Xian
2 | Zhang Sanfeng |
3 | Miejue Shitai |
24 | Xu Xian
24 | Xu Xian
4 | Lin Chaoying
1 | Song Jiang
|
|
25 | Sun Dasheng
25 | Sun Dasheng
25 | Sun Dasheng
25 | Sun Dasheng
2 | Zhang Sanfeng |
3 | Miejue Shitai |
4 | Lin Chaoying
|
+-------+---------------+-------------+-----+---------------+-------------+
100 rows in set (0.000 sec)
3.7.2.4 内连接
inner join 内连接取多个表的交集
范例:内连接
#内连接inner join
MariaDB [hellodb]> select * from students inner join teachers on
students.teacherid=teachers.tid;
+-------+-------------+-----+--------+---------+-----------+-----+---------------
+-----+--------+
| StuID | Name
| Age | Gender | ClassID | TeacherID | TID | Name
| Age | Gender |
+-------+-------------+-----+--------+---------+-----------+-----+---------------
+-----+--------+
|
5 | Yu Yutong
45 | M
1 | Shi Zhongyu | 22 | M
|
26 | M
|
|
|
3 |
2 |
4 |
1 |
3 |
4 |
1 | Song Jiang
|
|
|
|
|
3 | Miejue Shitai
4 | Lin Chaoying
77 | F
|
4 | Ding Dian
|
32 | M
|
93 | F
|
+-------+-------------+-----+--------+---------+-----------+-----+---------------
+-----+--------+
#如果表定义了别名,原表名将无法使用
MariaDB [hellodb]> select stuid,s.name as student_name ,tid,t.name as
teacher_name from students as s inner join teachers as t on s.teacherid=t.tid;
+-------+--------------+-----+---------------+
| stuid | student_name | tid | teacher_name
|
+-------+--------------+-----+---------------+
|
|
|
5 | Yu Yutong
1 | Shi Zhongyu
4 | Ding Dian
|
|
|
1 | Song Jiang
3 | Miejue Shitai |
4 | Lin Chaoying
|
|
+-------+--------------+-----+---------------+
3 rows in set (0.00 sec)
MariaDB [hellodb]> select stuid,s.name studentname,s.age studentage,tid,t.name
as teachername,t.age teacherage
from students as s inner join teachers t on s.teacherid=t.tid;
+-------+-------------+------------+-----+---------------+------------+
| stuid | studentname | studentage | tid | teachername
| teacherage |
+-------+-------------+------------+-----+---------------+------------+
|
|
|
|
5 | Yu Yutong
|
26 |
100 |
22 |
1 | Song Jiang
1 | Song Jiang
|
|
45 |
45 |
77 |
93 |
25 | Sun Dasheng |
1 | Shi Zhongyu |
3 | Miejue Shitai |
4 | Lin Chaoying |
4 | Ding Dian
|
32 |
+-------+-------------+------------+-----+---------------+------------+
4 rows in set (0.00 sec)
MariaDB [hellodb]> select * from students , teachers where
students.teacherid=teachers.tid;
+-------+-------------+-----+--------+---------+-----------+-----+---------------
+-----+--------+
| StuID | Name
| Age | Gender | ClassID | TeacherID | TID | Name
| Age | Gender |
+-------+-------------+-----+--------+---------+-----------+-----+---------------
+-----+--------+
|
5 | Yu Yutong
45 | M
25 | Sun Dasheng | 100 | M
45 | M
1 | Shi Zhongyu | 22 | M
|
26 | M
|
|
|
|
3 |
NULL |
2 |
1 |
1 |
3 |
4 |
1 | Song Jiang
1 | Song Jiang
3 | Miejue Shitai
4 | Lin Chaoying
|
|
|
|
|
|
|
|
77 | F
|
4 | Ding Dian
|
32 | M
4 |
|
93 | F
|
+-------+-------------+-----+--------+---------+-----------+-----+---------------
+-----+--------+
4 rows in set (0.00 sec)
MariaDB [hellodb]> select s.name 学生姓名,s.age 学生年龄,s.gender 学生性别,t.name 老
师姓名,t.age 老师年龄,t.gender 老师性别 from students s inner join teachers t on
s.gender <> t.gender;
+---------------+--------------+--------------+---------------+--------------+---
| 学生姓名
| 学生年龄
| 学生性别
| 老师姓名
| 老师年龄
| 老师性别
|
+---------------+--------------+--------------+---------------+--------------+---
| Shi Zhongyu
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 | M
45 | M
22 | M
22 | M
77 | M
77 | M
32 | M
32 | M
26 | M
26 | M
46 | M
46 | M
19 | F
19 | F
17 | F
17 | F
20 | F
20 | F
19 | F
19 | F
23 | M
23 | M
| Miejue Shitai |
77 | F
29 | F
77 | F
29 | F
77 | F
29 | F
77 | F
29 | F
77 | F
29 | F
77 | F
29 | F
45 | M
94 | M
45 | M
94 | M
45 | M
94 | M
45 | M
94 | M
77 | F
29 | F
|
| Shi Zhongyu
| Lin Chaoying
|
|
| Shi Potian
| Miejue Shitai |
|
| Shi Potian
| Lin Chaoying
|
|
| Xie Yanke
| Miejue Shitai |
|
| Xie Yanke
| Lin Chaoying
|
|
| Ding Dian
| Miejue Shitai |
|
| Ding Dian
| Lin Chaoying
|
|
| Yu Yutong
| Miejue Shitai |
|
| Yu Yutong
| Lin Chaoying
|
|
| Shi Qing
| Miejue Shitai |
|
| Shi Qing
| Lin Chaoying
| Song Jiang
|
|
|
| Xi Ren
|
| Xi Ren
| Zhang Sanfeng |
|
| Lin Daiyu
| Song Jiang
|
|
| Lin Daiyu
| Zhang Sanfeng |
|
| Ren Yingying
| Song Jiang
|
|
| Ren Yingying
| Zhang Sanfeng |
|
| Yue Lingshan
| Song Jiang
|
|
| Yue Lingshan
|
| Zhang Sanfeng |
| Miejue Shitai |
| Yuan Chengzhi |
|
| Yuan Chengzhi |
|
| Lin Chaoying
|
| Wen Qingqing |
19 | F
19 | F
33 | M
33 | M
17 | F
17 | F
19 | M
19 | M
21 | M
21 | M
25 | M
25 | M
23 | M
23 | M
18 | F
18 | F
19 | F
19 | F
22 | F
22 | F
20 | F
20 | F
23 | M
23 | M
27 | M
27 | M
100 | M
100 | M
| Song Jiang
|
45 | M
94 | M
77 | F
29 | F
45 | M
94 | M
77 | F
29 | F
77 | F
29 | F
77 | F
29 | F
77 | F
29 | F
45 | M
94 | M
45 | M
94 | M
45 | M
94 | M
45 | M
94 | M
77 | F
29 | F
77 | F
29 | F
77 | F
29 | F
|
| Wen Qingqing |
| Zhang Sanfeng |
| Miejue Shitai |
| Lin Chaoying |
|
| Tian Boguang |
|
| Tian Boguang |
|
| Lu Wushuang |
| Song Jiang
|
|
| Lu Wushuang |
|
| Zhang Sanfeng |
| Miejue Shitai |
| Lin Chaoying |
| Miejue Shitai |
| Lin Chaoying |
| Miejue Shitai |
| Lin Chaoying |
| Miejue Shitai |
| Lin Chaoying |
| Duan Yu
| Duan Yu
| Xu Zhu
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| Xu Zhu
| Lin Chong
| Lin Chong
| Hua Rong
| Hua Rong
| Xue Baochai |
| Song Jiang
|
|
| Xue Baochai |
|
| Zhang Sanfeng |
| Diao Chan
|
| Song Jiang
|
|
|
| Diao Chan
|
| Zhang Sanfeng |
| Huang Yueying |
| Song Jiang
|
|
| Huang Yueying |
|
| Zhang Sanfeng |
| Xiao Qiao
| Xiao Qiao
| Ma Chao
| Ma Chao
| Xu Xian
| Xu Xian
|
|
|
|
|
|
| Song Jiang
|
|
|
|
|
|
|
| Zhang Sanfeng |
| Miejue Shitai |
| Lin Chaoying |
| Miejue Shitai |
| Lin Chaoying |
| Miejue Shitai |
| Lin Chaoying |
| Sun Dasheng |
|
| Sun Dasheng |
|
+---------------+--------------+--------------+---------------+--------------+---
50 rows in set (0.000 sec)
MariaDB [hellodb]> select stuid,s.name,tid,t.name from students s,teachers t
where s.teacherid=t.tid;
+-------+-------------+-----+---------------+
| stuid | name
| tid | name
|
+-------+-------------+-----+---------------+
|
|
|
5 | Yu Yutong
1 | Shi Zhongyu |
4 | Ding Dian
|
1 | Song Jiang
3 | Miejue Shitai |
4 | Lin Chaoying
|
|
|
+-------+-------------+-----+---------------+
3 rows in set (0.00 sec)
#内连接后过滤数据
MariaDB [hellodb]> select * from students s inner join teachers t on
s.teacherid=t.tid and s.age > 30 ;
+-------+-------------+-----+--------+---------+-----------+-----+--------------
+-----+--------+
| StuID | Name
| Age | Gender | ClassID | TeacherID | TID | Name
| Age | Gender |
+-------+-------------+-----+--------+---------+-----------+-----+--------------
+-----+--------+
|
|
|
|
25 | Sun Dasheng | 100 | M
|
NULL |
1 |
1 | Song Jiang
45 | M
|
4 | Ding Dian
|
32 | M
|
4 |
4 |
4 | Lin Chaoying
26 | F
|
+-------+-------------+-----+--------+---------+-----------+-----+--------------
+-----+--------+
2 rows in set (0.002 sec)
MariaDB [hellodb]> select * from students s inner join teachers t on
s.teacherid=t.tid where s.age > 30 ;
+-------+-------------+-----+--------+---------+-----------+-----+--------------
+-----+--------+
| StuID | Name
| Age | Gender | ClassID | TeacherID | TID | Name
| Age | Gender |
+-------+-------------+-----+--------+---------+-----------+-----+--------------
+-----+--------+
|
|
|
|
25 | Sun Dasheng | 100 | M
|
NULL |
1 |
1 | Song Jiang
45 | M
|
4 | Ding Dian
|
32 | M
|
4 |
4 |
4 | Lin Chaoying
26 | F
|
+-------+-------------+-----+--------+---------+-----------+-----+--------------
+-----+--------+
2 rows in set (0.001 sec)
自然连接
当源表和目标表共享相同名称的列时,就可以在它们之间执行自然连接,而无需指定连接列。
在使用纯自然连接时,如没有相同的列时,会产生交叉连接(笛卡尔乘积)
语法:(SQL:1999)SELECT table1.column, table2.column FROM table1 NATURAL JOIN table2;
范例:
MariaDB [db1]> create table t1 ( id int,name char(20));
MariaDB [db1]> create table t2 ( id int,title char(20));
MariaDB [db1]> insert t1 values(1,'mage'),(2,'wang'),(3,'zhang');
MariaDB [db1]> insert t2 values(1,'ceo'),(2,'cto');
MariaDB [db1]> select * from t1;
+------+-------+
| id
| name
|
+------+-------+
|
|
|
1 | mage
2 | wang
|
|
3 | zhang |
+------+-------+
3 rows in set (0.00 sec)
MariaDB [db1]> select * from t2;
+------+-------+
| id
| title |
+------+-------+
|
|
1 | ceo
2 | cto
|
|
+------+-------+
2 rows in set (0.00 sec)
MariaDB [db1]> select * from t1 NATURAL JOIN t2;
+------+------+-------+
| id
| name | title |
+------+------+-------+
|
|
1 | mage | ceo
2 | wang | cto
|
|
+------+------+-------+
2 rows in set (0.00 sec)
MariaDB [db1]> select t1.name,t2.title from t1 NATURAL JOIN t2;
+------+-------+
| name | title |
+------+-------+
| mage | ceo
| wang | cto
|
|
+------+-------+
2 rows in set (0.00 sec)
3.7.2.4 左和右外连接
左连接: 以左表为主根据条件查询右表数据﹐如果根据条件查询右表数据不存在使用null值填充
右连接: 以右表为主根据条件查询左表数据﹐如果根据条件查询左表数据不存在使用null值填充
范例:左,右外连接
#左外连接
MariaDB [hellodb]> select s.stuid,s.name,s.age,s.teacherid,t.tid,t.name,t.age
from students as s left outer join teachers as t on s.teacherid=t.tid;
+-------+---------------+-----+-----------+------+---------------+------+
| stuid | name
| age | teacherid | tid | name
| age
|
+-------+---------------+-----+-----------+------+---------------+------+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 | Shi Zhongyu
2 | Shi Potian
3 | Xie Yanke
4 | Ding Dian
5 | Yu Yutong
6 | Shi Qing
|
|
|
|
|
|
|
|
|
|
22 |
22 |
53 |
32 |
26 |
46 |
19 |
17 |
20 |
19 |
3 |
3 | Miejue Shitai |
77 |
| NULL |
| NULL |
7 | NULL | NULL
16 | NULL | NULL
4 |
1 |
4 | Lin Chaoying
1 | Song Jiang
|
|
93 |
45 |
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
7 | Xi Ren
8 | Lin Daiyu
9 | Ren Yingying
10 | Yue Lingshan
11 | Yuan Chengzhi | 23 |
12 | Wen Qingqing
13 | Tian Boguang
14 | Lu Wushuang
15 | Duan Yu
|
|
|
|
|
|
|
|
|
19 |
33 |
17 |
19 |
21 |
25 |
23 |
18 |
19 |
16 | Xu Zhu
17 | Lin Chong
18 | Hua Rong
19 | Xue Baochai
20 | Diao Chan
21 | Huang Yueying | 22 |
22 | Xiao Qiao
23 | Ma Chao
|
|
|
20 |
23 |
27 |
24 | Xu Xian
25 | Sun Dasheng
| 100 |
+-------+---------------+-----+-----------+------+---------------+------+
25 rows in set (0.00 sec)
#左外连接扩展
MariaDB [hellodb]> select * from students s left outer join teachers t on
s.teacherid=t.tid where t.tid is null;
+-------+---------------+-----+--------+---------+-----------+------+------+-----
-+--------+
| StuID | Name
| Gender |
| Age | Gender | ClassID | TeacherID | TID | Name | Age
+-------+---------------+-----+--------+---------+-----------+------+------+-----
-+--------+
|
2 | Shi Potian
NULL | NULL
3 | Xie Yanke
NULL | NULL
6 | Shi Qing
NULL | NULL
7 | Xi Ren
NULL | NULL
8 | Lin Daiyu
NULL | NULL
9 | Ren Yingying
NULL | NULL
10 | Yue Lingshan
NULL | NULL
11 | Yuan Chengzhi | 23 | M
NULL | NULL
12 | Wen Qingqing
NULL | NULL
13 | Tian Boguang
NULL | NULL
|
|
|
|
|
|
|
22 | M
53 | M
46 | M
19 | F
17 | F
20 | F
19 | F
|
|
|
|
|
|
|
|
|
|
1 |
2 |
5 |
3 |
7 |
6 |
3 |
6 |
1 |
2 |
7 | NULL | NULL |
16 | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 | F
33 | M
|
|
|
|
14 | Lu Wushuang | 17 | F
NULL | NULL |
15 | Duan Yu
NULL | NULL |
16 | Xu Zhu
NULL | NULL |
|
|
|
|
|
|
|
|
|
|
|
3 |
4 |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
|
| 19 | M
| 21 | M
| 25 | M
| 23 | M
|
1 |
|
17 | Lin Chong
4 |
NULL | NULL |
|
18 | Hua Rong
NULL | NULL |
19 | Xue Baochai | 18 | F
NULL | NULL |
7 |
|
6 |
|
20 | Diao Chan
| 19 | F
7 |
NULL | NULL |
|
21 | Huang Yueying | 22 | F
6 |
NULL | NULL |
|
22 | Xiao Qiao
| 20 | F
| 23 | M
| 27 | M
1 |
NULL | NULL |
|
23 | Ma Chao
NULL | NULL |
24 | Xu Xian
NULL | NULL |
4 |
|
NULL |
+-------+---------------+-----+--------+---------+-----------+------+------+-----
-+--------+
21 rows in set (0.001 sec)
#多个条件的左外连接
MariaDB [hellodb]> select * from students s left outer join teachers t on
s.teacherid=t.tid and s.teacherid is null;
+-------+---------------+-----+--------+---------+-----------+------+------+-----
-+--------+
| StuID | Name
| Gender |
| Age | Gender | ClassID | TeacherID | TID | Name | Age
+-------+---------------+-----+--------+---------+-----------+------+------+-----
-+--------+
|
1 | Shi Zhongyu | 22 | M
|
|
|
|
|
|
|
|
|
|
|
2 |
1 |
2 |
4 |
3 |
5 |
3 |
7 |
6 |
3 |
6 |
3 | NULL | NULL |
NULL | NULL |
|
2 | Shi Potian
| 22 | M
| 53 | M
| 32 | M
| 26 | M
| 46 | M
| 19 | F
| 17 | F
7 | NULL | NULL |
NULL | NULL |
|
3 | Xie Yanke
16 | NULL | NULL |
4 | NULL | NULL |
NULL | NULL |
|
4 | Ding Dian
NULL | NULL |
|
5 | Yu Yutong
1 | NULL | NULL |
NULL | NULL |
|
6 | Shi Qing
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL |
|
7 | Xi Ren
NULL | NULL |
|
8 | Lin Daiyu
NULL | NULL |
|
9 | Ren Yingying | 20 | F
NULL | NULL |
|
10 | Yue Lingshan | 19 | F
NULL | NULL |
|
11 | Yuan Chengzhi | 23 | M
NULL | NULL |
|
12 | Wen Qingqing | 19 | F
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
2 |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL |
|
13 | Tian Boguang | 33 | M
NULL | NULL |
|
14 | Lu Wushuang | 17 | F
3 |
NULL | NULL |
|
15 | Duan Yu
NULL | NULL |
16 | Xu Zhu
NULL | NULL |
| 19 | M
| 21 | M
| 25 | M
| 23 | M
4 |
|
1 |
|
17 | Lin Chong
4 |
NULL | NULL |
|
18 | Hua Rong
NULL | NULL |
19 | Xue Baochai | 18 | F
NULL | NULL |
7 |
|
6 |
|
20 | Diao Chan
| 19 | F
7 |
NULL | NULL |
|
21 | Huang Yueying | 22 | F
6 |
NULL | NULL |
|
22 | Xiao Qiao
| 20 | F
| 23 | M
| 27 | M
1 |
NULL | NULL |
|
23 | Ma Chao
NULL | NULL |
24 | Xu Xian
NULL | NULL |
25 | Sun Dasheng | 100 | M
NULL | NULL |
4 |
|
NULL |
NULL |
|
+-------+---------------+-----+--------+---------+-----------+------+------+-----
-+--------+
25 rows in set (0.001 sec)
#先左外连接,再过滤
MariaDB [hellodb]> select * from students s left outer join teachers t on
s.teacherid=t.tid where s.teacherid is null;
+-------+---------------+-----+--------+---------+-----------+------+------+-----
-+--------+
| StuID | Name
| Gender |
| Age | Gender | ClassID | TeacherID | TID | Name | Age
+-------+---------------+-----+--------+---------+-----------+------+------+-----
-+--------+
|
6 | Shi Qing
NULL | NULL |
7 | Xi Ren
NULL | NULL |
| 46 | M
| 19 | F
| 17 | F
|
|
|
|
|
|
|
|
5 |
3 |
7 |
6 |
3 |
6 |
1 |
2 |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
|
|
8 | Lin Daiyu
NULL | NULL |
|
9 | Ren Yingying | 20 | F
NULL | NULL |
|
10 | Yue Lingshan | 19 | F
NULL | NULL |
|
11 | Yuan Chengzhi | 23 | M
NULL | NULL |
|
12 | Wen Qingqing | 19 | F
NULL | NULL |
|
13 | Tian Boguang | 33 | M
NULL | NULL |
|
14 | Lu Wushuang
NULL | NULL
15 | Duan Yu
NULL | NULL
16 | Xu Zhu
NULL | NULL
17 | Lin Chong
NULL | NULL
18 | Hua Rong
NULL | NULL
19 | Xue Baochai
NULL | NULL
20 | Diao Chan
NULL | NULL
21 | Huang Yueying | 22 | F
NULL | NULL
22 | Xiao Qiao
NULL | NULL
23 | Ma Chao
NULL | NULL
24 | Xu Xian
NULL | NULL
25 | Sun Dasheng
NULL | NULL
|
|
|
|
|
|
|
17 | F
19 | M
21 | M
25 | M
23 | M
18 | F
19 | F
|
|
|
|
|
|
|
|
|
|
|
|
3 |
4 |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
NULL | NULL | NULL |
|
|
|
|
1 |
|
|
4 |
|
|
7 |
|
|
6 |
|
|
7 |
|
|
6 |
|
|
|
|
|
20 | F
23 | M
27 | M
1 |
|
|
4 |
|
|
NULL |
NULL |
|
|
| 100 | M
|
+-------+---------------+-----+--------+---------+-----------+------+------+-----
-+--------+
20 rows in set (0.000 sec)
#右外连接
MariaDB [hellodb]> select * from students s right outer join teachers t on
s.teacherid=t.tid
;
+-------+-------------+------+--------+---------+-----------+-----+--------------
-+-----+--------+
| StuID | Name
| Age | Gender | ClassID | TeacherID | TID | Name
| Age | Gender |
+-------+-------------+------+--------+---------+-----------+-----+--------------
-+-----+--------+
|
1 | Shi Zhongyu |
22 | M
32 | M
26 | M
|
|
|
|
|
2 |
3 |
3 | Miejue
Shitai | 77 | F
|
|
|
|
|
|
4 | Ding Dian
4 |
4 |
4 | Lin Chaoying
1 | Song Jiang
1 | Song Jiang
2 | Zhang
|
|
|
26 | F
|
5 | Yu Yutong
|
3 |
1 |
45 | M
|
25 | Sun Dasheng | 100 | M
NULL |
NULL |
1 |
45 | M
|
NULL | NULL
| NULL | NULL
|
NULL |
Sanfeng | 94 | M
+-------+-------------+------+--------+---------+-----------+-----+--------------
-+-----+--------+
5 rows in set (0.001 sec)
#右外连接的扩展用法
MariaDB [hellodb]> select * from students s right outer join teachers t on
s.teacherid=t.tid where s.teacherid is null;
+-------+------+------+--------+---------+-----------+-----+---------------+-----
+--------+
| StuID | Name | Age | Gender | ClassID | TeacherID | TID | Name
| Gender |
| Age
+-------+------+------+--------+---------+-----------+-----+---------------+-----
+--------+
|
NULL | NULL | NULL | NULL
|
NULL |
NULL |
2 | Zhang Sanfeng | 94
| M
|
+-------+------+------+--------+---------+-----------+-----+---------------+-----
+--------+
1 row in set (0.000 sec)
3.7.2.5 完全外连接
MySQL 不支持完全外连接full outer join语法
范例:完全外连接
#MySQL不支持完全外连接 full outer join,利用以下方式法代替
MariaDB [hellodb]> select * from students left join teachers on
students.teacherid=teachers.tid
-> union
-> select * from students right join teachers on
students.teacherid=teachers.tid;
MariaDB [hellodb]> select s.stuid,s.name,s.age,t.tid,t.name,t.age from students
as s left
join teachers as t on s.teacherid=t.tid
-> union
-> select s.stuid,s.name,s.age,t.tid,t.name,t.age from students as s right
join teachers as t on s.teacherid=t.tid;
+-------+---------------+------+------+---------------+------+
| stuid | name
| age | tid | name
| age
|
+-------+---------------+------+------+---------------+------+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 | Shi Zhongyu
2 | Shi Potian
3 | Xie Yanke
4 | Ding Dian
5 | Yu Yutong
6 | Shi Qing
|
|
|
|
|
|
|
|
|
|
22 |
3 | Miejue Shitai |
77 |
| NULL |
| NULL |
22 | NULL | NULL
53 | NULL | NULL
32 |
26 |
4 | Lin Chaoying
1 | Song Jiang
|
|
93 |
45 |
46 | NULL | NULL
19 | NULL | NULL
17 | NULL | NULL
20 | NULL | NULL
19 | NULL | NULL
23 | NULL | NULL
19 | NULL | NULL
33 | NULL | NULL
17 | NULL | NULL
19 | NULL | NULL
21 | NULL | NULL
25 | NULL | NULL
23 | NULL | NULL
18 | NULL | NULL
19 | NULL | NULL
22 | NULL | NULL
20 | NULL | NULL
23 | NULL | NULL
27 | NULL | NULL
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
7 | Xi Ren
8 | Lin Daiyu
9 | Ren Yingying
10 | Yue Lingshan
11 | Yuan Chengzhi |
12 | Wen Qingqing
13 | Tian Boguang
14 | Lu Wushuang
15 | Duan Yu
|
|
|
|
|
|
|
|
|
16 | Xu Zhu
17 | Lin Chong
18 | Hua Rong
19 | Xue Baochai
20 | Diao Chan
21 | Huang Yueying |
22 | Xiao Qiao
23 | Ma Chao
24 | Xu Xian
|
|
|
|
25 | Sun Dasheng | 100 | NULL | NULL
| NULL |
| NULL | NULL
| NULL |
2 | Zhang Sanfeng | 94 |
+-------+---------------+------+------+---------------+------+
26 rows in set (0.01 sec)
#完全外连接的扩展示例
MariaDB [hellodb]> select * from students s left outer join teachers t on
s.teacherid=t.tid where t.tid is null union select * from students s right outer
join teachers t on s.teacherid=t.tid where s.teacherid is null;
+-------+---------------+------+--------+---------+-----------+------+-----------
----+------+--------+
| StuID | Name
| Age | Gender |
| Age | Gender | ClassID | TeacherID | TID | Name
+-------+---------------+------+--------+---------+-----------+------+-----------
----+------+--------+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 | Shi Potian
| NULL | NULL |
3 | Xie Yanke
| 22 | M
| 53 | M
| 46 | M
| 19 | F
| 17 | F
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
2 |
5 |
3 |
7 |
6 |
3 |
6 |
1 |
2 |
3 |
4 |
1 |
4 |
7 |
6 |
7 |
6 |
1 |
4 |
7 | NULL | NULL
16 | NULL | NULL
| NULL | NULL |
6 | Shi Qing
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
| NULL | NULL |
7 | Xi Ren
| NULL | NULL |
8 | Lin Daiyu
| NULL | NULL |
9 | Ren Yingying | 20 | F
| NULL | NULL |
10 | Yue Lingshan | 19 | F
| NULL | NULL |
11 | Yuan Chengzhi | 23 | M
| NULL | NULL |
12 | Wen Qingqing | 19 | F
| NULL | NULL |
13 | Tian Boguang | 33 | M
| NULL | NULL |
14 | Lu Wushuang | 17 | F
| NULL | NULL |
15 | Duan Yu
| 19 | M
| 21 | M
| 25 | M
| 23 | M
| NULL | NULL |
16 | Xu Zhu
| NULL | NULL |
17 | Lin Chong
| NULL | NULL |
18 | Hua Rong
| NULL | NULL |
19 | Xue Baochai | 18 | F
| NULL | NULL |
20 | Diao Chan
| 19 | F
| NULL | NULL |
21 | Huang Yueying | 22 | F
| NULL | NULL |
22 | Xiao Qiao
| NULL | NULL |
23 | Ma Chao
| 20 | F
| 23 | M
| NULL | NULL |
|
|
24 | Xu Xian
| 27 | M
|
|
NULL |
NULL |
NULL |
NULL | NULL | NULL
NULL | NULL | NULL
| NULL | NULL |
25 | Sun Dasheng | 100 | M
| NULL | NULL |
| NULL | NULL
| NULL | NULL |
|
NULL |
2 | Zhang
Sanfeng | 94 | M
+-------+---------------+------+--------+---------+-----------+------+-----------
----+------+--------+
23 rows in set (0.001 sec)
MariaDB [hellodb]> select * from (select s.stuid,s.name
s_name,s.teacherid,t.tid,t.name t_name from students s left outer join teachers
t on s.teacherid=t.tid union select s.stuid,s.name,s.teacherid,t.tid,t.name
from students s right outer join teachers t on s.teacherid=t.tid) as a where
a.teacherid is null or a.tid is null;
+-------+---------------+-----------+------+---------------+
| stuid | s_name
| teacherid | tid | t_name
|
+-------+---------------+-----------+------+---------------+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 | Shi Potian
3 | Xie Yanke
6 | Shi Qing
7 | Xi Ren
|
|
|
|
|
7 | NULL | NULL
16 | NULL | NULL
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
NULL | NULL | NULL
8 | Lin Daiyu
9 | Ren Yingying |
10 | Yue Lingshan |
11 | Yuan Chengzhi |
12 | Wen Qingqing |
13 | Tian Boguang |
14 | Lu Wushuang |
15 | Duan Yu
16 | Xu Zhu
|
|
|
|
17 | Lin Chong
18 | Hua Rong
19 | Xue Baochai |
20 | Diao Chan
21 | Huang Yueying |
|
22 | Xiao Qiao
23 | Ma Chao
24 | Xu Xian
|
|
|
|
|
| NULL | NULL
| NULL | NULL
NULL |
NULL |
2 | Zhang Sanfeng |
5 | abc
|
+-------+---------------+-----------+------+---------------+
23 rows in set (0.00 sec)
3.7.2.6 自连接
自连接, 即表自身连接自身
范例:自连接
#自连接
MariaDB [hellodb]> select * from emp;
+------+----------+----------+
| id | name
+------+----------+----------+
1 | mage NULL |
| leaderid |
|
|
|
|
|
2 | zhangsir |
1 |
2 |
3 |
3 | wang
|
|
4 | zhang
+------+----------+----------+
4 rows in set (0.00 sec)
MariaDB [hellodb]> select
e.leaderid=l.id;
e.name,l.name
from emp as e inner join emp as l on
+----------+----------+
| name
+----------+----------+
| zhangsir | mage
| name
|
|
| wang
| zhangsir |
| wang
| zhang
|
+----------+----------+
3 rows in set (0.00 sec)
MariaDB [hellodb]> select
join emp as l on e.leaderid=l.id;
+----------+----------+
e.name,IFNULL(l.name,'无上级')
from emp as e left
| name
+----------+----------+
| zhangsir | mage
| name
|
|
| wang
| zhang
| mage
| zhangsir |
| wang
| NULL
|
|
+----------+----------+
4 rows in set (0.00 sec)
MariaDB [hellodb]> select e.name emp,IFNULL(l.name,'无上级') leader from emp as e
left join emp as l on e.leaderid=l.id;
+----------+----------+
| emp
+----------+----------+
| zhangsir | mage
| leader
|
|
| wang
| zhang
| mage
| zhangsir |
| wang
| NULL
|
|
+----------+----------+
4 rows in set (0.000 sec)
范例:三表连接
#三张表连接示例
MariaDB [hellodb]> select name,course,score from students st inner join scores
sc on st.stuid=sc.stuid inner join courses co on sc.courseid=co.CourseID;
+-------------+----------------+-------+
| name
| course
| score |
+-------------+----------------+-------+
| Shi Zhongyu | Kuihua Baodian |
| Shi Zhongyu | Weituo Zhang
| Shi Potian | Kuihua Baodian |
| Shi Potian | Daiyu Zanghua
77 |
93 |
47 |
97 |
88 |
75 |
|
|
| Xie Yanke
| Xie Yanke
| Kuihua Baodian |
| Weituo Zhang
|
| Ding Dian | Daiyu Zanghua |
| Ding Dian | Kuihua Baodian |
71 |
89 |
39 |
63 |
96 |
86 |
83 |
57 |
93 |
| Yu Yutong | Hamo Gong
|
| Yu Yutong | Dagou Bangfa |
| Shi Qing
| Xi Ren
| Xi Ren
| Hamo Gong
| Hamo Gong
|
|
| Dagou Bangfa |
| Lin Daiyu | Taiji Quan
|
| Lin Daiyu | Jinshe Jianfa |
+-------------+----------------+-------+
15 rows in set (0.000 sec)
MariaDB [hellodb]> select st.name,co.Course,sc.score from courses co inner
join scores sc on co.courseid=sc.courseid inner join students st on
sc.stuid=st.stuid;
+-------------+----------------+-------+
| name
| Course
| score |
+-------------+----------------+-------+
| Shi Zhongyu | Kuihua Baodian |
| Shi Zhongyu | Weituo Zhang |
| Shi Potian | Kuihua Baodian |
| Shi Potian | Daiyu Zanghua |
| Xie Yanke | Kuihua Baodian |
| Xie Yanke | Weituo Zhang |
| Ding Dian | Daiyu Zanghua |
| Ding Dian | Kuihua Baodian |
77 |
93 |
47 |
97 |
88 |
75 |
71 |
89 |
39 |
63 |
96 |
86 |
83 |
57 |
93 |
| Yu Yutong | Hamo Gong
|
| Yu Yutong | Dagou Bangfa |
| Shi Qing
| Xi Ren
| Xi Ren
| Hamo Gong
| Hamo Gong
|
|
| Dagou Bangfa |
| Lin Daiyu | Taiji Quan
|
| Lin Daiyu | Jinshe Jianfa |
+-------------+----------------+-------+
15 rows in set (0.001 sec)
MariaDB [hellodb]>
3.7.3 SELECT 语句处理的顺序
查询执行路径中的组件:查询缓存、解析器、预处理器、优化器、查询执行引擎、存储引擎
SELECT语句的执行流程:
FROM Clause --> WHERE Clause --> GROUP BY --> HAVING Clause -->SELECT --> ORDER
BY --> LIMIT
练习
导入hellodb.sql生成数据库
1. 在students表中,查询年龄大于25岁,且为男性的同学的名字和年龄
2. 以ClassID为分组依据,显示每组的平均年龄
3. 显示第2题中平均年龄大于30的分组及平均年龄
4. 显示以L开头的名字的同学的信息
5. 显示TeacherID非空的同学的相关信息
6. 以年龄排序后,显示年龄最大的前10位同学的信息
7. 查询年龄大于等于20岁,小于等于25岁的同学的信息
8. 以ClassID分组,显示每班的同学的人数
9. 以Gender分组,显示其年龄之和
10. 以ClassID分组,显示其平均年龄大于25的班级
11. 以Gender分组,显示各组中年龄大于25的学员的年龄之和
12. 显示前5位同学的姓名、课程及成绩
13. 显示其成绩高于80的同学的名称及课程
14. 取每位同学各门课的平均成绩,显示成绩前三名的同学的姓名和平均成绩
15. 显示每门课程课程名称及学习了这门课的同学的个数
16. 显示其年龄大于平均年龄的同学的名字
17. 显示其学习的课程为第1、2,4或第7门课的同学的名字
18. 显示其成员数最少为3个的班级的同学中年龄大于同班同学平均年龄的同学
19. 统计各班级中年龄大于全校同学平均年龄的同学
3.8 VIEW 视图
视图:虚拟表,保存有实表的查询结果,相当于别名
利用视图,可以隐藏表的真实结构,在程序中利用视图进行查询,可以避免表结构的变化,而修改程序,降低程
序和数据库之间的耦合度
创建方法:
CREATE
VIEW view_name [(column_list)]
AS select_statement
[WITH [CASCADED | LOCAL] CHECK OPTION]
查看视图定义:
SHOW CREATE VIEW view_name #只能看视图定义
SHOW CREATE TABLE view_name # 可以查看表和视图
删除视图:
DROP VIEW [IF EXISTS]
view_name [, view_name] ...
[RESTRICT | CASCADE]
注意:视图中的数据事实上存储于"基表"中,因此,其修改操作也会针对基表实现;其修改操作受基表
限制
范例:
MariaDB [hellodb]> create view v_st_co_sc as select st.name,co.Course,sc.score
from students st inner join scores sc on st.stuid=sc.stuid inner join courses co
on sc.courseid=co.CourseID;
MariaDB [hellodb]> SHOW TABLE STATUS LIKE 'v_st_co_sc'\G
*************************** 1. row ***************************
Name: v_st_co_sc
Engine: NULL
Version: NULL
Row_format: NULL
Rows: NULL
Avg_row_length: NULL
Data_length: NULL
Max_data_length: NULL
Index_length: NULL
Data_free: NULL
Auto_increment: NULL
Create_time: NULL
Update_time: NULL
Check_time: NULL
Collation: NULL
Checksum: NULL
Create_options: NULL
Comment: VIEW
Max_index_length: NULL
Temporary: NULL
1 row in set (0.001 sec)
MariaDB [hellodb]>
[root@centos8 ~]#ls /var/lib/mysql/hellodb/
classes.frm coc.ibd
v_old_student.frm
db.opt
students.frm teachers.ibd
classes.ibd courses.frm scores.frm students.ibd toc.frm
coc.frm courses.ibd scores.ibd teachers.frm toc.ibd
v_st_co_sc.frm
3.9 FUNCTION 函数
函数:分为系统内置函数和自定义函数
系统内置函数参考:
https://dev.mysql.com/doc/refman/8.0/en/sql-function-reference.html
https://dev.mysql.com/doc/refman/5.7/en/sql-function-reference.html
自定义函数:user-defined function UDF,保存在mysql.proc (MySQL8.0 中已经取消此表)表中
创建UDF语法
CREATE [AGGREGATE] FUNCTION function_name(parameter_name type,[parameter_name
type,...])
RETURNS {STRING|INTEGER|REAL}
runtime_body
说明:
参数可以有多个,也可以没有参数
无论有无参数,小括号()是必须的
必须有且只有一个返回值
查看函数列表:
SHOW FUNCTION STATUS;
查看函数定义
SHOW CREATE FUNCTION function_name
删除UDF
DROP FUNCTION function_name
调用自定义函数语法
SELECT function_name(parameter_value,...)
范例:
#无参UDF
CREATE FUNCTION simpleFun() RETURNS VARCHAR(20) RETURN "Hello World";
#有参数UDF
DELIMITER //
CREATE FUNCTION deleteById(id SMALLINT UNSIGNED) RETURNS VARCHAR(20)
BEGIN
DELETE FROM students WHERE stuid = id;
RETURN (SELECT COUNT(*) FROM students);
END//
DELIMITER ;
范例: MySQL8.0 默认开启二进制不允许创建函数
#默认MySQL8.0开启二进制日志,而不允许创建函数
mysql> CREATE FUNCTION simpleFun() RETURNS VARCHAR(20) RETURN "Hello World";
ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS
SQL DATA in its declaration and binary logging is enabled (you *might* want to
use the less safe log_bin_trust_function_creators variable)
mysql> select @@log_bin;
+-----------+
| @@log_bin |
+-----------+
|
1 |
+-----------+
1 row in set (0.00 sec)
mysql> show variables like 'log_bin_trust_function_creators';
+---------------------------------+-------+
| Variable_name
| Value |
+---------------------------------+-------+
| log_bin_trust_function_creators | OFF |
+---------------------------------+-------+
1 row in set (0.00 sec)
#打开此变量允许二进制日志信息函数创建
mysql> set global log_bin_trust_function_creators=ON;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE FUNCTION simpleFun() RETURNS VARCHAR(20) RETURN "Hello World";
Query OK, 0 rows affected (0.01 sec)
mysql> SHOW FUNCTION STATUS like 'simple%'\G
*************************** 1. row ***************************
Db: hellodb
Name: simpleFun
Type: FUNCTION
Definer: root@localhost
Modified: 2021-02-01 21:28:41
Created: 2021-02-01 21:28:41
Security_type: DEFINER
Comment:
character_set_client: utf8mb4
collation_connection: utf8mb4_0900_ai_ci
Database Collation: utf8_general_ci
1 row in set (0.00 sec)
范例: Mariadb10.3 默认没有开启二进制日志,所以可以创建函数
#Mariadb默认没有开启二进制日志,所以可以创建函数
[root@centos8 ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
log-bin
[root@centos8 ~]#systemctl restart mariadb
MariaDB [hellodb]> select @@log_bin;
+-----------+
| @@log_bin |
+-----------+
|
1 |
+-----------+
1 row in set (0.000 sec)
#开启二进制功能后,也不能创建函数
MariaDB [hellodb]> CREATE FUNCTION simpleFun() RETURNS VARCHAR(20) RETURN "Hello
World";
ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS
SQL DATA in its declaration and binary logging is enabled (you *might* want to
use the less safe log_bin_trust_function_creators variable)
MariaDB [hellodb]> show variables like 'log_bin_trust_function_creators';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| log_bin_trust_function_creators | OFF
|
+---------------------------------+-------+
1 row in set (0.001 sec)
#修改变量允许创建函数
MariaDB [hellodb]> set global log_bin_trust_function_creators=ON;
Query OK, 0 rows affected (0.000 sec)
MariaDB [hellodb]> CREATE FUNCTION simpleFun() RETURNS VARCHAR(20) RETURN "Hello
World";
Query OK, 0 rows affected (0.000 sec)
MariaDB [hellodb]> SHOW FUNCTION STATUS\G
*************************** 1. row ***************************
Db: hellodb
Name: simpleFun
Type: FUNCTION
Definer: root@localhost
Modified: 2021-02-01 21:32:23
Created: 2021-02-01 21:32:23
Security_type: DEFINER
Comment:
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: utf8_general_ci
1 row in set (0.001 sec)
MySQL中的变量
两种变量:系统内置变量和用户自定义变量
系统变量:MySQL数据库中内置的变量,可用@@var_name引用
用户自定义变量分为以下两种
普通变量:在当前会话中有效,可用@var_name引用
局部变量:在函数或存储过程内才有效,需要用DECLARE 声明,之后直接用 var_name引用
自定义函数中定义局部变量语法
DECLARE 变量1[,变量2,... ]变量类型 [DEFAULT 默认值]
说明:局部变量的作用范围是在BEGIN...END程序中,而且定义局部变量语句必须在BEGIN...END的第一
行定义
为变量赋值语法
SET parameter_name = value[,parameter_name = value...]
SELECT INTO parameter_name
范例:
DELIMITER //
CREATE FUNCTION addTwoNumber(x SMALLINT UNSIGNED, y SMALLINT UNSIGNED)
RETURNS SMALLINT
BEGIN
DECLARE a, b SMALLINT UNSIGNED;
SET a = x, b = y;
RETURN a+b;
END//
DELIMITER ;
范例:
.....
DECLARE x int;
SELECT COUNT(*) FROM tdb_name INTO x;
RETURN x;
END//
范例:自定义的普通变量
#方法1
MariaDB [hellodb]> select count(*) from students into @num ;
#方法2
MariaDB [hellodb]> select count(*) into @num from students;
#查看变量
MariaDB [hellodb]> select @num;
+------+
| @num |
+------+
|
24 |
+------+
1 row in set (0.000 sec)
3.10 PROCEDURE 存储过程
存储过程:多表SQL的语句的集合,可以独立执行,存储过程保存在mysql.proc表中
存储过程优势
存储过程把经常使用的SQL语句或业务逻辑封装起来,预编译保存在数据库中,当需要时从数据库中直接调
用,省去了编译的过程,提高了运行速度,同时降低网络数据传输量
存储过程与自定义函数的区别
存储过程实现的过程要复杂一些,而函数的针对性较强
存储过程可以有多个返回值,而自定义函数只有一个返回值
存储过程一般可独立执行,而函数往往是作为其他SQL语句的一部分来使用
无参数的存储过程执行过程中可以不加(),函数必须加 ( )
创建存储过程
CREATE PROCEDURE sp_name ([ proc_parameter [,proc_parameter ...]])
routime_body
proc_parameter : [IN|OUT|INOUT] parameter_name type
说明:其中IN表示输入参数,OUT表示输出参数,INOUT表示既可以输入也可以输出;param_name表
示参数名称;type表示参数的类型
查看存储过程列表
SHOW PROCEDURE STATUS;
查看存储过程定义
SHOW CREATE PROCEDURE sp_name
调用存储过程
CALL sp_name ([ proc_parameter [,proc_parameter ...]])
说明:当无参时,可以省略"()",当有参数时,不可省略"()"
存储过程修改
ALTER语句修改存储过程只能修改存储过程的注释等无关紧要的东西,不能修改存储过程体,所以要修改
存储过程,方法就是删除重建
删除存储过程
DROP PROCEDURE [IF EXISTS] sp_name
范例
# 创建无参存储过程
delimiter //
CREATE PROCEDURE showTime()
BEGIN
SELECT now();
END//
delimiter ;
CALL showTime;
范例
#创建含参存储过程:只有一个IN参数
delimiter //
CREATE PROCEDURE selectById(IN id SMALLINT UNSIGNED)
BEGIN
SELECT * FROM students WHERE stuid = id;
END//
delimiter ;
call selectById(2);
范例
delimiter //
CREATE PROCEDURE dorepeat(n INT)
BEGIN
SET @i = 0;
SET @sum = 0;
REPEAT SET @sum = @sum+@i;
SET @i = @i + 1;
UNTIL @i > n END REPEAT;
END//
delimiter ;
CALL dorepeat(100);
SELECT @sum;
范例
#创建含参存储过程:包含IN参数和OUT参数
delimiter //
CREATE PROCEDURE deleteById(IN id SMALLINT UNSIGNED, OUT num SMALLINT UNSIGNED)
BEGIN
DELETE FROM students WHERE stuid >= id;
SELECT row_count() into num;
END//
delimiter ;
call deleteById(20,@Line);
SELECT @Line;
#说明:创建存储过程deleteById,包含一个IN参数和一个OUT参数.调用时,传入删除的ID和保存被修改的行
数值的用户变量@Line,select @Line;输出被影响行数
#row_count() 系统内置函数,用于存放前一条SQL修改过的表的记录数
流程控制
存储过程和函数中可以使用流程控制来控制语句的执行
IF:用来进行条件判断。根据是否满足条件,执行不同语句
CASE:用来进行条件判断,可实现比IF语句更复杂的条件判断
LOOP:重复执行特定的语句,实现一个简单的循环
LEAVE:用于跳出循环控制,相当于SHELL中break
ITERATE:跳出本次循环,然后直接进入下一次循环,相当于SHELL中continue
REPEAT:有条件控制的循环语句。当满足特定条件时,就会跳出循环语句
WHILE:有条件控制的循环语句
3.11 TRIGGER 触发器
触发器的执行不是由程序调用,也不是由手工启动,而是由事件来触发、激活从而实现执行
创建触发器
CREATE [DEFINER = { user | CURRENT_USER }]
TRIGGER trigger_name
trigger_time trigger_event
ON tbl_name FOR EACH ROW
trigger_body
说明:
trigger_name:触发器的名称
trigger_time:{ BEFORE | AFTER },表示在事件之前或之后触发
trigger_event::{ INSERT |UPDATE | DELETE },触发的具体事件
tbl_name:该触发器作用在表名
范例:
#创建触发器,在向学生表INSERT数据时,学生数增加,DELETE学生时,学生数减少
CREATE TABLE student_info (
stu_id INT(11) NOT NULL AUTO_INCREMENT ,
stu_name VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (stu_id)
);
CREATE TABLE student_count (
student_count INT(11) DEFAULT 0
);
INSERT INTO student_count VALUES(0);
CREATE TRIGGER trigger_student_count_insert
AFTER INSERT
ON student_info FOR EACH ROW
UPDATE student_count SET student_count=student_count+1;
CREATE TRIGGER trigger_student_count_delete
AFTER DELETE
ON student_info FOR EACH ROW
UPDATE student_count SET student_count=student_count-1;
[root@centos8 ~]#cat /var/lib/mysql/hellodb/trigger_student_count_delete.TRN
TYPE=TRIGGERNAME
trigger_table=student_info
[root@centos8 ~]#cat /var/lib/mysql/hellodb/trigger_student_count_insert.TRN
TYPE=TRIGGERNAME
trigger_table=student_info
[root@centos8 ~]#cat /var/lib/mysql/hellodb/student_info.TRG
TYPE=TRIGGERS
triggers='CREATE DEFINER=`root`@`localhost` TRIGGER
trigger_student_count_insert\nAFTER INSERT\nON student_info FOR EACH ROW\nUPDATE
student_count SET student_count=student_count+1' 'CREATE
DEFINER=`root`@`localhost` TRIGGER trigger_student_count_delete\nAFTER DELETE\nON
student_info FOR EACH ROW\nUPDATE student_count SET student_count=student_count-
1'
sql_modes=1411383296 1411383296
definers='root@localhost' 'root@localhost'
client_cs_names='utf8' 'utf8'
connection_cl_names='utf8_general_ci' 'utf8_general_ci'
db_cl_names='utf8_general_ci' 'utf8_general_ci'
created=158207907828 158207907970
查看触发器
#在当前数据库对应的目录下,可以查看到新生成的相关文件:trigger_name.TRN,table_name.TRG
SHOW TRIGGERS;
#查询系统表information_schema.triggers的方式指定查询条件,查看指定的触发器信息。
USE information_schema;
SELECT * FROM triggers WHERE
trigger_name='trigger_student_count_insert';
删除触发器
DROP TRIGGER trigger_name;
3.12 Event 事件
3.12.1 Event 事件介绍
事件(event)是MySQL在相应的时刻调用的过程式数据库对象。一个事件可调用一次,也可周期性的
启动,它由一个特定的线程来管理的,也就是所谓的"事件调度器"。
事件和触发器类似,都是在某些事情发生的时候启动。当数据库上启动一条语句的时候,触发器就启动
了,而事件是根据调度事件来启动的。由于它们彼此相似,所以事件也称为临时性触发器。
事件取代了原先只能由操作系统的计划任务来执行的工作,而且MySQL的事件调度器可以精确到每秒钟
执行一个任务,而操作系统的计划任务(如:Linux下的CRON或Windows下的任务计划)只能精确到每
分钟执行一次。
事件的优缺点
优点:一些对数据定时性操作不再依赖外部程序,而直接使用数据库本身提供的功能,可以实现每秒钟
执行一个任务,这在一些对实时性要求较高的环境下就非常实用
缺点:定时触发,不可以直接调用
3.12.2 Event 管理
3.12.2.1 相关变量和服务器选项
MySQL事件调度器event_scheduler负责调用事件,它默认是关闭的。这个调度器不断地监视一个事件
是否要调用, 要创建事件,必须打开调度器
服务器系统变量和服务器选项:
event_scheduler:默认值为OFF,设置为ON才支持Event,并且系统自动打开专用的线程
范例:开启和关闭event_scheduler
#默认事件调度功能是关闭的,MySQL8.0默认是开启的
MariaDB [(none)]> select @@event_scheduler;
+-------------------+
| @@event_scheduler |
+-------------------+
| OFF
|
+-------------------+
1 row in set (0.000 sec)
#临时开启事件调度功能
MariaDB [(none)]> set global event_scheduler=1;
Query OK, 0 rows affected (0.000 sec)
#开启事件调度功能后,自启动一个event_scheduler线程
MariaDB [(none)]> show processlist;
+----+-----------------+-----------+------+---------+------+---------------------
-----+------------------+----------+
| Id | User
| Info
| Host
| db | Command | Time | State
| Progress |
+----+-----------------+-----------+------+---------+------+---------------------
-----+------------------+----------+
| 1 | system user
coordinator | NULL
| 4 | system user
| NULL
|
|
|
|
|
| NULL | Daemon | NULL | InnoDB purge
0.000 |
|
| NULL | Daemon | NULL | InnoDB purge worker
|
|
|
0.000 |
| NULL | Daemon | NULL | InnoDB purge worker
0.000 |
| NULL | Daemon | NULL | InnoDB purge worker
0.000 |
| NULL | Daemon | NULL | InnoDB shutdown
0.000 |
| localhost | NULL | Query |
0.000 |
| 10 | event_scheduler | localhost | NULL | Daemon |
queue | NULL 0.000 |
| 2 | system user
| NULL
| 3 | system user
| NULL
| 5 | system user
handler | NULL
| 9 | root
|
0 | Init
| show processlist |
4 | Waiting on empty
|
+----+-----------------+-----------+------+---------+------+---------------------
-----+------------------+----------+
7 rows in set (0.000 sec)
#临时关闭事件调度功能
MariaDB [(none)]> set global event_scheduler=0;
Query OK, 0 rows affected (0.000 sec)
MariaDB [(none)]> show processlist;
+----+-------------+-----------+------+---------+------+-------------------------
-+------------------+----------+
| Id | User
| Info
| Host
| db | Command | Time | State
| Progress |
+----+-------------+-----------+------+---------+------+-------------------------
-+------------------+----------+
| 1 | system user |
coordinator | NULL
| 4 | system user |
| NULL
| NULL | Daemon | NULL | InnoDB purge
0.000 |
| NULL | Daemon | NULL | InnoDB purge worker
0.000 |
| NULL | Daemon | NULL | InnoDB purge worker
0.000 |
| NULL | Daemon | NULL | InnoDB purge worker
0.000 |
| NULL | Daemon | NULL | InnoDB shutdown handler
0.000 |
|
|
|
|
|
| 2 | system user |
| NULL
| 3 | system user |
| NULL
| 5 | system user |
| NULL
| 9 | root
| localhost | NULL | Query |
0.000 |
0 | Init
| show processlist |
+----+-------------+-----------+------+---------+------+-------------------------
-+------------------+----------+
6 rows in set (0.000 sec)
#持久开启事件调度
[root@centos8 ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
event_scheduler=ON
[root@centos8 ~]#systemctl restart mariadb
3.12.2.2 管理事件
create event 语句创建一个事件。每个事件由两个主要部分组成,第一部分是事件调度(event
schedule),表示事件何时启动以及按什么频率启动,第二部分是事件动作(event action ),这是事
件启动时执行的代码,事件的动作包含一条SQL语句,它可能是一个简单地insert或者update语句,也
可以使一个存储过程或者 benin...end语句块,这两种情况允许我们执行多条SQL
一个事件可以是活动(打开)的或停止(关闭)的,活动意味着事件调度器检查事件动作是否必须调
用,停止意味着事件的声明存储在目录中,但调度器不会检查它是否应该调用。在一个事件创建之后,
它立即变为活动的,一个活动的事件可以执行一次或者多次
创建Event
CREATE
[DEFINER = { user | CURRENT_USER }]
EVENT
[IF NOT EXISTS]
event_name
ON SCHEDULE schedule
[ON COMPLETION [NOT] PRESERVE]
[ENABLE | DISABLE | DISABLE ON SLAVE]
[COMMENT 'comment']
DO event_body;
schedule:
AT timestamp [+ INTERVAL interval] ...
| EVERY interval
[STARTS timestamp [+ INTERVAL interval] ...]
[ENDS timestamp [+ INTERVAL interval] ...]
interval:
quantity {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |
WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |
DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}
说明:
event_name :创建的event名字,必须是唯一确定的
ON SCHEDULE:计划任务
schedule: 决定event的执行时间和频率(注意时间一定要是将来的时间,过去的时间会出错),有两种
形式 AT和EVERY
[ON COMPLETION [NOT] PRESERVE]: 可选项,默认是ON COMPLETION NOT PRESERVE 即计划任
务执行完毕后自动drop该事件;ON COMPLETION PRESERVE则不会drop掉
[COMMENT 'comment'] :可选项,comment 用来描述event;相当注释,最大长度64个字节
[ENABLE | DISABLE] :设定event的状态,默认ENABLE:表示系统尝试执行这个事件, DISABLE:关
闭该事情,可以用alter修改
DO event_body: 需要执行的sql语句,可以是复合语句
提示:event事件是存放在mysql.event表中
查看Event
SHOW EVENTS [{FROM | IN} schema_name]
[LIKE 'pattern' | WHERE expr]
注意:事件执行完即释放,如立即执行事件,执行完后,事件便自动删除,多次调用事件或等待执行事
件,才可以用上述命令查看到。
修改Event
ALTER
[DEFINER = { user | CURRENT_USER }]
EVENT event_name
[ON SCHEDULE schedule]
[ON COMPLETION [NOT] PRESERVE]
[RENAME TO new_event_name]
[ENABLE | DISABLE | DISABLE ON SLAVE]
[COMMENT 'comment']
[DO event_body]
注意:alter event语句可以修改事件的定义和属性。可以让一个事件成为停止的或者再次让它活动,也
可以修改一个事件的名字或者整个调度。然而当一个使用 ON COMPLETION NOT PRESERVE 属性定义
的事件最后一次执行后,事件直接就不存在了,不能修改
删除Event
DROP EVENT [IF EXISTS] event_name
3.12.2.3 范例
范例:创建每秒启动的事件
MariaDB [(none)]> create database testdb;
Query OK, 1 row affected (0.000 sec)
MariaDB [(none)]> use testdb
Database changed
#创建一个表记录每次事件调度的名字和事件戳
MariaDB [testdb]> create table events_list(event_name varchar(20) not null,
event_started timestamp not null);
Query OK, 0 rows affected (0.005 sec)
#任务计划存放在mysql.event表中
MariaDB [testdb]> select * from mysql.event\G
*************************** 1. row ***************************
db: testdb
name: event_now
body: insert into events_list values('event_now', now())
definer: root@localhost
execute_at: 2020-02-19 02:46:04
interval_value: NULL
interval_field: NULL
created: 2020-02-19 10:46:04
modified: 2020-02-19 10:46:04
last_executed: NULL
starts: NULL
ends: NULL
status: ENABLED
on_completion: DROP
sql_mode:
STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUB
STITUTION
comment:
originator: 1
time_zone: SYSTEM
character_set_client: utf8
collation_connection: utf8_general_ci
db_collation: latin1_swedish_ci
body_utf8: insert into events_list values('event_now', now())
1 row in set (0.000 sec)
MariaDB [testdb]>
#开启事件调度功能
MariaDB [testdb]> set global event_scheduler=1;
MariaDB [testdb]> CREATE EVENT event_every_second
ON SCHEDULE
EVERY 1 SECOND
DO INSERT INTO events_list VALUES('event_now', now());
MariaDB [testdb]> SHOW EVENTS\G
*************************** 1. row ***************************
Db: testdb
Name: event_every_second
Definer: root@localhost
Time zone: SYSTEM
Type: RECURRING
Execute at: NULL
Interval value: 1
Interval field: SECOND
Starts: 2019-12-02 22:26:52
Ends: NULL
Status: ENABLED
Originator: 1
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: latin1_swedish_ci
1 row in set (0.002 sec)
#事件是存放在mysql.event表中
MariaDB [testdb]> select * from mysql.event\G
*************************** 1. row ***************************
db: testdb
name: event_every_second
body: INSERT INTO events_list VALUES('event_now', now())
definer: root@localhost
execute_at: NULL
interval_value: 1
interval_field: SECOND
created: 2019-12-02 22:26:52
modified: 2019-12-02 22:26:52
last_executed: 2019-12-02 14:30:06
starts: 2019-12-02 14:26:52
ends: NULL
status: ENABLED
on_completion: DROP
sql_mode:
STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUB
STITUTION
comment:
originator: 1
time_zone: SYSTEM
character_set_client: utf8
collation_connection: utf8_general_ci
db_collation: latin1_swedish_ci
body_utf8: INSERT INTO events_list VALUES('event_now', now())
1 row in set (0.000 sec)
MariaDB [testdb]> select *from events_list;
+------------+---------------------+
| event_name | event_started
|
+------------+---------------------+
| event_now | 2019-12-02 22:07:11 |
| event_now | 2019-12-02 22:26:52 |
| event_now | 2019-12-02 22:26:53 |
| event_now | 2019-12-02 22:26:54 |
| event_now | 2019-12-02 22:26:55 |
| event_now | 2019-12-02 22:26:56 |
| event_now | 2019-12-02 22:26:57 |
| event_now | 2019-12-02 22:26:58 |
| event_now | 2019-12-02 22:26:59 |
| event_now | 2019-12-02 22:27:00 |
| event_now | 2019-12-02 22:27:01 |
| event_now | 2019-12-02 22:27:02 |
| event_now | 2019-12-02 22:27:03 |
| event_now | 2019-12-02 22:27:04 |
| event_now | 2019-12-02 22:27:05 |
| event_now | 2019-12-02 22:27:06 |
| event_now | 2019-12-02 22:27:07 |
| event_now | 2019-12-02 22:27:08 |
| event_now | 2019-12-02 22:27:09 |
| event_now | 2019-12-02 22:27:10 |
+------------+---------------------+
20 rows in set (0.000 sec)
MariaDB [testdb]> drop event event_every_second;
Query OK, 0 rows affected (0.000 sec)
MariaDB [testdb]> SHOW EVENTS\G
Empty set (0.001 sec)
MariaDB [testdb]> select * from mysql.event\G
Empty set (0.000 sec)
3.13 MySQL 用户管理
相关数据库和表
元数据数据库:mysql
系统授权表:db, host, user,columns_priv, tables_priv, procs_priv, proxies_priv
用户帐号:
'USERNAME'@'HOST'
@'HOST': 主机名: user1@'web1.magedu.org'
IP地址或Network
通配符: % _
示例:wang@'172.16.%.%'
user2@'192.168.1.%'
mage@'10.0.0.0/255.255.0.0'
创建用户:CREATE USER
CREATE USER 'USERNAME'@'HOST' [IDENTIFIED BY 'password'];
#示例:
create user test@'10.0.0.0/255.255.255.0' identified by '123456';
create user test2@'10.0.0.%' identified by 123456;
新建用户的默认权限:USAGE
用户重命名:RENAME USER
RENAME USER old_user_name TO new_user_name;
删除用户:
DROP USER 'USERNAME'@'HOST'
范例:删除默认的空用户
DROP USER ''@'localhost';
修改密码:
注意:
新版mysql中用户密码可以保存在mysql.user表的authentication_string字段中
如果mysql.user表的authentication_string和password字段都保存密码,authentication_string
优先生效
#方法1,用户可以也可通过此方式修改自已的密码
SET PASSWORD FOR 'user'@'host' = PASSWORD('password'); #MySQL8.0 版本不支持此方法,
因为password函数被取消
set password for root@'localhost'='123456' ; #MySQL8.0版本支持此方法,此方式直接将密码
123456加密后存放在mysql.user表的authentication_string字段
#方法2
ALTER USER test@'%' IDENTIFIED BY 'centos'; #通用改密码方法, 用户可以也可通过此方式修
改自已的密码,MySQL8 版本修改密码
#方法3 此方式MySQL8.0不支持,因为password函数被取消
UPDATE mysql.user SET password=PASSWORD('password') WHERE clause;
#mariadb 10.3
update mysql.user set authentication_string=password('ubuntu') where
user='mage';
#此方法需要执行下面指令才能生效:
FLUSH PRIVILEGES;
忘记管理员密码的解决办法:
1. 启动mysqld进程时,为其使用如下选项:
--skip-grant-tables
--skip-networking
2. 使用UPDATE命令修改管理员密码
3. 关闭mysqld进程,移除上述两个选项,重启mysqld
范例:Mariadb 和MySQL5.6版之前破解root密码
[root@centos8 ~]#vim /etc/my.cnf
[mysqld]
skip-grant-tables
skip-networking
[root@centos8 ~]#systemctl restart mysqld|mariadb
[root@centos8 ~]#mysql
#方法1
#mariadb 旧版和MySQL5.6版之前
MariaDB [(none)]> update mysql.user set password=password('ubuntu') where
user='root';
#mariadb 新版
MariaDB [(none)]> update mysql.user set authentication_string=password('ubuntu')
where user='root';
#方法2
MariaDB [(none)]> flush privileges;
MariaDB [(none)]> alter user root@'localhost' identified by 'ubuntu';
[root@centos8 ~]#vim /etc/my.cnf
[mysqld]
#skip-grant-tables
#skip-networking
[root@centos8 ~]#systemctl restart mysqld|mariadb
[root@centos8 ~]#mysql -uroot -pubuntu
范例: MySQL5.7和8.0 破解root密码
[root@centos8 ~]#vim /etc/my.cnf
[mysqld]
skip-grant-tables
skip-networking #MySQL8.0不需要
[root@centos8 ~]#systemctl restart mysqld
#方法1
mysql> update mysql.user set authentication_string='' where user='root' and
host='localhost';
#方法2
mysql> flush privileges;
#再执行下面任意一个命令
mysql> alter user root@'localhost' identified by 'ubuntu';
mysql> set password for root@'localhost'='ubuntu';
[root@centos8 ~]#vim /etc/my.cnf
[mysqld]
#skip-grant-tables
#skip-networking
[root@centos8 ~]#systemctl restart mysqld
[root@centos8 ~]#mysql -uroot -pubuntu
范例: 删库跑路之清空root密码方法
#此方法适用于包安装方式的MySQL或Mariadb
[root@centos8 ~]#systemctl stop mysqld
[root@centos8 ~]#rm -rf /var/lib/mysql/*
[root@centos8 ~]#systemctl start mysqld
3.14 权限管理和DCL语句
3.14.1 权限类别
权限类别:
管理类
程序类
数据库级别
表级别
字段级别
管理类:
CREATE USER
FILE
SUPER
SHOW DATABASES
RELOAD
SHUTDOWN
REPLICATION SLAVE
REPLICATION CLIENT
LOCK TABLES
PROCESS
CREATE TEMPORARY TABLES
程序类:针对 FUNCTION、PROCEDURE、TRIGGER
CREATE
ALTER
DROP
EXCUTE
库和表级别:针对 DATABASE、TABLE
ALTER
CREATE
CREATE VIEW
DROP INDEX
SHOW VIEW
WITH GRANT OPTION:能将自己获得的权限转赠给其他用户
数据操作
SELECT
INSERT
DELETE
UPDATE
字段级别
SELECT(col1,col2,...)
UPDATE(col1,col2,...)
INSERT(col1,col2,...)
所有权限
ALL PRIVILEGES 或 ALL
3.14.2 授权
授权:GRANT
GRANT priv_type [(column_list)],... ON [object_type] priv_level TO 'user'@'host'
[IDENTIFIED BY 'password'] [WITH GRANT OPTION];
priv_type: ALL [PRIVILEGES]
object_type:TABLE | FUNCTION | PROCEDURE
priv_level: *(所有库) |*.* | db_name.* | db_name.tbl_name | tbl_name(当前库的
表) | db_name.routine_name(指定库的函数,存储过程,触发器)
with_option: GRANT OPTION
| MAX_QUERIES_PER_HOUR count
| MAX_UPDATES_PER_HOUR count
| MAX_CONNECTIONS_PER_HOUR count
| MAX_USER_CONNECTIONS count
参考:https://dev.mysql.com/doc/refman/5.7/en/grant.html
范例:
GRANT SELECT (col1), INSERT (col1,col2) ON mydb.mytbl TO 'someuser'@'somehost';
GRANT ALL ON wordpress.* TO wordpress@'10.0.0.%' ;
GRANT ALL PRIVILEGES ON *.* TO 'root'@'10.0.0.%' WITH GRANT OPTION;
#创建用户和授权同时执行的方式在MySQL8.0取消了
GRANT ALL ON wordpress.* TO wordpress@'192.168.8.%' IDENTIFIED BY 'magedu';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.8.%' IDENTIFIED BY 'magedu'
WITH GRANT OPTION;
3.14.3 取消权限
取消授权:REVOKE
REVOKE priv_type [(column_list)] [, priv_type [(column_list)]] ... ON
[object_type] priv_level FROM user [, user] ...
参考:https://dev.mysql.com/doc/refman/5.7/en/revoke.html
范例:
REVOKE DELETE ON *.* FROM 'testuser'@'172.16.0.%';
3.14.4 查看指定用户获得的授权
Help SHOW GRANTS
SHOW GRANTS FOR 'user'@'host';
SHOW GRANTS FOR CURRENT_USER[()];
注意:
MariaDB服务进程启动时会读取mysql库中所有授权表至内存
(1) GRANT或REVOKE等执行权限操作会保存于系统表中,MariaDB的服务进程通常会自动重读授权表,
使之生效
(2) 对于不能够或不能及时重读授权表的命令,可手动让MariaDB的服务进程重读授权表:
mysql> FLUSH PRIVILEGES;
3.15 MySQL的图形化的远程管理工具
在MySQL数据库中创建用户并授权后,可以使用相关图形化工具进行远程的管理。
常见的图形化管理工具:
Navicat
SQLyog
3.15.1 Navicat 工具
3.15.2 SQLyog 工具
范例:
#先创建用户并授权
GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.8.%' IDENTIFIED BY 'magedu' WITH
GRANT OPTION;
4 MySQL 架构和性能优化
MySQL是C/S 架构的,connectors是连接器;可供Native C API、JDBC、ODBC、NET、PHP、Perl、
Python、Ruby、Cobol等连接mysql;ODBC叫开放数据库(系统)互联,open database
connection;JDBC是主要用于java语言利用较为底层的驱动连接数据库;以上这些,站在编程角度可以
理解为连入数据库管理系统的驱动,站在mysql角度称作专用语言对应的链接器.
任何链接器连入mysql以后,mysql是单进程多线程模型的,因此,每个用户连接,都会创建一个单独的
连接线程;其实mysql连接也有长短连接两种方式,使用mysql客户端连入数据库后,直到使用quit命令
才退出,可认为是长连接;使用mysql中的-e选项,在mysql客户端向服务器端申请运行一个命令后则立
即退出,也就意味着连接会立即断开;所以,mysql也支持长短连接类似于两种类型;所以,用户连入
mysql后,创建一个连接线程,完成之后,能够通过这个连接线程完成接收客户端发来的请求,为其处
理请求,构建响应报文并发给客户端;由于是单进程模型,就意味着必须要维持一个线程池,跟之前介
绍过的varnish很接近,需要一个线程池来管理这众多线程是如何对众多客户端的并发请求,完成并发响
应的,组件connection pool就是实现这样功能;connection pool对于mysql而言,它所实现的功能,
包括authentication认证,用户发来的账号密码是否正确要完成认证功能;thread reuse线程重用功
能,一般当一个用户连接进来以后要用一个线程来响应它,而后当用户退出这个线程有可能并非被销
毁,而是把它清理完以后,重新收归到线程池当中的空闲线程中去,以完成所谓的线程重用;
connection limit 线程池的大小决定了连接并发数量的上限,例如,最多容纳100线程,一旦到达此上限
后续到达的连接请求则只能排队或拒绝连接;check memory用来检测内存,caches实现线程缓存;整
个都属于线程池的功能.当用户请求之后,通过线程池建立一个用户连接,这个线程一直存在,然后用户
就通过这个会话,发送对应的SQL语句到服务器端.
服务器收到SQL语句后,要对语句完成执行,首先要能理解sql语句需要有sql解释器或叫sql接口sql
interface就可理解为是整个mysql的外壳,就像shell是linux操作系统的外壳一样;用户无论通过哪种链
接器发来的基本的SQL请求,当然,事实上通过native C API也有发过来的不是SQL 请求,而仅仅是对
API中的传递参数后的调用;不是SQL语句不过都统统理解为sql语句罢了;对SQL而言分为DDL 和DML
两种类型,但是无论哪种类型,提交以后必须交给内核,让内核来运行,在这之前必须要告诉内核哪个
是命令,哪个是选项,哪些是参数,是否存在语法错误等等;因此,这个整个SQL 接口就是一个完完整
整的sql命令的解释器,并且这个sql接口还有提供完整的sql接口应该具备的功能,比如支持所谓过程式
编程,支持代码块的实现像存储过程、存储函数,触发器、必要时还要实现部署一个关系型数据库应该
具备的基本组件例如视图等等,其实都在sql interface这个接口实现的;SQL接口做完词法分析、句法分
析后,要分析语句如何执行让parser解析器或分析器实现
parser是专门的分析器,这个分析器并不是分析语法问题的,语法问题在sql接口时就能发现是否有错误
了,一个语句没有问题,就要做执行分析,所谓叫查询翻译,把一个查询语句给它转换成对应的能够在
本地执行的特定操作;比如说看上去是语句而背后可能是执行的一段二进制指令,这个时候就完成对应
的指令,还要根据用户请求的对象,比如某一字段查询内容是否有对应数据的访问权限,或叫对象访问
权限;在数据库中库、表、字段、字段中的数据有时都称为object,叫一个数据库的对象,用户认证的
通过,并不意味着就能一定能访问数据库上的所有数据,所以说,mysql的认证大概分为两过程都要完
成,第一是连入时需要认证账号密码是否正确这是authentication,然后,验证成功后用户发来sql语句
还要验证用户是否有权限获取它期望请求获取的数据;这个称为object privilege,这一切都是由parser
分析器进行的
分析器分析完成之后,可能会生成多个执行树,这意味着为了能够达到访问期望访问到的目的,可能有
多条路径都可实现,就像文件系统一样可以使用相对路径也可使用绝对路径;它有多种方式,在多种路
径当中一定有一个是最优的,类似路由选择,因此,优化器就要去衡量多个访问路径中哪一个代价或开
销是最小的,这个开销的计算要依赖于索引等各种内部组件来进行评估;而且这个评估的只是近似值,
同时还要考虑到当前mysql内部在实现资源访问时统计数据,比如,根据判断认为是1号路径的开销最小
的,但是众多统计数据表明发往1号路径的访问的资源开销并不小,并且比3号路径大的多,因此,可能
会依据3号路径访问;这就是所谓的优化器它负责检查多条路径,每条路径的开销,然后评估开销,这个
评估根据内部的静态数据,索引,根域根据动态生成的统计数据来判定每条路径的开销大小,因此这里
还有statics;一旦优化完成之后,还要生成统计数据,这就是优化器的作用;如果没有优化器mysql执
行语句是最慢的,其实优化还包括一种功能,一旦选择完一条路径后,例如用户给的这个命令执行起
来,大概需要100个开销,如果通过改写语句能够达到同样目的可能只需要30个开销;于是,优化器还
要试图改写sql语句;所以优化本身还包括查询语句的改写;一旦优化完成,接下来就交给存储引擎完成.
mysql是插件式存储引擎,它就能够替换使用选择多种不同的引擎,MyISAM是MySQL 经典的存储引擎
之一,InnoDB是由Innobase Oy公司所开发,2006年五月由甲骨文公司并购提供给MySQL的,NDB主
要用于MySQL Cluster 分布式集群环境,archive做归档的等等,还有许多第三方开发的存储引擎;存储
引擎负责把具体分析的结果完成对磁盘上文件路径访问的转换,数据库中的行数据都是存储在磁盘块上
的,因此存储引擎要把数据库数据映射为磁盘块,并把磁盘块加载至内存中;进程实现数据处理时,是
不可能直接访问磁盘上的数据的,因为它没有权限,只有让内核来把它所访问的数据加载至内存中以
后,进程在内存中完成修改,由内核再负责把数据存回磁盘;对于文件系统而言,数据的存储都是以磁
盘块方式存储的,但是,mysql在实现数据组织时,不完全依赖于磁盘,而是把磁盘块再次组织成更大
一级的逻辑单位,类似于lvm中的PE或LE的形式;其实,MySQL的存储引擎在实现数据管理时,也是在
文件系统之上布设文件格式,对于文件而言在逻辑层上还会再次组织成一个逻辑单位,这个逻辑单位称
为mysql的数据块datablock 一般为16k ,对于关系型数据库,数据是按行存储的;一般一行数据都是存
储在一起的,因此,MySQL 在内部有一个datablock,在datablock可能存储一行数据,也可能存放了n
行数据;将来在查询加载一行数据时,内核会把整个一个数据数据块加载至内存中,而mysql存储引
擎,就从中挑出来某一行返回给查询者,是这样实现的;所以整个存储是以datablock在底层为其最终级
别的.
事实上,整个存取过程,尤其是访问比较热点的数据,也不可能每一次当用户访问时或当某SQL语句用
到时再临时从磁盘加载到内存中,因此,为了能够加上整个性能,mysql的有些存储引擎可以实现,把
频繁访问到的热点数据,统统装入内存,用户访问、修改时直接在内存中操作,只不过周期性的写入磁
盘上而已,比如像InnoDB,所以caches和buffers组件就是实现此功能的;MySQL为了执行加速,因为
它会不断访问数据,而随计算机来说io是最慢的一环,尤其是磁盘io,所以为了加速都载入内存中管
理;这就需要MySQL 维护cache和buffer缓存或缓冲;这是由MySQL 服务器自己维护的;有很多存储引
擎自己也有cache和buffer
一个数据库提供了3种视图,物理视图就是看到的对应的文件系统存储为一个个的文件,MySQL的数据
文件类型,常见的有redo log重做日志,undo log撤销日志,data是真正的数据文件,index是索引文
件,binary log是二进制日志文件,error log错误日志,query log查询日志,slow query log慢查询日
志,在复制架构中还存在中继日志文件,跟二进制属于同种格式;这是mysql数据文件类型,也就是物
理视图;逻辑视图这是在mysql接口上通过存储引擎把mysql文件尤其是data文件,给它映射为一个个
关系型数据库应该具备组成部分,比如表,一张表在底层是一个数据文件而已,里面组织的就是
datablock,最终映射为磁盘上文件系统的block,然后再次映射为本地扇区的存储,但是整个mysql需
要把他们映射成一个二维关系表的形式,需要依赖sql接口以及存储引擎共同实现;所以,把底层数据文
件映射成关系型数据库的组件就是逻辑视图;DBA 就是关注内部组件是如何运作的,并且定义、配置其
运作模式,而链接器都是终端用户通过链接器的模式进入数据库来访问数据;数据集可能非常大,每一
类用户可能只有一部分数据的访问权限,这个时候,最终的终端用户所能访问到的数据集合称作用户视
图;
为了保证MySQL运作还提供了管理和服务工具,例如:备份恢复工具,安全工具,复制工具,集群服务,
管理、配置、迁移、元数据等工具
4.1 存储引擎
MySQL中的数据用各种不同的技术存储在文件(或者内存)中。这些技术中的每一种技术都使用不同的
存储机制、索引技巧、锁定水平并且最终提供广泛的不同的功能和能力,此种技术称为存储擎,MySQL 支
持多种存储引擎其中目前应用最广泛的是InnoDB和MyISAM两种
官方参考资料:
https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/storage-engines.html
https://docs.oracle.com/cd/E17952_01/mysql-5.7-en/storage-engines.html
4.1.1 MyISAM 存储引擎
MyISAM 引擎特点
不支持事务
表级锁定
读写相互阻塞,写入不能读,读时不能写
只缓存索引
不支持外键约束
不支持聚簇索引
读取数据较快,占用资源较少
不支持MVCC(多版本并发控制机制)高并发
崩溃恢复性较差
MySQL5.5.5 前默认的数据库引擎
MyISAM 存储引擎适用场景
只读(或者写较少)
表较小(可以接受长时间进行修复操作)
MyISAM 引擎文件
tbl_name.frm 表格式定义
tbl_name.MYD 数据文件
tbl_name.MYI 索引文件
4.1.2 InnoDB 引擎
InnoDB引擎特点
行级锁
支持事务,适合处理大量短期事务
读写阻塞与事务隔离级别相关
可缓存数据和索引
支持聚簇索引
崩溃恢复性更好
支持MVCC高并发
从MySQL5.5后支持全文索引
从MySQL5.5.5开始为默认的数据库引擎
InnoDB数据库文件
所有InnoDB表的数据和索引放置于同一个表空间中
数据文件:ibdata1, ibdata2,存放在datadir定义的目录下
表格式定义:tb_name.frm,存放在datadir定义的每个数据库对应的目录下
每个表单独使用一个表空间存储表的数据和索引
两类文件放在对应每个数据库独立目录中
数据文件(存储数据和索引):tb_name.ibd
表格式定义:tb_name.frm
启用:innodb_file_per_table=ON (MariaDB 5.5以后版是默认值)
参看:https://mariadb.com/kb/en/library/xtradbinnodb-server-system-variables/#innodb_file_pe
r_table
4.1.3 其它存储引擎
Performance_Schema:Performance_Schema数据库使用
Memory :将所有数据存储在RAM中,以便在需要快速查找参考和其他类似数据的环境中进行快
速访问。适用存放临时数据。引擎以前被称为HEAP引擎
MRG_MyISAM:使MySQL DBA或开发人员能够对一系列相同的MyISAM表进行逻辑分组,并将它
们作为一个对象引用。适用于VLDB(Very Large Data Base)环境,如数据仓库
Archive :为存储和检索大量很少参考的存档或安全审核信息,只支持SELECT和INSERT操作;支
持行级锁和专用缓存区
Federated联合:用于访问其它远程MySQL服务器一个代理,它通过创建一个到远程MySQL服务器
的客户端连接,并将查询传输到远程服务器执行,而后完成数据存取,提供链接单独MySQL服务器
的能力,以便从多个物理服务器创建一个逻辑数据库。非常适合分布式或数据集市环境
BDB:可替代InnoDB的事务引擎,支持COMMIT、ROLLBACK和其他事务特性
Cluster/NDB:MySQL的簇式数据库引擎,尤其适合于具有高性能查找要求的应用程序,这类查找
需求还要求具有最高的正常工作时间和可用性
CSV:CSV存储引擎使用逗号分隔值格式将数据存储在文本文件中。可以使用CSV引擎以CSV格式导
入和导出其他软件和应用程序之间的数据交换
BLACKHOLE :黑洞存储引擎接受但不存储数据,检索总是返回一个空集。该功能可用于分布式数
据库设计,数据自动复制,但不是本地存储
example:"stub"引擎,它什么都不做。可以使用此引擎创建表,但不能将数据存储在其中或从中
检索。目的是作为例子来说明如何开始编写新的存储引擎
4.1.4 管理存储引擎
查看mysql支持的存储引擎
show engines;
查看当前默认的存储引擎
show variables like '%storage_engine%';
设置默认的存储引擎
vim /etc/my.cnf
[mysqld]
default_storage_engine= InnoDB
查看库中所有表使用的存储引擎
show table status from db_name;
查看库中指定表的存储引擎
show table status like 'tb_name';
show create table tb_name;
设置表的存储引擎:
CREATE TABLE tb_name(... ) ENGINE=InnoDB;
ALTER TABLE tb_name ENGINE=InnoDB;
4.2 MySQL 中的系统数据库
mysql 数据库
是mysql的核心数据库,类似于Sql Server中的master库,主要负责存储数据库的用户、权限设置、关
键字等mysql自己需要使用的控制和管理信息
information_schema 数据库
MySQL 5.0之后产生的,一个虚拟数据库,物理上并不存在information_schema数据库类似与"数据字
典",提供了访问数据库元数据的方式,即数据的数据。比如数据库名或表名,列类型,访问权限(更加
细化的访问方式)
performance_schema 数据库
MySQL 5.5开始新增的数据库,主要用于收集数据库服务器性能参数,库里表的存储引擎均为
PERFORMANCE_SCHEMA,用户不能创建存储引擎为PERFORMANCE_SCHEMA的表
sys 数据库
MySQL5.7之后新增加的数据库,库中所有数据源来自performance_schema。目标是把
performance_schema的把复杂度降低,让DBA能更好的阅读这个库里的内容。让DBA更快的了解
DataBase的运行情况
4.3 服务器配置和状态
可以通过mysqld选项,服务器系统变量和服务器状态变量进行MySQL的配置和查看状态
官方帮助:
https://dev.mysql.com/doc/refman/8.0/en/server-option-variable-reference.html
https://dev.mysql.com/doc/refman/5.7/en/server-option-variable-reference.html
https://mariadb.com/kb/en/library/full-list-of-mariadb-options-system-and-
status-variables/
注意:
其中有些参数支持运行时修改,会立即生效
有些参数不支持动态修改,且只能通过修改配置文件,并重启服务器程序生效
有些参数作用域是全局的,为所有会话设置
有些可以为每个用户提供单独(会话)的设置
4.3.1 服务器选项
注意: 服务器选项用横线,不用下划线
获取mysqld的可用选项列表:
#查看mysqld可用选项列表和及当前值
mysqld --verbose --help
#获取mysqld当前启动选项
mysqld --print-defaults
范例:
#查看可用选项列表和当前值
[root@centos8 ~]#/usr/libexec/mysqld --verbose --help
#查看mysqld的当前启动选项
[root@centos8 ~]#/usr/libexec/mysqld --print-defaults
/usr/libexec/mysqld would have been started with the following arguments:
--plugin-load-add=auth_gssapi.so --datadir=/var/lib/mysql --
socket=/var/lib/mysql/mysql.sock --log-error=/var/log/mariadb/mariadb.log --pid-
file=/run/mariadb/mariadb.pid
设置服务器选项方法:
1. 在命令行中设置
shell> /usr/bin/mysqld_safe --skip-name-resolve=1
shell> /usr/libexec/mysqld --basedir=/usr
2.在配置文件my.cnf中设置
范例:
vim /etc/my.cnf
[mysqld]
skip_name_resolve=1
skip-grant-tables
范例: skip-grant-tables是服务器选项,但不是系统变量
[root@centos8 ~]#mysqladmin variables |grep skip_grant_tables
[root@centos8 ~]#mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 12
Server version: 10.3.17-MariaDB MariaDB Server
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> show variables like 'skip_grant_tables';
Empty set (0.001 sec)
4.3.2 服务器系统变量
服务器系统变量:可以分全局和会话两种
注意: 系统变量用下划线,不用横线
获取系统变量
SHOW GLOBAL VARIABLES; #只查看global变量
SHOW [SESSION] VARIABLES;#查看所有变量(包括global和session)
#查看指定的系统变量
SHOW VARIABLES LIKE 'VAR_NAME';
SELECT @@VAR_NAME;
#查看选项和部分变量
[root@centos8 ~]#mysqladmin variables
修改服务器变量的值:
help SET
修改全局变量:仅对修改后新创建的会话有效;对已经建立的会话无效
SET GLOBAL system_var_name=value;
SET @@global.system_var_name=value;
修改会话变量:
SET [SESSION] system_var_name=value;
SET @@[session.]system_var_name=value;
范例: character_set_results是系统变量并非服务器选项
[root@centos8 ~]#mysql
MariaDB [(none)]> show variables like 'character_set_results';
+-----------------------+-------+
| Variable_name
+-----------------------+-------+
| character_set_results | utf8
| Value |
|
+-----------------------+-------+
1 row in set (0.001 sec)
MariaDB [(none)]> set character_set_results="utf8mb4";
Query OK, 0 rows affected (0.000 sec)
MariaDB [(none)]> show variables like 'character_set_results';
+-----------------------+---------+
| Variable_name
| Value
|
+-----------------------+---------+
| character_set_results | utf8mb4 |
+-----------------------+---------+
1 row in set (0.001 sec)
[root@centos8 ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
character_set_results=utf8mb4
#character_set_results不是服务器选项,写入配置文件将导致无法启动
[root@centos8 ~]#systemctl restart mariadb
Job for mariadb.service failed because the control process exited with error
code.
See "systemctl status mariadb.service" and "journalctl -xe" for details.
范例:修改mysql的最大并发连接数
注意: CentOS 8.2 已无此问题,CentOS7 仍有此问题
#默认值为151
[root@centos8 ~]#mysqladmin variables |grep 'max_connections'
| max_connections
| 151
[root@centos8 ~]#mysql
MariaDB [(none)]> show variables like 'max_connections';
+-----------------+-------+
| Variable_name
+-----------------+-------+
| max_connections | 151
| Value |
|
+-----------------+-------+
1 row in set (0.001 sec)
MariaDB [hellodb]> set global max_connections=2000;
Query OK, 0 rows affected (0.000 sec)
MariaDB [hellodb]> show variables like 'max_connections';
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| max_connections | 2000 |
+-----------------+-------+
1 row in set (0.001 sec)
[root@centos8 ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
max_connections = 8000
[root@centos8 ~]#systemctl restart mariadb
[root@centos8 ~]#mysql -uroot -p
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 9
Server version: 10.3.11-MariaDB-log MariaDB Server
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> select @@max_connections;
+-------------------+
| @@max_connections |
+-------------------+
|
594 |
+-------------------+
1 row in set (0.000 sec)
#方法1
[root@centos8 ~]#vim /usr/lib/systemd/system/mariadb.service
[Service]
#加下面一行
LimitNOFILE=65535
#方法2
[root@centos8 ~]#mkdir /etc/systemd/system/mariadb.service.d/
[root@node3 ~]#vim /etc/systemd/system/mariadb.service.d/limits.conf
[Service]
LimitNOFILE=65535
[root@centos8 ~]#systemctl daemon-reload
[root@centos8 ~]#systemctl restart mariadb
[root@centos8 ~]#mysql -uroot -p -e "select @@max_connections"
Enter password:
+-------------------+
| @@max_connections |
+-------------------+
|
8000 |
+-------------------+
范例:修改页大小
参看:https://mariadb.com/kb/en/innodb-system-variables/#innodb_page_size
说明:初始化数据目录后,不能更改此系统变量的值。 在MariaDB实例启动时设置InnoDB的页面大
小,此后保持不变。
[root@centos8 ~]#mysqladmin variables |grep innodb_page_size
| innodb_page_size
| 16384
[root@centos8 ~]#mysql
MariaDB [(none)]> show variables like "innodb_page_size";
+------------------+-------+
| Variable_name
| Value |
+------------------+-------+
| innodb_page_size | 16384 |
+------------------+-------+
1 row in set (0.001 sec)
[root@centos8 ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
innodb_page_size=64k
[root@centos8 ~]#rm -rf /var/lib/mysql/*
[root@centos8 ~]#systemctl restart mariadb
[root@centos8 ~]#mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 9
Server version: 10.3.11-MariaDB MariaDB Server
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> show variables like "innodb_page_size";
+------------------+-------+
| Variable_name
| Value |
+------------------+-------+
| innodb_page_size | 65536 |
+------------------+-------+
1 row in set (0.001 sec)
4.3.3 服务器状态变量
服务器状态变量:分全局和会话两种
状态变量(只读):用于保存mysqld运行中的统计数据的变量,不可更改
SHOW GLOBAL STATUS;
SHOW [SESSION] STATUS;
范例:
MariaDB [(none)]> show status like "innodb_page_size";
+------------------+-------+
| Variable_name
| Value |
+------------------+-------+
| Innodb_page_size | 16384 |
+------------------+-------+
1 row in set (0.001 sec)
MariaDB [hellodb]> SHOW GLOBAL STATUS like 'com_select';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Com_select
| 5
|
+---------------+-------+
1 row in set (0.001 sec)
4.3.4 服务器变量 SQL_MODE
SQL_MODE:对其设置可以完成一些约束检查的工作,可分别进行全局的设置或当前会话的设置
参考:
https://mariadb.com/kb/en/library/sql-mode/
https://dev.mysql.com/doc/refman/5.7/en/server-options.html#option_mysqld_sql-
mode
常见MODE:
NO_AUTO_CREATE_USER: 禁止GRANT创建密码为空的用户
NO_ZERO_DATE:在严格模式,不允许使用'0000-00-00'的时间
ONLY_FULL_GROUP_BY: 对于GROUP BY聚合操作,如果在SELECT中的列,没有在GROUP BY
中出现,那么将认为这个SQL是不合法的
NO_BACKSLASH_ESCAPES: 反斜杠"\作为普通字符而非转义字符
PIPES_AS_CONCAT: 将"||"视为连接操作符而非"或"运算符
范例:CentOS 8 修改SQL_MODE变量实现分组语句控制
MariaDB [hellodb]> show variables like 'sql_mode';
+---------------+----------------------------------------------------------------
| Variable_name | Value
|
+---------------+----------------------------------------------------------------
| sql_mode
|
STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUB
STITUTION |
+---------------+----------------------------------------------------------------
1 row in set (0.001 sec)
MariaDB [hellodb]> select classid,count(*) from students group by classid;
+---------+----------+
| classid | count(*) |
+---------+----------+
|
|
|
|
|
NULL |
1 |
2 |
4 |
3 |
4 |
4 |
2 |
3 |
4 |
|
|
|
5 |
6 |
7 |
1 |
4 |
3 |
+---------+----------+
8 rows in set (0.000 sec)
MariaDB [hellodb]> select stuid,classid,count(*) from students group by classid;
+-------+---------+----------+
| stuid | classid | count(*) |
+-------+---------+----------+
|
|
|
|
|
|
|
|
24 |
2 |
1 |
5 |
4 |
6 |
9 |
8 |
NULL |
1 |
2 |
4 |
3 |
4 |
4 |
1 |
4 |
3 |
2 |
3 |
4 |
5 |
6 |
7 |
+-------+---------+----------+
8 rows in set (0.001 sec)
#修改SQL_MODE
MariaDB [hellodb]> set sql_mode="ONLY_FULL_GROUP_BY";
Query OK, 0 rows affected (0.000 sec)
MariaDB [hellodb]> show variables like 'sql_mode';
+---------------+--------------------+
| Variable_name | Value
+---------------+--------------------+
| sql_mode | ONLY_FULL_GROUP_BY |
|
+---------------+--------------------+
1 row in set (0.001 sec)
MariaDB [hellodb]> select classid,count(*) from students group by classid;
+---------+----------+
| classid | count(*) |
+---------+----------+
|
|
|
|
|
|
|
|
NULL |
1 |
2 |
4 |
3 |
4 |
4 |
1 |
4 |
3 |
2 |
3 |
4 |
5 |
6 |
7 |
+---------+----------+
8 rows in set (0.001 sec)
MariaDB [hellodb]> select stuid,classid,count(*) from students group by classid;
ERROR 1055 (42000): 'hellodb.students.StuID' isn't in GROUP BY
范例:CentOS 7 修改SQL_MODE变量
MariaDB [hellodb]> create table test (id int ,name varchar(3));
Query OK, 0 rows affected (0.04 sec)
MariaDB [hellodb]> insert test values(1,'abcde');
Query OK, 1 row affected, 1 warning (0.00 sec)
MariaDB [hellodb]> show warnings;
+---------+------+-------------------------------------------+
| Level
| Code | Message
|
+---------+------+-------------------------------------------+
| Warning | 1265 | Data truncated for column 'name' at row 1 |
+---------+------+-------------------------------------------+
1 row in set (0.00 sec)
MariaDB [hellodb]> select * from test;
+------+------+
| id
+------+------+
1 | abc
| name |
|
|
+------+------+
1 row in set (0.00 sec)
MariaDB [hellodb]> show variables like 'SQL_MODE';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| sql_mode
|
|
+---------------+-------+
1 row in set (0.00 sec)
MariaDB [hellodb]> SET SQL_MODE=TRADITIONAL;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> show variables like 'SQL_MODE';
+---------------+----------------------------------------------------------------
-----+
| Variable_name | Value
|
+---------------+----------------------------------------------------------------
-----+
| sql_mode
|
STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIV
ISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+---------------+----------------------------------------------------------------
-----+
1 row in set (0.00 sec)
MariaDB [hellodb]> insert test values(2,'magedu');
ERROR 1406 (22001): Data too long for column 'name' at row 1
4.4 INDEX 索引
4.4.1 索引介绍
索引:是排序的快速查找的特殊数据结构,定义作为查找条件的字段上,又称为键key,索引通过存储引
擎实现
优点:
索引可以降低服务需要扫描的数据量,减少了IO次数
索引可以帮助服务器避免排序和使用临时表
索引可以帮助将随机I/O转为顺序 I/O
缺点:
占用额外空间,影响插入速度
索引类型:
B+ TREE、HASH、R TREE、FULL TEXT
聚簇(集)索引、非聚簇索引:数据和索引是否存储在一起
主键索引、二级(辅助)索引
稠密索引、稀疏索引:是否索引了每一个数据项
简单索引、组合索引: 是否是多个字段的索引
左前缀索引:取前面的字符做索引
覆盖索引:从索引中即可取出要查询的数据,性能高
4.4.2 索引结构
参考链接 : https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
二叉树
参考链接: https://www.cs.usfca.edu/~galles/visualization/BST.html
红黑树
参考链接:https://www.cs.usfca.edu/~galles/visualization/RedBlack.html
根节点是黑色的, 叶节点是不存储数据的黑色空节点,图中叶节点为正方形的黑色节点
任何相邻的两个节点不能同时为红色,红色节点被黑色节点隔开,红色节点的子节点是黑色的
任意节点到其可到达的叶节点间包含相同数量的黑色节点,保证任何路径相差不会超出2倍,从而实现
基本平衡
B-Tree 索引
参考链接: https://www.cs.usfca.edu/~galles/visualization/BTree.html
B+Tree索引
参考链接: https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html
B+Tree索引:按顺序存储,每一个叶子节点到根结点的距离是相同的;左前缀索引,适合查询范围类的
数据
面试题: InnoDB中一颗的B+树可以存放多少行数据?
假设定义一颗B+树高度为2,即一个根节点和若干叶子节点。那么这棵B+树的存放总行记录数=根节点指针数*
单个叶子记录的行数。这里先计算叶子节点,B+树中的单个叶子节点的大小为16K,假设每一条目为1K,那么
记录数即为16(16k/1K=16),然后计算非叶子节点能够存放多少个指针,假设主键ID为bigint类型,那么长
度为8字节,而指针大小在InnoDB中是设置为6个字节,这样加起来一共是14个字节。那么通过页大小/(主键
ID大小+指针大小),即16384/14=1170个指针,所以一颗高度为2的B+树能存放16*1170=18720条这样的
记录。根据这个原理就可以算出一颗高度为3的B+树可以存放16*1170*1170=21902400条记录。所以在
InnoDB中B+树高度一般为2-3层,它就能满足千万级的数据存储
可以使用B+Tree索引的查询类型:(假设前提: 姓,名,年龄三个字段建立了一个复合索引)
全值匹配:精确所有索引列,如:姓wang,名xiaochun,年龄30
匹配最左前缀:即只使用索引的第一列,如:姓wang
匹配列前缀:只匹配一列值开头部分,如:姓以w开头的记录
匹配范围值:如:姓ma和姓wang之间
精确匹配某一列并范围匹配另一列:如:姓wang,名以x开头的记录
只访问索引的查询
B+Tree索引的限制:
如不从最左列开始,则无法使用索引,如:查找名为xiaochun,或姓为g结尾
不能跳过索引中的列:如:查找姓wang,年龄30的,只能使用索引第一列
特别提示:
索引列的顺序和查询语句的写法应相匹配,才能更好的利用索引
为优化性能,可能需要针对相同的列但顺序不同创建不同的索引来满足不同类型的查询需求
Hash索引
Hash索引:基于哈希表实现,只有精确匹配索引中的所有列的查询才有效,索引自身只存储索引列对应
的哈希值和数据指针,索引结构紧凑,查询性能好
Memory存储引擎支持显式hash索引,InnoDB和MyISAM存储引擎不支持
适用场景:只支持等值比较查询,包括=, <=>, IN()
不适合使用hash索引的场景
不适用于顺序查询:索引存储顺序的不是值的顺序
不支持模糊匹配
不支持范围查询
不支持部分索引列匹配查找:如A,B列索引,只查询A列索引无效
地理空间数据索引R-Tree( Geospatial indexing )
MyISAM支持地理空间索引,可使用任意维度组合查询,使用特有的函数访问,常用于做地理数据存
储,使用不多
InnoDB从MySQL5.7之后也开始支持
全文索引(FULLTEXT)
在文本中查找关键词,而不是直接比较索引中的值,类似搜索引擎
InnoDB从MySQL 5.6之后也开始支持
聚簇和非聚簇索引,主键和二级索引
冗余和重复索引:
冗余索引:(A),(A,B),注意如果同时存在,仍可能会使用(A)索引
重复索引:已经有索引,再次建立索引
4.4.3 索引优化
参考资料: 阿里的《Java开发手册》
https://developer.aliyun.com/topic/java2020
独立地使用列:尽量避免其参与运算,独立的列指索引列不能是表达式的一部分,也不能是函数的
参数,在where条件中,始终将索引列单独放在比较符号的一侧,尽量不要在列上进行运算(函数
操作和表达式操作)
左前缀索引:构建指定索引字段的左侧的字符数,要通过索引选择性(不重复的索引值和数据表的
记录总数的比值)来评估,尽量使用短索引,如果可以,应该制定一个前缀长度
多列索引:AND操作时更适合使用多列索引,而非为每个列创建单独的索引
选择合适的索引列顺序:无排序和分组时,将选择性最高放左侧
只要列中含有NULL值,就最好不要在此列设置索引,复合索引如果有NULL值,此列在使用时也不
会使用索引
对于经常在where子句使用的列,最好设置索引
对于有多个列where或者order by子句,应该建立复合索引
对于like语句,以 % 或者 _ 开头的不会使用索引,以 % 结尾会使用索引
尽量不要使用not in和<>操作,虽然可能使用索引,但性能不高
不要使用RLIKE正则表达式会导致索引失效
查询时,能不要*就不用*,尽量写全字段名,比如:select id,name,age from students;
大部分情况连接效率远大于子查询
在有大量记录的表分页时使用limit
对于经常使用的查询,可以开启查询缓存
多使用explain和profile分析查询语句
查看慢查询日志,找出执行时间长的sql语句优化
4.4.4 管理索引
创建索引:
CREATE [UNIQUE] INDEX index_name ON tbl_name (index_col_name[(length)],...);
ALTER TABLE tbl_name ADD INDEX index_name(index_col_name[(length)]);
help CREATE INDEX;
删除索引:
DROP INDEX index_name ON tbl_name;
ALTER TABLE tbl_name DROP INDEX index_name(index_col_name);
查看索引:
SHOW INDEX FROM [db_name.]tbl_name;
优化表空间:
OPTIMIZE TABLE tb_name;
查看索引的使用
SET GLOBAL userstat=1; #MySQL无此变量
SHOW INDEX_STATISTICS;
范例:
MariaDB [hellodb]> SET GLOBAL userstat=1;
Query OK, 0 rows affected (0.000 sec)
MariaDB [hellodb]> SHOW INDEX_STATISTICS;
Empty set (0.000 sec)
MariaDB [hellodb]> desc students;
+-----------+---------------------+------+-----+---------+----------------+
| Field
| Type
| Null | Key | Default | Extra
|
+-----------+---------------------+------+-----+---------+----------------+
| StuID
| Name
| Age
| int(10) unsigned
| varchar(50)
| NO | PRI | NULL
| auto_increment |
| NO |
| NULL
| NULL
| NULL
| NULL
| NULL
|
|
|
|
|
|
|
|
|
|
| tinyint(3) unsigned | NO |
| enum('F','M') | NO |
| Gender
| ClassID | tinyint(3) unsigned | YES |
| TeacherID | int(10) unsigned | YES |
+-----------+---------------------+------+-----+---------+----------------+
6 rows in set (0.001 sec)
MariaDB [hellodb]> show index from students\G
*************************** 1. row ***************************
Table: students
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: StuID
Collation: A
Cardinality: 25
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
1 row in set (0.000 sec)
MariaDB [hellodb]> SHOW INDEX_STATISTICS;
Empty set (0.000 sec)
MariaDB [hellodb]> select * from students where stuid=10;
+-------+--------------+-----+--------+---------+-----------+
| StuID | Name
+-------+--------------+-----+--------+---------+-----------+
10 | Yue Lingshan | 19 | F 3 | NULL |
| Age | Gender | ClassID | TeacherID |
|
|
+-------+--------------+-----+--------+---------+-----------+
1 row in set (0.000 sec)
MariaDB [hellodb]> SHOW INDEX_STATISTICS;
+--------------+------------+------------+-----------+
| Table_schema | Table_name | Index_name | Rows_read |
+--------------+------------+------------+-----------+
| hellodb
| students
| PRIMARY
|
1 |
+--------------+------------+------------+-----------+
MariaDB [hellodb]> select * from students where stuid=10;
+-------+--------------+-----+--------+---------+-----------+
| StuID | Name
+-------+--------------+-----+--------+---------+-----------+
10 | Yue Lingshan | 19 | F 3 | NULL |
| Age | Gender | ClassID | TeacherID |
|
|
+-------+--------------+-----+--------+---------+-----------+
1 row in set (0.000 sec)
MariaDB [hellodb]> SHOW INDEX_STATISTICS;
+--------------+------------+------------+-----------+
| Table_schema | Table_name | Index_name | Rows_read |
+--------------+------------+------------+-----------+
| hellodb
| students
| PRIMARY
|
2 |
+--------------+------------+------------+-----------+
1 row in set (0.000 sec)
4.4.5 EXPLAIN 工具
可以通过EXPLAIN来分析索引的有效性,获取查询执行计划信息,用来查看查询优化器如何执行查询
参考资料: https://dev.mysql.com/doc/refman/5.7/en/explain-output.html
语法:
EXPLAIN SELECT clause
EXPLAIN输出信息说明:
列名
说明
执行编号,标识select所属的行。如果在语句中没子查询或关联查询,只有唯一
的select,每行都将显示1。否则,内层的select语句一般会顺序编号,对应于其
在原始语句中的位置
id
简单查询:SIMPLE|
复杂查询:PRIMARY(最外面的SELECT)、DERIVED(用于FROM中的子查
询)、UNION(UNION语句的第一个之后的SELECT语句)、UNION RESUlT
(匿名临时表)、SUBQUERY(简单子查询)
select_type
table
访问引用哪个表(引用某个查询,如“derived3”)
关联类型或访问类型,即MySQL决定的如何去查询表中的行的方式
查询可能会用到的索引
type
possible_keys
key
显示mysql决定采用哪个索引来优化查询
key_len
ref
显示mysql在索引里使用的字节数
当使用索引列等值查询时,与索引列进行等值匹配的对象信息
为了找到所需的行而需要读取的行数,估算值,不精确。通过把所有rows列值
相乘,可粗略估算整个查询会检查的行数
rows
额外信息
Using index:MySQL将会使用覆盖索引,以避免访问表
Using where:MySQL服务器将在存储引擎检索后,再进行一次过滤
Using temporary:MySQL对结果排序时会使用临时表
Using filesort:对结果使用一个外部索引排序
Extra
说明: type显示的是访问类型,是较为重要的一个指标,结果值从好到坏依次是:NULL> system >
const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery >
range > index > ALL ,一般来说,得保证查询至少达到range级别,最好能达到ref
NULL>system>const>eq_ref>ref>fulltext>ref_or_null>index_merge>unique_subquery>in
dex_subquery>range>index>ALL //最好到最差
备注:掌握以下10种常见的即可
NULL>system>const>eq_ref>ref>ref_or_null>index_merge>range>index>ALL
类型
说明
All
最坏的情况,全表扫描
和全表扫描一样。只是扫描表的时候按照索引次序进行而不是行。主要优点就是避免了
排序, 但是开销仍然非常大。如在Extra列看到Using index,说明正在使用覆盖索引,
只扫描索引的数据,它比按索引次序全表扫描的开销要小很多
index
range
范围扫描,一个有限制的索引扫描。key 列显示使用了哪个索引。当使用=、 <>、>、
>=、<、<=、IS NULL、<=>、BETWEEN 或者 IN 操作符,用常量比较关键字列时,可以使
用 range
一种索引访问,它返回所有匹配某个单个值的行。此类索引访问只有当使用非唯一性索
引或唯一性索引非唯一性前缀时才会发生。这个类型跟eq_ref不同的是,它用在关联操
作只使用了索引的最左前缀,或者索引不是UNIQUE和PRIMARY KEY。ref可以用于使
用=或<=>操作符的带索引的列。
ref
eq_ref
const
system
Null
最多只返回一条符合条件的记录。使用唯一性索引或主键查找时会发生 (高效)
当确定最多只会有一行匹配的时候,MySQL优化器会在查询前读取它而且只读取一
次,因此非常快。当主键放入where子句时,mysql把这个查询转为一个常量(高效)
这是const连接类型的一种特例,表仅有一行满足条件。
意味着mysql能在优化阶段分解查询语句,在执行阶段甚至用不到访问表或索引(高
效)
范例:
MariaDB [hellodb]> explain select * from students where stuid not in (5,10,20);
+------+-------------+----------+------+---------------+------+---------+------+-
-----+-------------+
| id
| select_type | table
| type | possible_keys | key | key_len | ref
|
rows | Extra
|
+------+-------------+----------+------+---------------+------+---------+------+-
-----+-------------+
|
1 | SIMPLE
| students | ALL | PRIMARY
| NULL | NULL
| NULL |
25 | Using where |
+------+-------------+----------+------+---------------+------+---------+------+-
-----+-------------+
MariaDB [hellodb]> explain select * from students where stuid <> 10 ;
+------+-------------+----------+-------+---------------+---------+---------+----
--+------+-------------+
| id
| select_type | table
| type | possible_keys | key
| key_len |
ref | rows | Extra
|
+------+-------------+----------+-------+---------------+---------+---------+----
--+------+-------------+
|
1 | SIMPLE
| students | range | PRIMARY
| PRIMARY | 4
|
NULL | 24 | Using where |
+------+-------------+----------+-------+---------------+---------+---------+----
--+------+-------------+
1 row in set (0.000 sec)
MariaDB [hellodb]> explain select * from students where age > (select avg(age)
from teachers);
+------+-------------+----------+-------+---------------+---------+---------+----
--+------+-------------+
| id
| select_type | table
| type | possible_keys | key
| key_len |
ref | rows | Extra
|
+------+-------------+----------+-------+---------------+---------+---------+----
--+------+-------------+
|
1 | PRIMARY
NULL | 1 | Using where |
2 | SUBQUERY | teachers | ALL
| students | range | idx_age
| idx_age | 1
|
|
| NULL
| NULL
| NULL
|
NULL |
4 |
|
+------+-------------+----------+-------+---------------+---------+---------+----
--+------+-------------+
范例:创建索引和使用索引
MariaDB [hellodb]> create index idx_name on students(name(10));
Query OK, 0 rows affected (0.009 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [hellodb]> show indexes from students\G
*************************** 1. row ***************************
Table: students
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: StuID
Collation: A
Cardinality: 25
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
*************************** 2. row ***************************
Table: students
Non_unique: 1
Key_name: idx_name
Seq_in_index: 1
Column_name: Name
Collation: A
Cardinality: 25
Sub_part: 10
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
2 rows in set (0.000 sec)
MariaDB [hellodb]> explain select * from students where name like 'w%';
+------+-------------+----------+-------+---------------+----------+---------+---
---+------+-----------------------+
| id | select_type | table
ref | rows | Extra
| type | possible_keys | key
|
| key_len |
+------+-------------+----------+-------+---------------+----------+---------+---
---+------+-----------------------+
|
1 | SIMPLE
| students | range | idx_name
| idx_name | 152
|
NULL | 1 | Using index condition |
+------+-------------+----------+-------+---------------+----------+---------+---
---+------+-----------------------+
1 row in set (0.000 sec)
MariaDB [hellodb]> explain select * from students where name like 'x%';
+------+-------------+----------+------+---------------+------+---------+------+-
-----+-------------+
| id | select_type | table
| type | possible_keys | key | key_len | ref |
rows | Extra
|
+------+-------------+----------+------+---------------+------+---------+------+-
-----+-------------+
|
1 | SIMPLE
| students | ALL | idx_name
| NULL | NULL
| NULL |
25 | Using where |
+------+-------------+----------+------+---------------+------+---------+------+-
-----+-------------+
1 row in set (0.000 sec)
范例: 复合索引
mysql> desc students;
+-----------+---------------------+------+-----+---------+----------------+
| Field
| Type
| Null | Key | Default | Extra
|
+-----------+---------------------+------+-----+---------+----------------+
| StuID
| Name
| int(10) unsigned
| varchar(50)
| NO
| NO
| PRI | NULL
| auto_increment |
|
|
|
|
|
| NULL
| NULL
| NULL
| NULL
| NULL
|
|
|
|
|
|
|
|
|
|
| Age
| tinyint(3) unsigned | NO
| enum('F','M') | NO
| tinyint(3) unsigned | YES
| YES
| Gender
| ClassID
| TeacherID | int(10) unsigned
+-----------+---------------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)
#创建复合索引
mysql> create index idx_name_age on students(name,age);
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc students;
+-----------+---------------------+------+-----+---------+----------------+
| Field
| Type
| Null | Key | Default | Extra
|
+-----------+---------------------+------+-----+---------+----------------+
| StuID
| Name
| int(10) unsigned
| varchar(50)
| NO
| NO
| PRI | NULL
| MUL | NULL
| auto_increment |
|
|
|
|
|
|
|
|
|
|
| Age
| tinyint(3) unsigned | NO
| enum('F','M') | NO
| tinyint(3) unsigned | YES
| YES
|
|
|
|
| NULL
| NULL
| NULL
| NULL
| Gender
| ClassID
| TeacherID | int(10) unsigned
+-----------+---------------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)
mysql> show indexes from students\G
*************************** 1. row ***************************
Table: students
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: StuID
Collation: A
Cardinality: 25
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
Visible: YES
Expression: NULL
*************************** 2. row ***************************
Table: students
Non_unique: 1
Key_name: idx_name_age
Seq_in_index: 1
Column_name: Name
Collation: A
Cardinality: 25
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
Visible: YES
Expression: NULL
*************************** 3. row ***************************
Table: students
Non_unique: 1
Key_name: idx_name_age
Seq_in_index: 2
Column_name: Age
Collation: A
Cardinality: 25
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
Visible: YES
Expression: NULL
3 rows in set (0.01 sec)
#跳过查询复合索引的前面字段,后续字段的条件查询无法利用复合索引
mysql> explain select * from students where age=20;
+----+-------------+----------+------------+------+---------------+------+-------
--+------+------+----------+-------------+
| id | select_type | table
| partitions | type | possible_keys | key
|
key_len | ref | rows | filtered | Extra
|
+----+-------------+----------+------------+------+---------------+------+-------
--+------+------+----------+-------------+
|
1 | SIMPLE
| NULL |
| students | NULL
| ALL | NULL
| NULL | NULL
25 |
10.00 | Using where |
+----+-------------+----------+------------+------+---------------+------+-------
--+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
范例: 复合索引和覆盖索引
mysql> desc testlog;
+--------+----------+------+-----+---------+----------------+
| Field | Type
| Null | Key | Default | Extra
|
+--------+----------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | char(10) | YES |
| salary | int(11) | YES |
| NULL
| 20
|
|
|
|
+--------+----------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
#创建复合索引
mysql> create index idx_name_salary on testlog(name,salary);
Query OK, 0 rows affected (0.25 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc testlog;
+--------+----------+------+-----+---------+----------------+
| Field | Type
+--------+----------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | char(10) | YES | MUL | NULL
| salary | int(11) | YES | | 20
| Null | Key | Default | Extra
|
|
|
|
|
+--------+----------+------+-----+---------+----------------+
3 rows in set (0.01 sec)
mysql> show indexes from testlog\G
*************************** 1. row ***************************
Table: testlog
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: id
Collation: A
Cardinality: 90620
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
Visible: YES
Expression: NULL
*************************** 2. row ***************************
Table: testlog
Non_unique: 1
Key_name: idx_name_salary
Seq_in_index: 1
Column_name: name
Collation: A
Cardinality: 95087
Sub_part: NULL
Packed: NULL
Null: YES
Index_type: BTREE
Comment:
Index_comment:
Visible: YES
Expression: NULL
*************************** 3. row ***************************
Table: testlog
Non_unique: 1
Key_name: idx_name_salary
Seq_in_index: 2
Column_name: salary
Collation: A
Cardinality: 99852
Sub_part: NULL
Packed: NULL
Null: YES
Index_type: BTREE
Comment:
Index_comment:
Visible: YES
Expression: NULL
3 rows in set (0.00 sec)
#覆盖索引
mysql> explain select * from testlog where salary=66666;
+----+-------------+---------+------------+-------+-----------------+------------
-----+---------+------+--------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key
| key_len | ref | rows | filtered | Extra
|
+----+-------------+---------+------------+-------+-----------------+------------
-----+---------+------+--------+----------+--------------------------+
| 1 | SIMPLE
| testlog | NULL
| index | idx_name_salary |
10.00 | Using where; Using index
idx_name_salary | 36
|
| NULL | 100290 |
+----+-------------+---------+------------+-------+-----------------+------------
-----+---------+------+--------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)
4.4.6 使用 profile 工具
#打开后,会显示语句执行详细的过程
set profiling = ON;
#查看语句,注意结果中的query_id值
show profiles ;
MariaDB [hellodb]> show profiles ;
+----------+------------+-------------------------------------+
| Query_ID | Duration | Query
|
+----------+------------+-------------------------------------+
|
|
|
|
1 | 0.00019238 | select @@profiling
|
2 | 0.00115590 | select * from students where age=20 |
3 | 0.00006616 | show profiles for query 2
4 | 4.00319568 | select sleep(1) from teachers
|
|
+----------+------------+-------------------------------------+
4 rows in set (0.000 sec)
#显示语句的详细执行步骤和时长
Show profile for query #
MariaDB [hellodb]> show profile for query 4;
+------------------------+----------+
| Status
+------------------------+----------+
| Starting | 0.000157 |
| Checking permissions | 0.000009 |
| Opening tables | 0.000025 |
| After opening tables | 0.000005 |
| Duration |
| System lock
| Table lock
| 0.000004 |
| 0.000006 |
| 0.000017 |
| 0.000009 |
| 0.000018 |
| 0.000028 |
| 0.000003 |
| 0.000070 |
| 1.001128 |
| 1.000313 |
| 1.000834 |
| 1.000348 |
| 0.000032 |
| 0.000003 |
| 0.000014 |
| 0.000004 |
| 0.000003 |
| 0.000012 |
| 0.000003 |
| 0.000056 |
| 0.000024 |
| 0.000069 |
| Init
| Optimizing
| Statistics
| Preparing
| Executing
| Sending data
| User sleep
| User sleep
| User sleep
| User sleep
| End of update loop
| Query end
| Commit
| Closing tables
| Unlocking tables
| Closing tables
| Starting cleanup
| Freeing items
| Updating status
| Logging slow query
| Reset for next command | 0.000004 |
+------------------------+----------+
27 rows in set (0.000 sec)
MariaDB [hellodb]>
#显示cpu使用情况
Show profile cpu for query #
MariaDB [hellodb]> Show profile cpu for query 4;
+------------------------+----------+----------+------------+
| Status
+------------------------+----------+----------+------------+
| Starting | 0.000157 | 0.000090 | 0.000065 |
| Checking permissions | 0.000009 | 0.000005 | 0.000004 |
| Opening tables | 0.000025 | 0.000014 | 0.000010 |
| After opening tables | 0.000005 | 0.000003 | 0.000002 |
| Duration | CPU_user | CPU_system |
| System lock
| Table lock
| Init
| 0.000004 | 0.000002 | 0.000002 |
| 0.000006 | 0.000004 | 0.000002 |
| 0.000017 | 0.000010 | 0.000007 |
| 0.000009 | 0.000005 | 0.000004 |
| 0.000018 | 0.000010 | 0.000007 |
| 0.000028 | 0.000016 | 0.000012 |
| 0.000003 | 0.000002 | 0.000002 |
| 0.000070 | 0.000059 | 0.000000 |
| 1.001128 | 0.000665 | 0.000000 |
| 1.000313 | 0.000716 | 0.000000 |
| 1.000834 | 0.000379 | 0.000100 |
| 1.000348 | 0.000319 | 0.000231 |
| 0.000032 | 0.000017 | 0.000012 |
| 0.000003 | 0.000002 | 0.000002 |
| Optimizing
| Statistics
| Preparing
| Executing
| Sending data
| User sleep
| User sleep
| User sleep
| User sleep
| End of update loop
| Query end
| Commit
| 0.000014 | 0.000008 |
| 0.000004 | 0.000002 |
| 0.000003 | 0.000002 |
| 0.000012 | 0.000007 |
| 0.000003 | 0.000001 |
| 0.000056 | 0.000034 |
| 0.000024 | 0.000013 |
| 0.000069 | 0.000040 |
0.000005 |
0.000002 |
0.000001 |
0.000005 |
0.000001 |
0.000024 |
0.000010 |
0.000029 |
0.000001 |
| Closing tables
| Unlocking tables
| Closing tables
| Starting cleanup
| Freeing items
| Updating status
| Logging slow query
| Reset for next command | 0.000004 | 0.000002 |
+------------------------+----------+----------+------------+
27 rows in set (0.000 sec)
MariaDB [hellodb]>
4.5 并发控制
4.5.1 锁机制
锁类型:
读锁:共享锁,也称为 S 锁,只读不可写(包括当前事务) ,多个读互不阻塞
写锁:独占锁,排它锁,也称为 X 锁,写锁会阻塞其它事务(不包括当前事务)的读和写
S 锁和 S 锁是兼容的,X 锁和其它锁都不兼容,举个例子,事务 T1 获取了一个行 r1 的 S 锁,另外
事务 T2 可以立即获得行 r1 的 S 锁,此时 T1 和 T2 共同获得行 r1 的 S 锁,此种情况称为锁兼容,
但是另外一个事务 T2 此时如果想获得行 r1 的 X 锁,则必须等待 T1 对行 r1 锁的释放,此种情况
也称为锁冲突
锁粒度:
表级锁:MyISAM
行级锁:InnoDB
实现
存储引擎:自行实现其锁策略和锁粒度
服务器级:实现了锁,表级锁,用户可显式请求
分类:
隐式锁:由存储引擎自动施加锁
显式锁:用户手动请求
锁策略:在锁粒度及数据安全性寻求的平衡机制
4.5.2 显式使用锁
帮助:https://mariadb.com/kb/en/lock-tables/
加锁
LOCK TABLES tbl_name [[AS] alias] lock_type [, tbl_name [[AS] alias]
lock_type] ...
lock_type:
READ
#读锁
WRITE #写锁
解锁
UNLOCK TABLES
关闭正在打开的表(清除查询缓存),通常在备份前加全局读锁
FLUSH TABLES [tb_name[,...]] [WITH READ LOCK]
查询时加写或读锁
SELECT clause [FOR UPDATE | LOCK IN SHARE MODE]
范例: 加读锁
mysql> lock tables students read ;
Query OK, 0 rows affected (0.00 sec)
mysql> update students set classid=2 where stuid=24;
ERROR 1099 (HY000): Table 'students' was locked with a READ lock and can't be
updated
mysql> unlock tables ;
mysql> update students set classid=2 where stuid=24;
Query OK, 1 row affected (1 min 45.52 sec)
Rows matched: 1 Changed: 1 Warnings: 0
范例: 同时在两个终端对同一行记录修改
#同时对同一行记录执行update
#在第一终端提示1行成功
MariaDB [hellodb]> update students set classid=1 where stuid=24;
Query OK, 1 row affected (0.002 sec)
Rows matched: 1 Changed: 1 Warnings: 0
#在第二终端提示0行修改
MariaDB [hellodb]> update students set classid=1 where stuid=24;
Query OK, 0 rows affected (0.000 sec)
Rows matched: 1 Changed: 0 Warnings: 0
4.5.3 事务
事务 Transactions:一组原子性的 SQL语句,或一个独立工作单元
事务日志:记录事务信息,实现undo,redo等故障恢复功能
4.5.3.1 事务特性
ACID特性:
A:atomicity 原子性;整个事务中的所有操作要么全部成功执行,要么全部失败后回滚
C:consistency一致性;数据库总是从一个一致性状态转换为另一个一致性状态,类似于能量守恒定
律(N50周启皓语录)
I:Isolation隔离性;一个事务所做出的操作在提交之前,是不能为其它事务所见;隔离有多种隔离
级别,实现并发
D:durability持久性;一旦事务提交,其所做的修改会永久保存于数据库中
Transaction 生命周期
4.5.3.2 管理事务
显式启动事务:
BEGIN
BEGIN WORK
START TRANSACTION
结束事务:
#提交,相当于vi中的wq保存退出
COMMIT
#回滚,相当于vi中的q!不保存退出
ROLLBACK
注意:只有事务型存储引擎中的DML语句方能支持此类操作
自动提交:
set autocommit={1|0}
默认为1,为0时设为非自动提交
建议:显式请求和提交事务,而不要使用"自动提交"功能
事务支持保存点:
SAVEPOINT identifier
ROLLBACK [WORK] TO [SAVEPOINT] identifier
RELEASE SAVEPOINT identifier
查看事务:
#查看当前正在进行的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
#以下两张表在MySQL8.0中已取消
#查看当前锁定的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
#查看当前等锁的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
死锁:
两个或多个事务在同一资源相互占用,并请求锁定对方占用的资源的状态
范例:找到未完成的导致阻塞的事务(支持Mariadb)
#在第一会话中执行
MariaDB [hellodb]> begin;
Query OK, 0 rows affected (0.000 sec)
MariaDB [hellodb]> update students set classid=10;
#在第二个会话中执行
MariaDB [hellodb]> update students set classid=20;
#在第三个会话中执行
MariaDB [hellodb]> show engine innodb status;
...省略...
---TRANSACTION 120, ACTIVE 673 sec
2 lock struct(s), heap size 1136, 28 row lock(s), undo log entries 27
MySQL thread id 13, OS thread handle 139719808595712, query id 206 localhost
root
...省略...
#此指令不支持MySQL8.0
MariaDB [hellodb]> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
+-----------+-------------+-----------+-----------+----------------------+-------
-----+------------+-----------+----------+-----------+
| lock_id
| lock_trx_id | lock_mode | lock_type | lock_table
|
lock_index | lock_space | lock_page | lock_rec | lock_data |
+-----------+-------------+-----------+-----------+----------------------+-------
-----+------------+-----------+----------+-----------+
| 123:9:3:2 | 123
PRIMARY
| 120:9:3:2 | 120
PRIMARY
| X
| RECORD
2 | 1
| RECORD
2 | 1
| `hellodb`.`students` |
|
9 |
9 |
3 |
3 |
|
| X
| `hellodb`.`students` |
|
|
+-----------+-------------+-----------+-----------+----------------------+-------
-----+------------+-----------+----------+-----------+
2 rows in set (0.001 sec)
#此指令不支持MySQL8.0
MariaDB [hellodb]> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
+-------------------+-------------------+-----------------+------------------+
| requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id |
+-------------------+-------------------+-----------------+------------------+
| 123
| 123:9:3:2
| 120
| 120:9:3:2
|
+-------------------+-------------------+-----------------+------------------+
1 row in set (0.000 sec)
#查看正在进行的事务
MariaDB [hellodb]> SELECT * FROM information_schema.INNODB_TRX\G
*************************** 1. row ***************************
trx_id: 123
trx_state: LOCK WAIT
trx_started: 2019-11-22 19:17:06
trx_requested_lock_id: 123:9:3:2
trx_wait_started: 2019-11-22 19:18:50
trx_weight: 2
trx_mysql_thread_id: 15
#线程ID
trx_query: update students set classid=20
trx_operation_state: starting index read
trx_tables_in_use: 1
trx_tables_locked: 1
trx_lock_structs: 2
trx_lock_memory_bytes: 1136
trx_rows_locked: 2
trx_rows_modified: 0
trx_concurrency_tickets: 0
trx_isolation_level: REPEATABLE READ
trx_unique_checks: 1
trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
trx_is_read_only: 0
trx_autocommit_non_locking: 0
*************************** 2. row ***************************
trx_id: 120
trx_state: RUNNING
trx_started: 2019-11-22 19:08:51
trx_requested_lock_id: NULL
trx_wait_started: NULL
trx_weight: 29
trx_mysql_thread_id: 13
#线程ID
trx_query: NULL
trx_operation_state: NULL
trx_tables_in_use: 0
trx_tables_locked: 1
trx_lock_structs: 2
trx_lock_memory_bytes: 1136
trx_rows_locked: 28
trx_rows_modified: 27
trx_concurrency_tickets: 0
trx_isolation_level: REPEATABLE READ
trx_unique_checks: 1
trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
trx_is_read_only: 0
trx_autocommit_non_locking: 0
2 rows in set (0.000 sec)
MariaDB [hellodb]> show processlist;
+----+-------------+-----------+---------+---------+------+----------------------
----+------------------+----------+
| Id | User
| Info
| Host
| db
| Command | Time | State
| Progress |
+----+-------------+-----------+---------+---------+------+----------------------
----+------------------+----------+
|
1 | system user |
| NULL
| Daemon | NULL | InnoDB purge
coordinator | NULL
|
0.000 |
|
|
|
|
3 | system user |
| NULL
| NULL
0.000 |
| NULL
0.000 |
| NULL
0.000 |
| NULL
| Daemon | NULL | InnoDB purge worker
| Daemon | NULL | InnoDB purge worker
| Daemon | NULL | InnoDB purge worker
| Daemon | NULL | InnoDB shutdown
|
|
|
4 | system user |
| NULL
2 | system user |
| NULL
5 | system user |
handler | NULL
| 11 | root
|
0.000 |
| localhost | hellodb | Query
|
|
|
0 | Init
38 |
| show processlist |
0.000 |
| 13 | root
| NULL
| localhost | hellodb | Sleep
|
0.000 |
| localhost | hellodb | Query
0.000
| 15 | root
10 | Updating
| update students set classid=20 |
+----+-------------+-----------+---------+---------+------+----------------------
----+------------------+----------+
7 rows in set (0.000 sec)
#杀掉未完成的事务
MariaDB [hellodb]> kill 13;
Query OK, 0 rows affected (0.000 sec)
#查看事务锁的超时时长,默认50s
MariaDB [hellodb]> show global variables like 'innodb_lock_wait_timeout';
+--------------------------+-------+
| Variable_name
+--------------------------+-------+
| innodb_lock_wait_timeout | 50
| Value |
|
+--------------------------+-------+
1 row in set (0.001 sec)
4.5.3.3 事务隔离级别
MySQL 支持四种隔离级别,事务隔离级别从上至下更加严格
隔离级别
读未提交
读提交
脏读
不可重复读
可以出现
幻读
加读锁
否
可以出现
不允许出现
不允许出现
不允许出现
可以出现
可以出现
可以出现
不允许出现
可以出现
否
可重复读
序列化
不允许出现
不允许出现
否
是
READ UNCOMMITTED
可读取到未提交数据,产生脏读
READ COMMITTED
可读取到提交数据,但未提交数据不可读,产生不可重复读,即可读取到多个提交数据,导致每次
读取数据不一致
REPEATABLE READ
可重复读,多次读取数据都一致,产生幻读,即读取过程中,即使有其它提交的事务修改数据,仍
只能读取到未修改前的旧数据。此为MySQL默认设置
SERIALIZABLE
可串行化,未提交的读事务阻塞写事务(加读锁,但不阻塞读事务),或者未提交的写事务阻塞读
和写事务(加写锁,其它事务的读,写都不可以执行)。会导致并发性能差
MVCC和事务的隔离级别:
MVCC(多版本并发控制机制)只在READ COMMITTED和REPEATABLE READ两个隔离级别下工作。其
他两个隔离级别都和MVCC不兼容,因为READ UNCOMMITTED总是读取最新的数据行,而不是符合当前
事务版本的数据行。而SERIALIZABLE则会对所有读取的行都加锁
指定事务隔离级别:
服务器变量tx_isolation(MySQL8.0改名为transaction_isolation)指定,默认为REPEATABLE-
READ,可在GLOBAL和SESSION级进行设置
#MySQL8.0之前版本
SET tx_isolation='READ-UNCOMMITTED|READ-COMMITTED|REPEATABLE-
READ|SERIALIZABLE'
#MySQL8.0
SET transaction_isolation='READ-UNCOMMITTED|READ-COMMITTED|REPEATABLE-
READ|SERIALIZABLE'
服务器选项中指定
vim /etc/my.cnf
[mysqld]
transaction-isolation=SERIALIZABLE
范例: MySQL8.0 事务隔离级别系统变量tx_isolation已取消
mysql> select @@tx_isolation;
ERROR 1193 (HY000): Unknown system variable 'tx_isolation'
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ
|
+-------------------------+
1 row in set (0.00 sec)
4.6 日志管理
MySQL 支持丰富的日志类型,如下:
事务日志:transaction log
事务日志的写入类型为"追加",因此其操作为"顺序IO";通常也被称为:预写式日志 write ahead
logging
事务日志文件: ib_logfile0, ib_logfile1
错误日志error log
通用日志general log
慢查询日志 slow query log
二进制日志 binary log
中继日志reley log,在主从复制架构中,从服务器用于保存从主服务器的二进制日志中读取的事件
4.6.1 事务日志
事务日志:transaction log
redo log:记录某数据块被修改后的值,数据更新前先记录redo log( WALWrite Ahead Log ),可以
用来恢复未写入data file的已成功事务更新的数据
undo log:保存与执行的操作相反的操作,即记录某数据被修改前的值,可以用来在事务失败时进
行rollback
事务型存储引擎自行管理和使用,建议和数据文件分开存放
Innodb事务日志相关配置:
show variables like '%innodb_log%';
innodb_log_file_size 50331648
innodb_log_files_in_group 2
innodb_log_group_home_dir ./
#每个日志文件大小
#日志组成员个数
#事务文件路径
事务日志性能优化
innodb_flush_log_at_trx_commit=0|1|2
1
0
此为默认值,日志缓冲区将写入日志文件,并在每次事务后执行刷新到磁盘。 这是完全遵守ACID特性
提交时没有写磁盘的操作; 而是每秒执行一次将日志缓冲区的提交的事务写入刷新到磁盘。 这样可提供更
好的性能,但服务器崩溃可能丢失最后一秒的事务
2
每次提交后都会写入OS的缓冲区,但每秒才会进行一次刷新到磁盘文件中。 性能比0略差一些,但操作系
统或停电可能导致最后一秒的交易丢失
高并发业务行业最佳实践,是使用第三种折衷配置(=2):
1.配置为2和配置为0,性能差异并不大,因为将数据从Log Buffer拷贝到OS cache,虽然跨越用户态与内
核态,但毕竟只是内存的数据拷贝,速度很快
2.配置为2和配置为0,安全性差异巨大,操作系统崩溃的概率相比MySQL应用程序崩溃的概率,小很多,设置
为2,只要操作系统不奔溃,也绝对不会丢数据
说明:
设置为1,同时sync_binlog = 1表示最高级别的容错
innodb_use_global_flush_log_at_trx_commit=0 时,将不能用SET语句重置此变量( MariaDB
10.2.6 后废弃)
4.6.2 错误日志
错误日志
mysqld启动和关闭过程中输出的事件信息
mysqld运行中产生的错误信息
event scheduler运行一个event时产生的日志信息
在主从复制架构中的从服务器上启动从服务器线程时产生的信息
错误文件路径
SHOW GLOBAL VARIABLES LIKE 'log_error' ;
范例:
MariaDB [hellodb]> SHOW GLOBAL VARIABLES LIKE 'log_error';
+---------------+------------------------------+
| Variable_name | Value
+---------------+------------------------------+
| log_error | /var/log/mariadb/mariadb.log |
|
+---------------+------------------------------+
1 row in set (0.001 sec)
记录哪些警告信息至错误日志文件
#CentOS7 mariadb 5.5 默认值为1
#CentOS8 mariadb 10.3 默认值为2
log_warnings=0|1|2|3...
#MySQL5.7之前
log_error_verbosity=0|1|2|3... #MySQL8.0
范例:
MariaDB [hellodb]> SHOW GLOBAL VARIABLES LIKE 'log_warnings';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_warnings | 2
|
+---------------+-------+
1 row in set (0.001 sec)
范例: MySQL8.0变量变化
mysql> SHOW GLOBAL VARIABLES LIKE 'log_error_verbosity';
+---------------------+-------+
| Variable_name
+---------------------+-------+
| log_error_verbosity | 2
| Value |
|
+---------------------+-------+
1 row in set (0.00 sec)
4.6.3 通用日志
通用日志:记录对数据库的通用操作,包括:错误的SQL语句
通用日志可以保存在:file(默认值)或 table(mysql.general_log表)
通用日志相关设置
general_log=ON|OFF
general_log_file=HOSTNAME.log
log_output=TABLE|FILE|NONE
范例: 启用通用日志并记录至文件中
#默认没有启用通用日志
mysql> select @@general_log;
+---------------+
| @@general_log |
+---------------+
|
0 |
+---------------+
1 row in set (0.00 sec)
#启用
mysql> set global general_log=1;
Query OK, 0 rows affected (0.01 sec)
mysql> select @@general_log;
+---------------+
| @@general_log |
+---------------+
|
1 |
+---------------+
1 row in set (0.00 sec)
#默认通用日志存放在文件中
mysql> SHOW GLOBAL VARIABLES LIKE 'log_output';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_output
| FILE |
+---------------+-------+
1 row in set (0.00 sec)
#通用日志存放的文件路径
mysql> select @@general_log_file;
+----------------------------+
| @@general_log_file
|
+----------------------------+
| /var/lib/mysql/centos8.log |
+----------------------------+
1 row in set (0.00 sec)
范例:通用日志记录到表中
#修改通用日志,记录通用日志至mysql.general_log表中
MariaDB [mysql]> set global log_output="table";
MariaDB [mysql]> SHOW GLOBAL VARIABLES LIKE 'log_output';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_output
| TABLE |
+---------------+-------+
1 row in set (0.002 sec)
#general_log表是CSV格式的存储引擎
mysql> show table status like 'general_log'\G
*************************** 1. row ***************************
Name: general_log
Engine: CSV
Version: 10
Row_format: Dynamic
Rows: 1
Avg_row_length: 0
Data_length: 0
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: NULL
Create_time: 2021-01-30 08:56:13
Update_time: NULL
Check_time: NULL
Collation: utf8_general_ci
Checksum: NULL
Create_options:
Comment: General log
1 row in set (0.01 sec)
#general_log表是CSV的文本文件
[root@centos8 ~]#file /var/lib/mysql/mysql/general_log.CSV
/var/lib/mysql/mysql/general_log.CSV: ASCII text
[root@centos8 ~]#head /var/lib/mysql/mysql/general_log.CSV
"2021-02-05 10:01:42.506955","root[root] @ localhost []",8,1,"Query","select
count(*) from general_log"
"2021-02-05 10:01:48.436410","root[root] @ localhost []",8,1,"Query","select *
from general_log"
"2021-02-05 10:01:57.619597","root[root] @ localhost []",8,1,"Query","select *
from students"
"2021-02-05 10:02:03.628124","root[root] @ localhost []",8,1,"Query","SELECT
DATABASE()"
"2021-02-05 10:02:03.628309","root[root] @ localhost []",8,1,"Init DB","hellodb"
"2021-02-05 10:02:03.629031","root[root] @ localhost []",8,1,"Query","show
databases"
"2021-02-05 10:02:03.629901","root[root] @ localhost []",8,1,"Query","show
tables"
MariaDB [mysql]> select * from mysql.general_log\G
...省略...
*************************** 6. row ***************************
event_time: 2019-11-25 11:03:41.163896
user_host: root[root] @ localhost []
thread_id: 9
server_id: 1
command_type: Query
argument: xxx
*************************** 7. row ***************************
event_time: 2019-11-25 11:03:44.549211
user_host: root[root] @ localhost []
thread_id: 8
server_id: 1
command_type: Query
argument: select * from general_log
7 rows in set (0.000 sec)
范例: 查找执行次数最多的前三条语句
MariaDB [mysql]> select argument,count(argument) num from mysql.general_log
group by argument order by num desc limit 3;
+---------------------------+-----------------+
| argument
|
num |
+---------------------------+-----------------+
| select * from teachers
| select * from general_log |
| select * from students
|
6 |
4 |
3 |
|
+---------------------------+-----------------+
3 rows in set (0.002 sec)
范例:对访问的语句进行排序
[root@centos8 ~]#mysql -e 'select argument from mysql.general_log' | awk
'{sql[$0]++}END{for(i in sql){print sql[i],i}}'|sort -nr
[root@centos8 ~]#mysql -e 'select argument from mysql.general_log' |sort |uniq -c
|sort -nr
4.6.4 慢查询日志
慢查询日志:记录执行查询时长超出指定时长的操作
慢查询相关变量
slow_query_log=ON|OFF #开启或关闭慢查询,支持全局和会话,只有全局设置才会生成慢查询文件
long_query_time=N
#慢查询的阀值,单位秒,默认为10s
slow_query_log_file=HOSTNAME-slow.log #慢查询日志文件
log_slow_filter = admin,filesort,filesort_on_disk,full_join,full_scan,
query_cache,query_cache_miss,tmp_table,tmp_table_on_disk
#上述查询类型且查询时长超过long_query_time,则记录日志
log_queries_not_using_indexes=ON #不使用索引或使用全索引扫描,不论是否达到慢查询阀值的语
句是否记录日志,默认OFF,即不记录
log_slow_rate_limit = 1
#多少次查询才记录,mariadb特有
log_slow_verbosity= Query_plan,explain #记录内容
log_slow_queries = OFF
#同slow_query_log,MariaDB 10.0/MySQL 5.6.1 版后已删除
范例: 慢查询分析工具mysqldumpslow
[root@centos8 ~]#mysqldumpslow --help
Usage: mysqldumpslow [ OPTS... ] [ LOGS... ]
Parse and summarize the MySQL slow query log. Options are
--verbose
--debug
--help
verbose
debug
write this text to standard output
-v
verbose
-d
debug
-s ORDER
what to sort by (aa, ae, al, ar, at, a, c, e, l, r, t), 'at' is
default
aa: average rows affected
ae: aggregated rows examined
al: average lock time
ar: average rows sent
at: average query time
a: rows affected
c: count
e: rows examined
l: lock time
r: rows sent
t: query time
-r
reverse the sort order (largest last instead of first)
just show the top n queries
don't abstract all numbers to N and strings to 'S'
abstract numbers with at least n digits within names
-t NUM
-a
-n NUM
-g PATTERN grep: only consider stmts that include this string
-h HOSTNAME hostname of db server for *-slow.log filename (can be wildcard),
default is '*', i.e. match all
-i NAME
-l
name of server instance (if using mysql.server startup script)
don't subtract lock time from total time
[root@centos8 ~]#mysqldumpslow -s c -t 2 /var/lib/mysql/centos8-slow.log
Reading mysql slow query log from /var/lib/mysql/centos8-slow.log
Count: 1 Time=0.00s (0s) Lock=0.00s (0s) Rows_sent=2.0 (2),
Rows_examined=25.0 (25), Rows_affected=0.0 (0), root[root]@localhost
select * from students where age=N
Count: 1 Time=4.00s (4s) Lock=0.00s (0s) Rows_sent=4.0 (4), Rows_examined=4.0
(4), Rows_affected=0.0 (0), root[root]@localhost
select sleep(N) from teachers
4.6.5 二进制日志(备份)
记录导致数据改变或潜在导致数据改变的SQL语句
记录已提交的日志
不依赖于存储引擎类型
功能:通过"重放"日志文件中的事件来生成数据副本
注意:建议二进制日志和数据文件分开存放
二进制日志记录三种格式
基于"语句"记录:statement,记录语句,默认模式( MariaDB 10.2.3 版本以下 ),日志量较少
基于"行"记录:row,记录数据,日志量较大,更加安全,建议使用的格式,MySQL8.0默认格式
混合模式:mixed, 让系统自行判定该基于哪种方式进行,默认模式( MariaDB 10.2.4及版本以上
)
格式配置
MariaDB [hellodb]> show variables like 'binlog_format';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | MIXED |
+---------------+-------+
1 row in set (0.001 sec)
#MySQL 8.0 默认使用ROW方式
mysql> show variables like 'binlog_format';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW |
+---------------+-------+
1 row in set (0.07 sec)
二进制日志文件的构成
有两类文件
1.日志文件:mysql|mariadb-bin.文件名后缀,二进制格式,如: on.000001,mariadb-bin.000002
2.索引文件:mysql|mariadb-bin.index,文本格式,记录当前已有的二进制日志文件列表
二进制日志相关的服务器变量:
sql_log_bin=ON|OFF:#是否记录二进制日志,默认ON,支持动态修改,系统变量,而非服务器选项
log_bin=/PATH/BIN_LOG_FILE:#指定文件位置;默认OFF,表示不启用二进制日志功能,上述两项都开
启才可以
binlog_format=STATEMENT|ROW|MIXED:#二进制日志记录的格式,mariadb5.5默认STATEMENT
max_binlog_size=1073741824:#单个二进制日志文件的最大体积,到达最大值会自动滚动,默认为1G
#说明:文件达到上限时的大小未必为指定的精确值
binlog_cache_size=4m #此变量确定在每次事务中保存二进制日志更改记录的缓存的大小(每次连接)
max_binlog_cache_size=512m #限制用于缓存多事务查询的字节大小。
sync_binlog=1|0:#设定是否启动二进制日志即时同步磁盘功能,默认0,由操作系统负责同步日志到磁盘
expire_logs_days=N:#二进制日志可以自动删除的天数。 默认为0,即不自动删除
二进制日志相关配置
查看mariadb自行管理使用中的二进制日志文件列表,及大小
SHOW {BINARY | MASTER} LOGS
查看使用中的二进制日志文件
SHOW MASTER STATUS
在线查看二进制文件中的指定内容
SHOW BINLOG EVENTS [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count]
范例:
show binlog events in 'mysql-bin.000001' from 6516 limit 2,3
范例:
MariaDB [hellodb]> SHOW BINLOG EVENTS;
+------------------+-----+-------------------+-----------+-------------+---------
| Log_name
| Pos | Event_type
| Server_id | End_log_pos | Info
|
+------------------+-----+-------------------+-----------+-------------+---------
| mysql-bin.000001 |
4 | Format_desc
|
1 |
1 |
1 |
1 |
256 | Server
ver: 10.3.17-MariaDB-log, Binlog ver: 4 |
| mysql-bin.000001 | 256 | Gtid_list
|
|
285 | []
| mysql-bin.000001 | 285 | Binlog_checkpoint |
328 | mysql-
375 | mysql-
bin.000001
|
| mysql-bin.000001 | 328 | Rotate
bin.000002;pos=4
|
|
+------------------+-----+-------------------+-----------+-------------+---------
4 rows in set (0.000 sec)
MariaDB [hellodb]> SHOW BINLOG EVENTS in 'mysql-bin.000002' from 614 limit 2,3
\G
*************************** 1. row ***************************
Log_name: mysql-bin.000002
Pos: 782
Event_type: Query
Server_id: 1
End_log_pos: 1098
Info: use `hellodb`; CREATE TABLE `classes` (
`ClassID` tinyint(3) unsigned NOT NULL AUTO_INCREMENT,
`Class` varchar(100) DEFAULT NULL,
`NumOfStu` smallint(5) unsigned DEFAULT NULL,
PRIMARY KEY (`ClassID`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8
*************************** 2. row ***************************
Log_name: mysql-bin.000002
Pos: 1098
Event_type: Gtid
Server_id: 1
End_log_pos: 1140
Info: GTID 0-1-4
*************************** 3. row ***************************
Log_name: mysql-bin.000002
Pos: 1140
Event_type: Query
Server_id: 1
End_log_pos: 1256
Info: use `hellodb`; /*!40000 ALTER TABLE `classes` DISABLE KEYS */
3 rows in set (0.000 sec)
MariaDB [hellodb]> SHOW BINLOG EVENTS in 'mysql-bin.000002' from 614 limit 2,3
\G
*************************** 1. row ***************************
Log_name: mysql-bin.000002
Pos: 782
Event_type: Query
Server_id: 1
End_log_pos: 1098
Info: use `hellodb`; CREATE TABLE `classes` (
`ClassID` tinyint(3) unsigned NOT NULL AUTO_INCREMENT,
`Class` varchar(100) DEFAULT NULL,
`NumOfStu` smallint(5) unsigned DEFAULT NULL,
PRIMARY KEY (`ClassID`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8
*************************** 2. row ***************************
Log_name: mysql-bin.000002
Pos: 1098
Event_type: Gtid
Server_id: 1
End_log_pos: 1140
Info: GTID 0-1-4
*************************** 3. row ***************************
Log_name: mysql-bin.000002
Pos: 1140
Event_type: Query
Server_id: 1
End_log_pos: 1256
Info: use `hellodb`; /*!40000 ALTER TABLE `classes` DISABLE KEYS */
3 rows in set (0.000 sec)
mysqlbinlog:二进制日志的客户端命令工具,支持离线查看二进制日志
命令格式:
mysqlbinlog [OPTIONS] log_file…
--start-position=# 指定开始位置
--stop-position=#
--start-datetime=
--stop-datetime=
--base64-output[=name]
-v -vvv
#时间格式:YYYY-MM-DD hh:mm:ss
范例:
mysqlbinlog --start-position=678 --stop-position=752 /var/lib/mysql/mariadb-
bin.000003 -v
mysqlbinlog --start-datetime="2018-01-30 20:30:10"
30 20:35:22" mariadb-bin.000003 -vvv
--stop-datetime="2018-01-
范例: 同步远程主机的二进制日志
#从10.0.0.8远程主机同步二进制日志到当前目录
[root@centos8 data]#mysqlbinlog -R --host=10.0.0.8 --user=test --password=123456
--raw --stop-never binlog.000002
二进制日志事件的格式:
# at 328
#151105 16:31:40 server id 1 end_log_pos 431
Query
thread_id=1
exec_time=0
error_code=0
use `mydb`/*!*/;
SET TIMESTAMP=1446712300/*!*/;
CREATE TABLE tb1 (id int, name char(30))
/*!*/;
事件发生的日期和时间:151105 16:31:40
事件发生的服务器标识:server id 1
事件的结束位置:end_log_pos 431
事件的类型:Query
事件发生时所在服务器执行此事件的线程的ID:thread_id=1
语句的时间戳与将其写入二进制文件中的时间差:exec_time=0
错误代码:error_code=0
事件内容:
GTID:Global Transaction ID,mysql5.6以mariadb10以上版本专属属性:GTID
清除指定二进制日志
PURGE { BINARY | MASTER } LOGS { TO 'log_name' | BEFORE datetime_expr }
范例:
PURGE BINARY LOGS TO 'mariadb-bin.000003'; #删除mariadb-bin.000003之前的日志
PURGE BINARY LOGS BEFORE '2017-01-23';
PURGE BINARY LOGS BEFORE '2017-03-22 09:25:30';
删除所有二进制日志,index文件重新记数
RESET MASTER [TO #]; #删除所有二进制日志文件,并重新生成日志文件,文件名从#开始记数,默认从1
开始,一般是master主机第一次启动时执行,MariaDB 10.1.6开始支持TO #
切换日志文件:
FLUSH LOGS;
范例:
[root@master ~]#file /var/lib/mysql/mariadb-bin.000001
/var/lib/mysql/mariadb-bin.000001: MySQL replication log, server id 18 MySQL
V5+, server version 10.3.17-MariaDB-log
范例: 切换二进制日志
[root@centos8 ~]#mysqladmin flush-binary-log
[root@centos8 ~]#mysqladmin flush-logs
[root@centos8 ~]#mysql
MariaDB [hellodb]> flush logs;
5 MySQL 备份和恢复
5.1 备份恢复概述
5.1.1 为什么要备份
灾难恢复:硬件故障、软件故障、自然灾害、黑客攻击、误操作测试等数据丢失场景
参考链接: https://www.toutiao.com/a6939518201961251359/
5.1.2 备份类型
完全备份,部分备份
完全备份:整个数据集
部分备份:只备份数据子集,如部分库或表
完全备份、增量备份、差异备份
增量备份:仅备份最近一次完全备份或增量备份(如果存在增量)以来变化的数据,备份较快,
还原复杂
差异备份:仅备份最近一次完全备份以来变化的数据,备份较慢,还原简单
注意:二进制日志文件不应该与数据文件放在同一磁盘
冷、温、热备份
冷备:读、写操作均不可进行,数据库停止服务
温备:读操作可执行;但写操作不可执行
热备:读、写操作均可执行
MyISAM:温备,不支持热备
InnoDB:都支持
物理和逻辑备份
物理备份:直接复制数据文件进行备份,与存储引擎有关,占用较多的空间,速度快
逻辑备份:从数据库中"导出"数据另存而进行的备份,与存储引擎无关,占用空间少,速度慢,可
能丢失精度
5.1.3 备份什么
数据
二进制日志、InnoDB的事务日志
用户帐号,权限设置,程序代码(存储过程、函数、触发器、事件调度器)
服务器的配置文件
5.1.4 备份注意要点
能容忍最多丢失多少数据
备份产生的负载
备份过程的时长
温备的持锁多久
恢复数据需要在多长时间内完成
需要备份和恢复哪些数据
5.1.5 还原要点
做还原测试,用于测试备份的可用性
还原演练,写成规范的技术文档
5.1.6 备份工具
cp, tar等复制归档工具:物理备份工具,适用所有存储引擎;只支持冷备;完全和部分备份
LVM的快照:先加读锁,做快照后解锁,几乎热备;借助文件系统工具进行备份
mysqldump:逻辑备份工具,适用所有存储引擎,对MyISAM存储引擎进行温备;支持完全或部
分备份;对InnoDB存储引擎支持热备,结合binlog的增量备份
xtrabackup:由Percona提供支持对InnoDB做热备(物理备份)的工具,支持完全备份、增量备份
MariaDB Backup: 从MariaDB 10.1.26开始集成,基于Percona XtraBackup 2.3.8实现
mysqlbackup:热备份, MySQL Enterprise Edition 组件
mysqlhotcopy:PERL 语言实现,几乎冷备,仅适用于MyISAM存储引擎,使用LOCK TABLES、
FLUSH TABLES和cp或scp来快速备份数据库
5.1.7 实战案例:数据库冷备份和还原
MySQL8.0
#备份过程
[root@centos8 ~]#systemctl stop mysqld
#备份数据
[root@centos8 ~]#rsync -a /var/lib/mysql 10.0.0.28:/data/
#如果配置及二进制文件相关有特殊设置也需要备份
#还原
[root@centos8 ~]#yum -y install mysql-server
[root@centos8 ~]#cp -a /data/mysql/* /var/lib/mysql/
[root@centos8 ~]#systemctl start mysqld
Mariadb10.3
#在目标服务器(10.0.0.18)安装mariadb-server,不启动服务
[root@centos8 ~]#dnf install mariadb-server
#在源主机(10.0.0.8)执行
[root@centos8 ~]# systemctl stop mariadb
#复制相关文件
[root@centos8 ~]# scp -r /var/lib/mysql/* 10.0.0.18:/var/lib/mysql/
[root@centos8 ~]# scp /etc/my.cnf.d/mariadb-server.cnf 10.0.0.18:/etc/my.cnf.d/
[root@centos8 ~]# scp -r /data/logbin/ 10.0.0.18:/data/ #10.0.0.18须事先存
在/data/目录
#复制相关文件并保留属性:可以用rsync
[root@centos8 ~]#rsync /etc/my.cnf.d/mariadb-server.cnf 10.0.0.18:/etc/my.cnf.d/
[root@centos8 ~]#rsync -av /var/lib/mysql/ 10.0.0.18:/var/lib/mysql/
[root@centos8 ~]#rsync -av/data/logbin/ 10.0.0.18:/data/ #10.0.0.18 须事先存
在/data/目录
#在目标主机(10.0.0.18)执行
[root@centos8 ~]#chown -R mysql.mysql /var/lib/mysql/
[root@centos8 ~]#chown -R mysql.mysql /data/logbin/
[root@centos8 ~]#systemctl start mariadb
5.2 mysqldump 备份工具
5.2.1 mysqldump 说明
逻辑备份工具:
mysqldump, mydumper, phpMyAdmin
Schema和数据存储在一起、巨大的SQL语句、单个巨大的备份文件
mysqldump是MySQL的客户端命令,通过mysql协议连接至mysql服务器进行备份
命令格式:
mysqldump [OPTIONS] database [tables] #支持指定数据库和指定多表的备份,但数据库本身定义
不备份
mysqldump [OPTIONS] -B DB1 [DB2 DB3...] #支持指定数据库备份,包含数据库本身定义也会备份
mysqldump [OPTIONS] -A [OPTIONS]
#备份所有数据库,包含数据库本身定义也会备份
mysqldump参考:
https://dev.mysql.com/doc/refman/5.7/en/mysqldump.html
mysqldump 常见通用选项:
-u, --user=name
User for login if not current user
-p, --password[=name] Password to use when connecting to server
-A, --all-databases #备份所有数据库,含create database
-B, --databases db_name… #指定备份的数据库,包括create database语句
-E, --events:#备份相关的所有event scheduler
-R, --routines:#备份所有存储过程和自定义函数
--triggers:#备份表相关触发器,默认启用,用--skip-triggers,不备份触发器
--default-character-set=utf8 #指定字符集
--master-data[=#]:#注意:MySQL8.0.26版以后,此选项变为--source-data
#此选项须启用二进制日志
#1:所备份的数据之前加一条记录为CHANGE MASTER TO语句,非注释,不指定#,默认为1,适合于主从复
制多机使用
#2:记录为被注释的#CHANGE MASTER TO语句,适合于单机使用,适用于备份还原
#此选项会自动关闭--lock-tables功能,自动打开-x | --lock-all-tables功能(除非开启--
single-transaction)
-F, --flush-logs #备份前滚动日志,锁定表完成后,执行flush logs命令,生成新的二进制日志文件,
配合-A 或 -B 选项时,会导致刷新多次数据库。建议在同一时刻执行转储和日志刷新,可通过和--single-
transaction或-x,--master-data 一起使用实现,此时只刷新一次二进制日志
--compact
#去掉注释,适合调试,节约备份占用的空间,生产不使用
#只备份表结构,不备份数据,即只备份create table
#只备份数据,不备份表结构,即不备份create table
#不备份create database,可被-A或-B覆盖
#备份mysql或相关时需要使用
-d, --no-data
-t, --no-create-info
-n,--no-create-db
--flush-privileges
-f, --force
#忽略SQL错误,继续执行
--hex-blob
#使用十六进制符号转储二进制列,当有包括BINARY,VARBINARY,BLOB,
BIT的数据类型的列时使用,避免乱码
-q, --quick
#不缓存查询,直接输出,加快备份速度
mysqldump的MyISAM存储引擎相关的备份选项:
MyISAM不支持事务,只能支持温备;不支持热备,所以必须先锁定要备份的库,而后启动备份操作
-x,--lock-all-tables #加全局读锁,锁定所有库的所有表,同时加--single-transaction或--
lock-tables选项会关闭此选项功能,注意:数据量大时,可能会导致长时间无法并发访问数据库
-l,--lock-tables #对于需要备份的每个数据库,在启动备份之前分别锁定其所有表,默认为on,--
skip-lock-tables选项可禁用,对备份MyISAM的多个库,可能会造成数据不一致
#注:以上选项对InnoDB表一样生效,实现温备,但不推荐使用
mysqldump的InnoDB存储引擎相关的备份选项:
InnoDB 存储引擎支持事务,可以利用事务的相应的隔离级别,实现热备,也可以实现温备但不建议用
--single-transaction
#此选项Innodb中推荐使用,不适用MyISAM,此选项会开始备份前,先执行START TRANSACTION指令开启
事务
#此选项通过在单个事务中转储所有表来创建一致的快照。 仅适用于存储在支持多版本控制的存储引擎中的表
(目前只有InnoDB可以); 转储不保证与其他存储引擎保持一致。 在进行单事务转储时,要确保有效的转储
文件(正确的表内容和二进制日志位置),没有其他连接应该使用以下语句:ALTER TABLE,DROP TABLE,
RENAME TABLE,TRUNCATE TABLE,此选项和--lock-tables(此选项隐含提交挂起的事务)选项是相互
排斥,备份大型表时,建议将--single-transaction选项和--quick结合一起使用
5.2.2 生产环境实战备份策略
InnoDB建议备份策略
mysqldump -uroot -p -A -F -E -R --triggers --single-transaction --master-data=1
--flush-privileges --default-character-set=utf8 --hex-blob
>$/fullbak_$.sql
MyISAM建议备份策略
mysqldump -uroot -p -A -F -E -R -x --master-data=1 --flush-privileges --
triggers --default-character-set=utf8 --hex-blob
>$/fullbak_$.sql
5.2.3 mysqldump 备份还原实战案例
5.2.3.1 实战案例:特定数据库的备份脚本
[root@centos8 ~]#cat mysql_backup.sh
#!/bin/bash
TIME=`date +%F_%H-%M-%S`
DIR=/backup
DB=hellodb
PASS=magedu
[ -d $DIR ] || mkdir $DIR
mysqldump -uroot -p "$PASS" -F -E -R --triggers --single-transaction --master-
data=2 --default-character-set=utf8 -q -B $DB | gzip
$/$_$.sql.gz
>
5.2.3.2 实战案例:分库备份并压缩
[root@centos8 ~]#for db in `mysql -uroot -e 'show databases'|grep -Ev
'^(Database|information_schema|performance_schema)$'`;do mysqldump -B $db | gzip
> /backup/$db.sql.gz;done
[root@centos8 ~]#mysql -uroot -e 'show databases'|grep -Ev
'^(Database|information_schema|performance_schema)$'|while read db;do mysqldump -
B $db | gzip > /backup/$db.sql.gz;done
[root@centos8 ~]#mysql -uroot -e 'show databases'|grep -Ev
'^(Database|information_schema|performance_schema)$' | sed -rn 's#(.*)#mysqldump
-B \1 | gzip > /backup/\1.sql.gz#p' |bash
[root@centos8 ~]#mysql -uroot -e 'show databases'|sed -rn
'/^(Database|information_schema|performance_schema)$/!s#(.*)#mysqldump -B \1 |
gzip > /backup/\1.sql.gz#p' |bash
5.2.3.3 实战案例:分库备份的实战脚本
[root@centos8 ~]#cat backup_db.sh
#!/bin/bash
TIME=`date +%F_%H-%M-%S`
DIR=/backup
PASS=magedu
[ -d "$DIR" ] || mkdir $DIR
for DB in `mysql -uroot -p "$PASS" -e 'show databases' | grep -Ev
"^Database|.*schema$"`;do
mysqldump -F --single-transaction --master-data=2 --default-character-
set=utf8 -q -B $DB | gzip
done
>
$/$_$.sql.gz
5.2.3.4 实战案例:完全备份和还原
#开启二进制日志
[root@centos8 ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
log-bin
#备份
[root@centos8 ~]#mysqldump -uroot -pmagedu -A -F --single-transaction --master-
data=2 |gzip > /backup/all-`date +%F`.sql.gz
#还原
[root@centos8 backup]#dnf install mariadb-server
[root@centos8 backup]#gzip -d all-2019-11-27.sql.gz
[root@centos8 ~]#mysql
MariaDB [(none)]> set sql_log_bin=off;
MariaDB [(none)]> source /backup/all-2019-11-27.sql
MariaDB [(none)]> set sql_log_bin=on;
5.2.3.5 实战案例:利用二进制日志,还原数据库最新状态
#二进制日志独立存放
[mysqld]
log-bin=/data/mysql/mysql-bin
#完全备份,并记录备份的二进制位置
mysqldump -uroot -pmagedu -A -F --default-character-set=utf8 --single-
transaction --master-data=2 | gzip > /backup/all_`date +%F`.sql.gz
#修改数据库
insert students (name,age,gender)value('mage',20,'M');
insert students (name,age,gender)value('wang',22,'M');
#损坏数据库
rm -rf /var/lib/mysql/*
#还原
cd /backup
gzip -d all_2019-11-25.sql.gz
#CentOS 8 需要事先生成数据库相关文件,CentOS7 不需要执行此步
mysql_install_db --user=mysql
systemctl restart mariadb
MariaDB [(none)]> show master logs;
+------------------+-----------+
| Log_name
| File_size |
+------------------+-----------+
| mysql-bin.000001 |
| mysql-bin.000002 |
| mysql-bin.000003 |
998 |
28090 |
342 |
+------------------+-----------+
3 rows in set (0.000 sec)
MariaDB [(none)]>set sql_log_bin=0;
MariaDB [(none)]>source /data/all_2019-11-25.sql
[root@centos8 ~]#grep '^-- CHANGE MASTER TO' /data/all_2019-11-25.sql
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=328;
#二进制日志的备份
[root@centos8 mysql]#mysqlbinlog mysql-bin.000001 --start-position=328 >
/backup/inc.sql
[root@centos8 mysql]#mysqlbinlog mysql-bin.000002 >> /backup/inc.sql
MariaDB [(none)]>set sql_log_bin=0;
MariaDB [(none)]>source /backup/inc.sql
MariaDB [(none)]>set sql_log_bin=1;
5.2.3.6 实战案例:mysqldump 和二进制日志结合实现差异(增量)备份
[root@centos8 ~]#mysqldump -uroot -p -A -F --single-transaction --master-data=2
|gzip > /backup/all-`date +%F`.sql.gz
#观察上面备份文件中记录的二进制文件和位置,定期将其之后生成的所有二进制日志进行复制备份
[root@centos8 ~]#cp /var/lib/mysql/mariadb-bin.000003 /backup #假设mariadb-
bin.000003是后续生成的二进制日志
[root@centos8 ~]#mysqlbinlog backup/mariadb-bin.000003 > /backup/inc.sql
5.2.3.7 实战案例:恢复误删除的表
案例说明:每天2:30做完全备份,早上10:00误删除了表students,10:10才发现故障,现需要将数
据库还原到10:10的状态,且恢复被删除的students表
#完全备份
[root@centos8 ~]#mysqldump -uroot -p -A -F --single-transaction --master-data=2
> /backup/allbackup_`date +%F_%T`.sql
[root@centos8 ~]#ll /backup/
total 2992
-rw-r--r-- 1 root root 3060921 Nov 27 10:20 allbackup_2019-11-27_10:20:08.sql
#完全备份后数据更新
MariaDB [testdb]> insert students (name,age,gender) values('rose',20,'f');
Query OK, 1 row affected (0.001 sec)
MariaDB [testdb]> insert students (name,age,gender) values('jack',22,'M');
Query OK, 1 row affected (0.001 sec)
#10:00误删除了一个重要的表
MariaDB [testdb]> drop table students;
Query OK, 0 rows affected (0.021 sec)
#后续其它表继续更新
MariaDB [testdb]> use hellodb;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
MariaDB [hellodb]> insert teachers (name,age,gender)values('wang',30,'M');
Query OK, 1 row affected (0.002 sec)
MariaDB [hellodb]> insert teachers (name,age,gender)values('mage',28,'M');
Query OK, 1 row affected (0.002 sec)
MariaDB [hellodb]> select * from teachers;
+-----+---------------+-----+--------+
| TID | Name
| Age | Gender |
+-----+---------------+-----+--------+
|
|
|
|
|
|
1 | Song Jiang
|
45 | M
|
|
|
|
|
|
2 | Zhang Sanfeng | 94 | M
3 | Miejue Shitai | 77 | F
4 | Lin Chaoying
5 | wang
|
|
|
93 | F
30 | M
28 | M
6 | mage
+-----+---------------+-----+--------+
6 rows in set (0.001 sec)
#10:10发现表删除,进行还原
#停止数据库访问
#从完全备份中,找到二进制位置
[root@centos8 ~]#grep '\\ CHANGE MASTER TO' /backup/allbackup_2019-11-
27_10\20\08.sql
-- CHANGE MASTER TO MASTER_LOG_FILE='mariadb-bin.000003', MASTER_LOG_POS=389;
#备份从完全备份后的二进制日志
[root@centos8 ~]#mysqlbinlog --start-position=389 /var/lib/mysql/mariadb-
bin.000003 > /backup/inc.sql
#找到误删除的语句,从备份中删除此语句
[root@centos8 ~]#vim /data/inc.sql
#DROP TABLE `student_info` /* generated by server */
#如果文件过大,可以使用sed实现
[root@centos8 ~]#sed -i.bak '/^DROP TABLE/d' /data/inc.sql
#利用完全备份和修改过的二进制日志进行还原
[root@centos8 ~]#mysql -uroot -p
MariaDB [hellodb]> set sql_log_bin=0;
MariaDB [hellodb]> source /backup/allbackup_2019-11-27_10:20:08.sql;
MariaDB [hellodb]> source /backup/inc.sql
MariaDB [hellodb]> set sql_log_bin=1;
5.3 xtrabackup 备份工具
5.3.1 xtrabackup 工具介绍
Percona 公司
官网:www.percona.com
percona-server
InnoDB --> XtraDB
Xtrabackup备份工具
percona提供的mysql数据库备份工具,惟一开源的能够对innodb和xtradb数据库进行热备的工具
手册:https://www.percona.com/doc/percona-xtrabackup/LATEST/index.html
下载: https://www.percona.com/downloads/
xtrabackup 特点:
备份还原过程快速、可靠
备份过程不会打断正在执行的事务
能够基于压缩等功能节约磁盘空间和流量
自动实现备份检验
开源,免费
xtrabackup工具文件组成
Xtrabackup2.2 版之前包括4个可执行文件:
innobackupex:
xtrabackup:
xbcrypt:
Perl 脚本
C/C++,编译的二进制程序
加解密
xbstream:
支持并发写的流文件格式
说明:
xtrabackup 是用来备份 InnoDB 表的,不能备份非 InnoDB 表,和 MySQL Server 没有交互
innobackupex 脚本用来备份非 InnoDB 表,同时会调用 xtrabackup 命令来备份 InnoDB 表,还会和
MySQL Server 发送命令进行交互,如加全局读锁(FTWRL)、获取位点(SHOW SLAVE STATUS)
等。即innobackupex是在 xtrabackup 之上做了一层封装实现的
xtrabackup的新版变化
xtrabackup版本升级到2.4后,相比之前的2.1有了比较大的变化:innobackupex 功能全部集成到
xtrabackup 里面,只有一个 binary程序,另外为了兼容考虑,innobackupex作为 xtrabackup 的软链
接,即xtrabackup现在支持非Innodb表备份,并且 Innobackupex 在下一版本中移除,建议通过
xtrabackup替换innobackupex
xtrabackup备份过程
备份生成的相关文件
使用innobackupex备份时,其会调用xtrabackup备份所有的InnoDB表,复制所有关于表结构定义的相
关文件(.frm)、以及MyISAM、MERGE、CSV和ARCHIVE表的相关文件,同时还会备份触发器和数据库配
置信息相关的文件。这些文件会被保存至一个以时间命名的目录中,在备份时,innobackupex还会在备
份目录中创建如下文件:
xtrabackup_info:文本文件,innobackupex工具执行时的相关信息,包括版本,备份选项,备份
时长,备份LSN(log sequence number日志序列号),BINLOG的位置
xtrabackup_checkpoints:文本文件,备份类型(如完全或增量)、备份状态(如是否已经为
prepared状态)和LSN范围信息,每个InnoDB页(通常为16k大小)都会包含一个日志序列号LSN。
LSN是整个数据库系统的系统版本号,每个页面相关的LSN能够表明此页面最近是如何发生改变的
xtrabackup_binlog_info:文本文件,MySQL服务器当前正在使用的二进制日志文件及至备份这一
刻为止二进制日志事件的位置,可利用实现基于binlog的恢复
backup-my.cnf:文本文件,备份命令用到的配置选项信息
xtrabackup_logfile:备份生成的二进制日志文件
范例:相关文件
[root@centos8 ~]#ll /backup/
total 12340
-rw-r----- 1 root root
drwxr-x--- 2 root root
-rw-r----- 1 root root
487 Jun 12 15:07 backup-my.cnf
272 Jun 12 15:07 hellodb
425 Jun 12 15:07 ib_buffer_pool
-rw-r----- 1 root root 12582912 Jun 12 15:07 ibdata1
drwxr-x--- 2 root root
drwxr-x--- 2 root root
drwxr-x--- 2 root root
-rw-r----- 1 root root
-rw-r----- 1 root root
-rw-r----- 1 root root
-rw-r----- 1 root root
4096 Jun 12 15:07 mysql
8192 Jun 12 15:07 performance_schema
8192 Jun 12 15:07 sys
25 Jun 12 15:07 xtrabackup_binlog_info
135 Jun 12 15:07 xtrabackup_checkpoints
479 Jun 12 15:07 xtrabackup_info
2560 Jun 12 15:07 xtrabackup_logfile
[root@centos8 ~]#cat /backup/xtrabackup_info
uuid = 55a26ea0-ac7b-11ea-a8ab-000c293f7395
name =
tool_name = xtrabackup
tool_command = -uroot -pmagedu --backup --target-dir=/backup/
tool_version = 2.4.20
ibbackup_version = 2.4.20
server_version = 5.7.29-log
start_time = 2020-06-12 15:07:08
end_time = 2020-06-12 15:07:10
lock_time = 1
binlog_pos = filename 'centos8-bin.000002', position '10185'
innodb_from_lsn = 0
innodb_to_lsn = 2687527
partial = N
incremental = N
format = file
compact = N
compressed = N
encrypted = N
[root@centos8 ~]#cat /backup/xtrabackup_checkpoints
backup_type = full-backuped
from_lsn = 0
to_lsn = 2687527
last_lsn = 2687536
compact = 0
recover_binlog_info = 0
flushed_lsn = 2687536
[root@centos8 ~]#cat /backup/xtrabackup_binlog_info
centos8-bin.000002 10185
[root@centos8 ~]#cat /backup/backup-my.cnf
# This MySQL options file was generated by innobackupex.
# The MySQL server
[mysqld]
innodb_checksum_algorithm=crc32
innodb_log_checksum_algorithm=strict_crc32
innodb_data_file_path=ibdata1:12M:autoextend
innodb_log_files_in_group=2
innodb_log_file_size=50331648
innodb_fast_checksum=false
innodb_page_size=16384
innodb_log_block_size=512
innodb_undo_directory=./
innodb_undo_tablespaces=0
server_id=1
redo_log_version=1
server_uuid=6fb9641a-ac79-11ea-8bed-000c293f7395
master_key_id=0
[root@centos8 ~]#file /backup/xtrabackup_logfile
/backup/xtrabackup_logfile: data
5.3.2 xtrabackup 安装
在EPEL源中
yum install percona-xtrabackup
范例: CentOS 8没有提供
[root@centos7 ~]#yum info percona-xtrabackup
Available Packages
Name
: percona-xtrabackup
Arch
: x86_64
Version
Release
Size
: 2.3.6
: 1.el7
: 4.6 M
Repo
: epel/7/x86_64
Summary
MariaDB
URL
: Online backup for InnoDB/XtraDB in MySQL, Percona Server and
: http://www.percona.com/software/percona-xtrabackup/
: GPLv2
License
Description : Online backup for InnoDB/XtraDB in MySQL, MariaDB and Percona
Server.
范例: 最新版本下载安装:
https://www.percona.com/downloads/XtraBackup/LATEST/
[root@centos8 ~]#ll percona-xtrabackup-24-2.4.20-1.el8.x86_64.rpm
-rw-r--r-- 1 root root 8045696 Oct 12 08:42 percona-xtrabackup-24-2.4.20-
1.el8.x86_64.rpm
[root@centos8 ~]#yum -y install percona-xtrabackup-24-2.4.20-1.el8.x86_64.rpm
Last metadata expiration check: 0:05:30 ago on Mon 12 Oct 2020 09:43:57 AM CST.
Dependencies resolved.
================================================================================
============================================
Package
Architecture
Size
Version
Repository
================================================================================
============================================
Installing:
percona-xtrabackup-24
x86_64
7.7 M
2.4.20-1.el8
@commandline
Installing dependencies:
libev
x86_64
52 k
4.24-6.el8
3.0.7-1.el8
3.0.7-1.el8
4.046-
AppStream
mariadb-connector-c
AppStream
x86_64
148 k
noarch
13 k
mariadb-connector-c-config
AppStream
perl-DBD-MySQL
3.module_el8.1.0+203+e45423dc
perl-DBI
x86_64
AppStream
x86_64
AppStream
156 k
1.641-
3.module_el8.1.0+199+8f0a6bbd
perl-Math-BigInt
BaseOS
740 k
noarch
196 k
1:1.9998.11-7.el8
perl-Math-Complex
BaseOS
noarch
108 k
1.59-416.el8
Enabling module streams:
perl
5.26
perl-DBD-MySQL
perl-DBI
4.046
1.641
Transaction Summary
================================================================================
============================================
Install 8 Packages
Total size: 9.1 M
Installed size: 35 M
Downloading Packages:
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Running scriptlet: mariadb-connector-c-3.0.7-1.el8.x86_64
1/1
Preparing
:
1/1
Installing
: mariadb-connector-c-config-3.0.7-1.el8.noarch
1/8
warning: /etc/my.cnf created as /etc/my.cnf.rpmnew
Installing
Installing
Installing
Installing
Installing
: mariadb-connector-c-3.0.7-1.el8.x86_64
2/8
: libev-4.24-6.el8.x86_64
3/8
: perl-Math-Complex-1.59-416.el8.noarch
4/8
: perl-Math-BigInt-1:1.9998.11-7.el8.noarch
5/8
: perl-DBI-1.641-3.module_el8.1.0+199+8f0a6bbd.x86_64
6/8
Installing
Installing
: perl-DBD-MySQL-4.046-3.module_el8.1.0+203+e45423dc.x86_64
7/8
: percona-xtrabackup-24-2.4.20-1.el8.x86_64
8/8
Running scriptlet: percona-xtrabackup-24-2.4.20-1.el8.x86_64
8/8
Verifying
Verifying
Verifying
Verifying
Verifying
Verifying
Verifying
Verifying
: perl-Math-BigInt-1:1.9998.11-7.el8.noarch
1/8
: perl-Math-Complex-1.59-416.el8.noarch
2/8
: libev-4.24-6.el8.x86_64
3/8
: mariadb-connector-c-3.0.7-1.el8.x86_64
4/8
: mariadb-connector-c-config-3.0.7-1.el8.noarch
5/8
: perl-DBD-MySQL-4.046-3.module_el8.1.0+203+e45423dc.x86_64
6/8
: perl-DBI-1.641-3.module_el8.1.0+199+8f0a6bbd.x86_64
7/8
: percona-xtrabackup-24-2.4.20-1.el8.x86_64
8/8
Installed:
libev-4.24-6.el8.x86_64
mariadb-
percona-
perl-DBI-
perl-Math-
connector-c-3.0.7-1.el8.x86_64
mariadb-connector-c-config-3.0.7-1.el8.noarch
xtrabackup-24-2.4.20-1.el8.x86_64
perl-DBD-MySQL-4.046-3.module_el8.1.0+203+e45423dc.x86_64
1.641-3.module_el8.1.0+199+8f0a6bbd.x86_64
perl-Math-BigInt-1:1.9998.11-7.el8.noarch
Complex-1.59-416.el8.noarch
Complete!
[root@centos8 ~]#rpm -ql percona-xtrabackup-24-2.4.20
/usr/bin/innobackupex
/usr/bin/xbcloud
/usr/bin/xbcloud_osenv
/usr/bin/xbcrypt
/usr/bin/xbstream
/usr/bin/xtrabackup
/usr/lib/.build-id
/usr/lib/.build-id/07
/usr/lib/.build-id/07/7cff02ee26ea646a822a3f936194758707edd1
/usr/lib/.build-id/39
/usr/lib/.build-id/39/f3e9ba1bfa15a43b78bca58bc6ae9c3b15f1b5
/usr/lib/.build-id/3a
/usr/lib/.build-id/3a/911c034513e809c6752d5297c9d69c9c19bc9a
/usr/lib/.build-id/85
/usr/lib/.build-id/85/3597a47905af2ef200a6def4fb2582dc3ff60b
/usr/lib/.build-id/ad
/usr/lib/.build-id/ad/45538c7f190bf3875f39562c7e33c39ef9425c
/usr/lib/.build-id/ea
/usr/lib/.build-id/ea/0e60d4d718a1127d337df206d7004656433ebc
/usr/lib64/xtrabackup/plugin/keyring_file.so
/usr/lib64/xtrabackup/plugin/keyring_vault.so
/usr/share/doc/percona-xtrabackup-24
/usr/share/doc/percona-xtrabackup-24/COPYING
/usr/share/man/man1/innobackupex.1.gz
/usr/share/man/man1/xbcrypt.1.gz
/usr/share/man/man1/xbstream.1.gz
/usr/share/man/man1/xtrabackup.1.gz
[root@centos8 ~]#ll /usr/bin/innobackupex
lrwxrwxrwx 1 root root 10 Apr 21 04:42 /usr/bin/innobackupex -> xtrabackup
[root@centos8 ~]#file /usr/bin/xtrabackup
/usr/bin/xtrabackup: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux),
dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux
3.2.0, BuildID[sha1]=ad45538c7f190bf3875f39562c7e33c39ef9425c, stripped
5.3.3 xtrabackup 用法
xtrabackup工具备份和还原,需要三步实现
1. 备份:对数据库做完全或增量备份
2. 预准备: 还原前,先对备份的数据,整理至一个临时目录
3. 还原:将整理好的数据,复制回数据库目录中
xtrabackup 选项参考:
https://www.percona.com/doc/percona-xtrabackup/LATEST/genindex.html
备份:
innobackupex [option] BACKUP-ROOT-DIR
选项说明:
--user:#该选项表示备份账号
--password:#该选项表示备份的密码
--host:#该选项表示备份数据库的地址
--databases:#该选项接受的参数为数据库名,如果要指定多个数据库,彼此间需要以空格隔开;
如:"xtra_test dba_test",同时,在指定某数据库时,也可以只指定其中的某张表。
如:"mydatabase.mytable"。该选项对innodb引擎表无效,还是会备份所有innodb表
--defaults-file:#该选项指定从哪个文件读取MySQL配置,必须放在命令行第一个选项位置
--incremental:#该选项表示创建一个增量备份,需要指定--incremental-basedir
--incremental-basedir:#该选项指定为前一次全备份或增量备份的目录,与--incremental同时使用
--incremental-dir:#该选项表示还原时增量备份的目录
--include=name:#指定表名,格式:databasename.tablename
Prepare预准备:
innobackupex --apply-log [option] BACKUP-DIR
选项说明:
--apply-log:#一般情况下,在备份完成后,数据尚且不能用于恢复操作,因为备份的数据中可能会包含尚
未提交的事务或已经提交但尚未同步至数据文件中的事务。因此,此时数据文件仍处理不一致状态。此选项作
用是通过回滚未提交的事务及同步已经提交的事务至数据文件使数据文件处于一致性状态
--use-memory:#和--apply-log选项一起使用,当prepare 备份时,做crash recovery分配的内存大
小,单位字节,也可1MB,1M,1G,1GB等,推荐1G
--export:#表示开启可导出单独的表之后再导入其他Mysql中
--redo-only:#此选项在prepare base full backup,往其中合并增量备份时候使用,但不包括对最后
一个增量备份的合并
还原:
innobackupex --copy-back [选项] BACKUP-DIR
innobackupex --move-back [选项] [--defaults-group=GROUP-NAME] BACKUP-DIR
选项说明:
--copy-back:#做数据恢复时将备份数据文件拷贝到MySQL服务器的datadir
--move-back:#这个选项与--copy-back相似,唯一的区别是它不拷贝文件,而是移动文件到目的地。这
个选项移除backup文件,用时候必须小心。使用场景:没有足够的磁盘空间同事保留数据文件和Backup副本
--force-non-empty-directories #指定该参数时候,使得innobackupex --copy-back或--move-
back选项转移文件到非空目录,已存在的文件不会被覆盖。如果--copy-back和--move-back文件需要从备
份目录拷贝一个在datadir已经存在的文件,会报错失败
还原注意事项:
1. datadir 目录必须为空。除非指定innobackupex --force-non-empty-directorires选项指定,否则--
copy-back选项不会覆盖
2. 在restore之前,必须shutdown MySQL实例,不能将一个运行中的实例restore到datadir目录中
3. 由于文件属性会被保留,大部分情况下需要在启动实例之前将文件的属主改为mysql,这些文件将
属于创建备份的用户, 执行chown -R mysql:mysql /data/mysql,以上需要在用户调用
innobackupex之前完成
5.3.4 实战案例:利用 xtrabackup 实现完全备份及还原
注意:目前percona-xtrabackup-24-2.4.18-1.el8.x86_64.rpm不支持CentOS 8上的mariadb-10.3版本
案例: 利用xtrabackup8.0 完全备份和还原MySQL8.0
1 安装xtrabackup包
[root@centos8 ~]#yum -y install percona-xtrabackup-80-8.0.23-16.1.el8.x86_64.rpm
2 在原主机做完全备份到/backup
[root@centos8 ~]#mkdir /backup
[root@centos8 ~]#xtrabackup -uroot -pmagedu --backup --target-dir=/backup/base
#目标主机无需创建/backup目录,直接复制目录本身
[root@centos8 ~]#scp -r /backup/
目标主机:/
3 在目标主机上还原
注意:恢复主机MySQL服务停止,并且数据目录为空
1)预准备:确保数据一致,提交完成的事务,回滚未完成的事务
[root@centos8 ~]#yum -y install percona-xtrabackup-80-8.0.23-16.1.el8.x86_64.rpm
[root@centos8 ~]#xtrabackup --prepare --target-dir=/backup/base
2)复制到数据库目录
注意:数据库目录必须为空,MySQL服务不能启动
[root@centos8 ~]#xtrabackup --copy-back --target-dir=/backup/base
3)还原属性
[root@centos8 ~]#chown -R mysql:mysql /var/lib/mysql
4)启动服务
[root@centos8 ~]#service mysqld start
案例:新版 xtrabackup完全备份及还原
本案例基于CentOS 8 的 MySQL5.7 实现,也支持MySQL5.5和Mariadb5.5,和上面案例步骤相同
1 安装xtrabackup包
#先安装MySQL5.7和xtrabackup包
[root@centos8 ~]#yum -y install percona-xtrabackup-24-2.4.20-1.el8.x86_64.rpm
2 在原主机做完全备份到/backup
[root@centos8 ~]#mkdir /backup
[root@centos8 ~]#xtrabackup -uroot -pmagedu --backup --target-dir=/backup/base
#目标主机无需创建/backup目录,直接复制目录本身
[root@centos8 ~]#scp -r /backup/
目标主机:/
3 在目标主机上还原
1)预准备:确保数据一致,提交完成的事务,回滚未完成的事务
[root@centos8 ~]#yum -y install percona-xtrabackup-24-2.4.20-1.el8.x86_64.rpm
[root@centos8 ~]#xtrabackup --prepare --target-dir=/backup/base
2)复制到数据库目录
注意:数据库目录必须为空,MySQL服务不能启动
[root@centos8 ~]#xtrabackup --copy-back --target-dir=/backup/base
3)还原属性
[root@centos8 ~]#chown -R mysql:mysql /var/lib/mysql
4)启动服务
[root@centos8 ~]#service mysqld start
案例:旧版xtrabackup完全备份及还原
1 在源主机备份
innobackupex --user=root
/backup
scp -r /backup/2018-02-23_11-55-57/
目标主机:/data/
2 在目标主机预准备并还原
#预准备
innobackupex --apply-log /data/2018-02-23_11-55-57/
#还原过程
systemctl stop mariadb
rm -rf /var/lib/mysql/*
innobackupex --copy-back /data/2018-02-23_11-55-57/
chown -R mysql.mysql /var/lib/mysql/
systemctl start mariadb
5.3.5 实战案例:利用xtrabackup完全,增量备份及还原
案例: 利用xtrabackup8.0 完全,增量备份及还原MySQL8.0
1 备份过程
1)完全备份:
[root@centos8 ~]#yum -y install percona-xtrabackup-24-2.4.20-1.el8.x86_64.rpm
[root@centos8 ~]#mkdir /backup/
[root@centos8 ~]#xtrabackup -uroot -pmagedu --backup --target-dir=/backup/base
2)第一次修改数据
3)第一次增量备份
[root@centos8 ~]#xtrabackup -uroot -pmagedu --backup --target-dir=/backup/inc1 --
incremental-basedir=/backup/base
4)第二次修改数据
5)第二次增量
[root@centos8 ~]#xtrabackup -uroot -pmagedu --backup --target-dir=/backup/inc2 --
incremental-basedir=/backup/inc1
6)[root@centos8 ~]#scp -r /backup/* 目标主机:/backup/
#备份过程生成三个备份目录
/backup/{base,inc1,inc2}
2还原过程
1)预准备完成备份,此选项--apply-log-only 阻止回滚未完成的事务
[root@centos8 ~]#yum -y install percona-xtrabackup-24-2.4.20-1.el8.x86_64.rpm
[root@centos8 ~]#xtrabackup --prepare --apply-log-only --target-dir=/backup/base
2)合并第1次增量备份到完全备份
[root@centos8 ~]#xtrabackup --prepare --apply-log-only --target-dir=/backup/base
--incremental-dir=/backup/inc1
3)合并第2次增量备份到完全备份:最后一次还原不需要加选项--apply-log-only
[root@centos8 ~]#xtrabackup --prepare --target-dir=/backup/base --incremental-
dir=/backup/inc2
4)复制到数据库目录,注意数据库目录必须为空,MySQL服务不能启动
[root@centos8 ~]#xtrabackup --copy-back --target-dir=/backup/base
5)还原属性:
[root@centos8 ~]#chown -R mysql:mysql /var/lib/mysql
6)启动服务:
[root@centos8 ~]#service mysqld start
案例:新版xtrabackup完全,增量备份及还原
和上面案例步骤相同
1 备份过程
1)完全备份:
[root@centos8 ~]#mkdir /backup/
[root@centos8 ~]#xtrabackup -uroot -pmagedu --backup --target-dir=/backup/base
2)第一次修改数据
3)第一次增量备份
[root@centos8 ~]#xtrabackup -uroot -pmagedu --backup --target-dir=/backup/inc1 --
incremental-basedir=/backup/base
#查看xtrabackup相关文件
[root@centos8 ~]#cat /backup/inc1/xtrabackup_info
uuid = 90be5bf4-0c32-11eb-b285-000c29e10e53
name =
tool_name = xtrabackup
tool_command = -uroot -pmagedu --backup --target-dir=/backup/inc1 --incremental-
basedir=/backup/base
tool_version = 2.4.20
ibbackup_version = 2.4.20
server_version = 5.7.29-log
start_time = 2020-10-12 10:28:06
end_time = 2020-10-12 10:28:08
lock_time = 1
binlog_pos = filename 'centos8-bin.000002', position '10735'
innodb_from_lsn = 2686016
innodb_to_lsn = 2691308
partial = N
incremental = Y
format = file
compact = N
compressed = N
encrypted = N
[root@centos8 ~]#cat /backup/inc1/xtrabackup_checkpoints
backup_type = incremental
from_lsn = 2686016
to_lsn = 2691308
last_lsn = 2691317
compact = 0
recover_binlog_info = 0
flushed_lsn = 2691317
[root@centos8 ~]#cat /backup/inc1/xtrabackup_binlog_info
centos8-bin.000002 10735
4)第二次修改数据
5)第二次增量
[root@centos8 ~]#xtrabackup -uroot -pmagedu --backup --target-dir=/backup/inc2 --
incremental-basedir=/backup/inc1
#查看xtrabackup相关文件
root@centos8 ~]#cat /backup/inc2/xtrabackup_info
uuid = 21b215ee-0c33-11eb-b285-000c29e10e53
name =
tool_name = xtrabackup
tool_command = -uroot -pmagedu --backup --target-dir=/backup/inc2 --incremental-
basedir=/backup/inc1
tool_version = 2.4.20
ibbackup_version = 2.4.20
server_version = 5.7.29-log
start_time = 2020-10-12 10:32:09
end_time = 2020-10-12 10:32:11
lock_time = 1
binlog_pos = filename 'centos8-bin.000002', position '11285'
innodb_from_lsn = 2691308
innodb_to_lsn = 2696589
partial = N
incremental = Y
format = file
compact = N
compressed = N
encrypted = N
[root@centos8 ~]#cat /backup/inc2/xtrabackup_checkpoints
backup_type = incremental
from_lsn = 2691308
to_lsn = 2696589
last_lsn = 2696598
compact = 0
recover_binlog_info = 0
flushed_lsn = 2696598
[root@centos8 ~]#cat /backup/inc2/xtrabackup_binlog_info
centos8-bin.000002 11285
6)[root@centos8 ~]#scp -r /backup/* 目标主机:/backup/
#备份过程生成三个备份目录
/backup/{base,inc1,inc2}
2还原过程
1)预准备完成备份,此选项--apply-log-only 阻止回滚未完成的事务
[root@centos8 ~]#xtrabackup --prepare --apply-log-only --target-dir=/backup/base
2)合并第1次增量备份到完全备份
[root@centos8 ~]#xtrabackup --prepare --apply-log-only --target-dir=/backup/base
--incremental-dir=/backup/inc1
3)合并第2次增量备份到完全备份:最后一次还原不需要加选项--apply-log-only
[root@centos8 ~]#xtrabackup --prepare --target-dir=/backup/base --incremental-
dir=/backup/inc2
4)复制到数据库目录,注意数据库目录必须为空,MySQL服务不能启动
[root@centos8 ~]#xtrabackup --copy-back --target-dir=/backup/base
5)还原属性:
[root@centos8 ~]#chown -R mysql:mysql /var/lib/mysql
6)启动服务:
[root@centos8 ~]#service mysqld start
案例:旧版xtrabackup完全,增量备份及还原
1 在源主机备份
innobackupex /backup
mkdir /backup/inc{1,2}
#修改数据库内容
innobackupex --incremental /backup/inc1 --incremental-basedir=/backup/2018-02-
23_14-21-42(完全备份生成的路径)
#再次修改数据库内容
innobackupex --incremental /backup/inc2 --incremental-
basedir=/backup/inc1/2018-02-23_14-26-17 (上次增量备份生成的路径)
scp
-r
/backup/*
目标主机:/data/
2 在目标主机还原
#预准备过程
innobackupex --apply-log --redo-only /data/2018-02-23_14-21-42/
innobackupex --apply-log --redo-only /data/2018-02-23_14-21-42/ --incremental-
dir=/data/inc1/2018-02-23_14-26-17
innobackupex --apply-log /data/2018-02-23_14-21-42/ --incremental-
dir=/data/inc2/2018-02-23_14-28-29/
#还原过程
不启动mariadb
systemctl stop mariadb
rm -rf /var/lib/mysql/*
innobackupex --copy-back /data/2018-02-23_14-21-42/
chown -R mysql.mysql /var/lib/mysql/
systemctl start mariadb
5.3.6 实战案例:xtrabackup单表导出和导入
#导出
1 单表备份
innobackupex -uroot -pmagedu --include='hellodb.students' /backup
2备份表结构
mysql -e 'show create table hellodb.students' > student.sql
3删除表
mysql -e 'drop table hellodb.students'
#导出
4 innobackupex --apply-log --export /backups/2018-02-23_15-03-23/
5 创建表
mysql>CREATE TABLE `students` (
`StuID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`Name` varchar(50) NOT NULL,
`Age` tinyint(3) unsigned NOT NULL,
`Gender` enum('F','M') NOT NULL,
`ClassID` tinyint(3) unsigned DEFAULT NULL,
`TeacherID` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`StuID`)
) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8
6 删除表空间
alter table students discard tablespace;
7 cp /backups/2018-02-23_15-03-23/hellodb/students.{cfg,exp,ibd}
/var/lib/mysql/hellodb/
8 chown -R mysql.mysql /var/lib/mysql/hellodb/
9 mysql>alter table students import tablespace;
6 MySQL 集群 Cluster
服务性能扩展方式
Scale Up,向上扩展,垂直扩展
Scale Out,向外扩展,横向扩展
6.1 MySQL 主从复制
6.1.1 主从复制架构和原理
6.1.1.1 MySQL的主从复制
读写分离
复制:每个节点都有相同的数据集,向外扩展,基于二进制日志的单向复制
6.1.1.2 复制的功用
负载均衡读操作
备份
高可用和故障切换
数据分布
MySQL升级
6.1.1.3 复制架构
一主一从复制架构
一主多从复制架构
6.1.1.4 主从复制原理
主从复制相关线程
主节点:
**dump Thread:**为每个Slave的I/O Thread启动一个dump线程,用于向其发送binary log events
从节点:
**I/O Thread:**向Master请求二进制日志事件,并保存于中继日志中
**SQL Thread:**从中继日志中读取日志事件,在本地完成重放
跟复制功能相关的文件:
master.info:用于保存slave连接至master时的相关信息,例如账号、密码、服务器地址等
relay-log.info:保存在当前slave节点上已经复制的当前二进制日志和本地relay log日志的对应关
系
mysql-relay-bin.00000#: 中继日志,保存从主节点复制过来的二进制日志,本质就是二进制日志
说明:
MySQL8.0 取消 master.info 和 relay-log.info文件
范例: 中继日志
[root@slave ~]#file /var/lib/mysql/mariadb-relay-bin.000001
/var/lib/mysql/mariadb-relay-bin.000001: MySQL replication log, server id 18
MySQL V5+, server version 10.3.17-MariaDB-log
[root@slave ~]#mysqlbinlog /var/lib/mysql/mariadb-relay-bin.000001|head
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#200615 17:58:48 server id 18 end_log_pos 256 CRC32 0x7bd00c79
binlog v 4, server v 10.3.17-MariaDB-log created 200615 17:58:48
BINLOG '
Start:
WEbnXg8cAAAA/AAAAAABAAAAAAQAMTAuMy4xNy1NYXJpYURCLWxvZwAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAA5AAEGggAAAAICAgCAAAACgoKAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
6.1.1.5 主从复制特点
异步复制: 客户端性能良好
主从数据不一致比较常见
6.1.1.6 各种复制架构
一Master/一Slave
一主多从
从服务器还可以再有从服务器
Master/Master
一从多主:适用于多个不同数据库
环状复制
复制需要考虑二进制日志事件记录格式
STATEMENT(5.0之前), Mariadb5.5 默认使用此格式
ROW(5.1之后,推荐),MySQL 8.0 默认使用此格式
MIXED: Mariadb10.3 默认使用此格式
6.1.2 实现主从复制配置
官网参考
https://dev.mysql.com/doc/refman/8.0/en/replication-configuration.html
https://dev.mysql.com/doc/refman/5.7/en/replication-configuration.html
https://dev.mysql.com/doc/refman/5.5/en/replication-configuration.html
https://mariadb.com/kb/en/library/setting-up-replication/
主节点配置:
(1) 启用二进制日志
[mysqld]
log_bin
(2) 为当前节点设置一个全局惟一的ID号
[mysqld]
server-id=#
log-basename=master #可选项,设置datadir中日志名称,确保不依赖主机名
说明:
server-id的取值范围
1 to 4294967295 (>= MariaDB 10.2.2),默认值为1,MySQL8.0默认值为1
0 to 4294967295 (<= MariaDB 10.2.1),默认值为0,如果从节点为0,所有master都将拒绝此
slave的连接
(3) 查看从二进制日志的文件和位置开始进行复制
SHOW MASTER STATUS;
(4) 创建有复制权限的用户账号
GRANT REPLICATION SLAVE ON *.* TO 'repluser'@'HOST' IDENTIFIED BY 'replpass';
#MySQL8.0 分成两步实现
mysql> create user repluser@'10.0.0.%' identified by '123456';
mysql> grant replication slave on *.* to repluser@'10.0.0.%';
从节点配置:
(1) 启动中继日志
[mysqld]
server_id=#
#为当前节点设置一个全局惟的ID号
log-bin
read_only=ON
relay_log=relay-log
#设置数据库只读,针对supper user无效
#relay log的文件路径,默认值hostname-relay-bin
relay_log_index=relay-log.index #默认值hostname-relay-bin.index
(2) 使用有复制权限的用户账号连接至主服务器,并启动复制线程
官方说明
https://dev.mysql.com/doc/refman/8.0/en/change-master-to.html
范例:
CHANGE MASTER TO MASTER_HOST='masterhost',
MASTER_USER='repluser',
MASTER_PASSWORD='replpass',
MASTER_LOG_FILE='mariadb-bin.xxxxxx',
MASTER_LOG_POS=#
MASTER_DELAY = interval; #可指定延迟复制实现访问误操作,单位秒
START SLAVE [IO_THREAD|SQL_THREAD];
SHOW SLAVE STATUS;
#查看 relaylog 事件
SHOW RELAYLOG EVENTS in 'relay-bin.00000x';
范例:新建主从复制
#主节点
[root@master ~]#dnf -y install mariadb-server
[root@master ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id=8
log-bin
[root@master ~]#systemctl restart mariadb
[root@master ~]#mysql
#查看二进制文件和位置
MariaDB [(none)]> show master logs;
+--------------------+-----------+
| Log_name
| File_size |
+--------------------+-----------+
| mariadb-bin.000001 |
| mariadb-bin.000002 |
28052 |
545 |
+--------------------+-----------+
2 rows in set (0.001 sec)
#创建复制用户
MariaDB [(none)]> grant replication slave on *.* to repluser@'10.0.0.%'
identified by 'magedu';
#如果是MySQL 8.0 需要分成下面两步实现
mysql>create user 'repluser'@'10.0.0.%';
mysql>grant replication slave on *.* to 'repluser'@'10.0.0.%';
#从节点
[root@slave ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id=18
[root@slave ~]#systemctl restart mariadb
[root@slave1 ~]#mysql
MariaDB [(none)]> help change master to
MariaDB [(none)]> CHANGE MASTER TO MASTER_HOST='10.0.0.8',
MASTER_USER='repluser', MASTER_PASSWORD='magedu', MASTER_PORT=3306,
MASTER_LOG_FILE='mariadb-bin.000002', MASTER_LOG_POS=545;
MariaDB [(none)]> start slave;
Query OK, 0 rows affected, 1 warning (0.000 sec)
MariaDB [(none)]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 10.0.0.8
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mariadb-bin.000002
Read_Master_Log_Pos: 26987890
Relay_Log_File: mariadb-relay-bin.000002
Relay_Log_Pos: 26987902
Relay_Master_Log_File: mariadb-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 26987890
Relay_Log_Space: 26988213
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
#复制的延迟时间
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 8
Master_SSL_Crl:
Master_SSL_Crlpath:
Using_Gtid: No
Gtid_IO_Pos:
Replicate_Do_Domain_Ids:
Replicate_Ignore_Domain_Ids:
Parallel_Mode: conservative
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for the
slave I/O thread to update it
Slave_DDL_Groups: 34
Slave_Non_Transactional_Groups: 0
Slave_Transactional_Groups: 100006
1 row in set (0.000 sec)
范例:主服务器非新建时,主服务器运行一段时间后,新增从节点服务器
如果主节点已经运行了一段时间,且有大量数据时,如何配置并启动slave节点
通过备份恢复数据至从服务器
复制起始位置为备份时,二进制日志文件及其POS
#在主服务器完全备份
[root@master ~]#mysqldump -A -F --single-transaction --master-data=1 >
/backup/fullbackup_`date +%F_%T`.sql
[root@master ~]#ll /backup/
total 2988
-rw-r--r-- 1 root root 3055918 Nov 27 17:41 fullbackup_2019-11-27_17:41:17.sql
[root@master ~]#scp /backup/fullbackup_2019-11-27_17\41\17.sql
192.168.8.11:/data/
#建议优化主和从节点服务器的性能
MariaDB [hellodb]> set global innodb_flush_log_at_trx_commit=2
MariaDB [hellodb]> set global sync_binlog=0
MariaDB [hellodb]> set global innodb_flush_log_at_trx_commit=2;
Query OK, 0 rows affected (0.001 sec)
MariaDB [hellodb]> show variables like 'sync_binlog';
+---------------------+-------+
| Variable_name
+---------------------+-------+
| sync_binlog | 0
| Value |
|
|---------------------+-------+
5 rows in set (0.001 sec)
#将完全备份还原到新的从节点
[root@slave ~]#dnf -y install mariadb-server
[root@slave ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id=11
read-only
[root@slave ~]#systemctl restart mariadb
#配置从节点,从完全备份的位置之后开始复制
[root@slave ~]#grep '^CHANGE MASTER' /data/fullbackup_2019-11-27_17\41\17.sql
CHANGE MASTER TO MASTER_LOG_FILE='mariadb-bin.000003', MASTER_LOG_POS=389;
[root@slave ~]#vim /data/fullbackup_2019-11-27_17\41\17.sql
CHANGE MASTER TO
MASTER_HOST='10.0.0.8',
MASTER_USER='repluser',
MASTER_PASSWORD='magedu',
MASTER_PORT=3306,
MASTER_LOG_FILE='mariadb-bin.000003', MASTER_LOG_POS=389;
[root@slave ~]#mysql < /data/fullbackup_2019-11-27_17\41\17.sql
[root@slave ~]#mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 9
Server version: 10.3.11-MariaDB MariaDB Server
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State:
Master_Host: 10.0.0.8
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mariadb-bin.000003
Read_Master_Log_Pos: 389
Relay_Log_File: mariadb-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File: mariadb-bin.000003
Slave_IO_Running: No
Slave_SQL_Running: No
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 389
Relay_Log_Space: 256
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 0
Master_SSL_Crl:
Master_SSL_Crlpath:
Using_Gtid: No
Gtid_IO_Pos:
Replicate_Do_Domain_Ids:
Replicate_Ignore_Domain_Ids:
Parallel_Mode: conservative
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State:
Slave_DDL_Groups: 0
Slave_Non_Transactional_Groups: 0
Slave_Transactional_Groups: 0
1 row in set (0.000 sec)
MariaDB [(none)]> start slave;
6.1.3 主从复制相关
6.1.3.1 限制从服务器为只读
read_only=ON
#注意:此限制对拥有SUPER权限的用户均无效
注意:以下命令会阻止所有用户, 包括主服务器复制的更新
FLUSH TABLES WITH READ LOCK;
6.1.3.2 在从节点清除信息
注意:以下都需要先 STOP SLAVE
RESET SLAVE #从服务器清除master.info ,relay-log.info, relay log ,开始新的relay log
RESET SLAVE ALL #清除所有从服务器上设置的主服务器同步信息,如HOST,PORT, USER和 PASSWORD
等
6.3.1.3 复制错误解决方法
可以在从服务器忽略几个主服务器的复制事件,此为global变量,或指定跳过事件的ID
注意: Centos 8.1以上版本上的MariaDB10.3主从节点同时建同名的库和表不会冲突,建主键记录会产生
冲突
#系统变量,指定跳过复制事件的个数
SET GLOBAL sql_slave_skip_counter = N
#服务器选项,只读系统变量,指定跳过事件的ID
[mysqld]
slave_skip_errors=1007|ALL
范例:复制冲突的解决
#CentOS7上Mariadb5.5 在slave创建库和表,再在master上创建同名的库和表,会出现复制冲突,而在
CentOS8上的Mariadb10.3上不会冲突
#如果添加相同的主键记录都会冲突
MariaDB [(none)]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.39.8
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mariadb-bin.000002
Read_Master_Log_Pos: 26988271
Relay_Log_File: mariadb-relay-bin.000003
Relay_Log_Pos: 557
Relay_Master_Log_File: mariadb-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: No
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 1007
Last_Error: Error 'Can't create database 'db4'; database
exists' on query. Default database: 'db4'. Query: 'create database db4'
Skip_Counter: 0
Exec_Master_Log_Pos: 26988144
Relay_Log_Space: 26988895
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 1007
#错误编码
Last_SQL_Error: Error 'Can't create database 'db4'; database
exists' on query. Default database: 'db4'. Query: 'create database db4'
Replicate_Ignore_Server_Ids:
Master_Server_Id: 8
Master_SSL_Crl:
Master_SSL_Crlpath:
Using_Gtid: No
Gtid_IO_Pos:
Replicate_Do_Domain_Ids:
Replicate_Ignore_Domain_Ids:
Parallel_Mode: conservative
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State:
Slave_DDL_Groups: 37
Slave_Non_Transactional_Groups: 0
Slave_Transactional_Groups: 100006
1 row in set (0.000 sec)
#方法1
MariaDB [(none)]> stop slave;
MariaDB [(none)]> set global sql_slave_skip_counter=1;
MariaDB [(none)]> start slave;
#方法2
[root@slave1 ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
slave_skip_errors=1007|ALL
[root@slave1 ~]#systemctl restart mariadb
6.3.1.4 START SLAVE 语句,指定执到特定的点
START SLAVE [thread_types]
START SLAVE [SQL_THREAD] UNTIL
log_pos
MASTER_LOG_FILE = 'log_name', MASTER_LOG_POS =
RELAY_LOG_FILE = 'log_name', RELAY_LOG_POS =
START SLAVE [SQL_THREAD] UNTIL
log_pos
thread_types:
[thread_type [, thread_type] ... ]
thread_type: IO_THREAD | SQL_THREAD
6.3.1.5 保证主从复制的事务安全
参看https://mariadb.com/kb/en/library/server-system-variables/
在master节点启用参数:
sync_binlog=1
#每次写后立即同步二进制日志到磁盘,性能差
#如果用到的为InnoDB存储引擎:
innodb_flush_log_at_trx_commit=1
sync_master_info=#
#每次事务提交立即同步日志写磁盘
#次事件后master.info同步到磁盘
在slave节点启用服务器选项:
skip-slave-start=ON
#不自动启动slave
在slave节点启用参数:
sync_relay_log=#
#次写后同步relay log到磁盘
#次事务后同步relay-log.info到磁盘
sync_relay_log_info=#
6.3.1.6 实战案例:将已有的MySQL8.0单机架构变成主从复制架构
主节点
#修改master主节点的配置
[root@centos8 ~]#vim /etc/my.cnf
[mysqld]
server-id=8
log-bin=/data/mysql/logbin/mysql-bin
[root@centos8 ~]#systemctl restart mysqld
#完全备份
[root@centos8 ~]#mysqldump -A -F --master-data=1 --single-transaction >
/data/all.sql
#创建复制用户并授权
mysql>create user repluser@"10.0.0.%" identified by "123456"
mysql>grant replication slave on *.* to repluser@"10.0.0.%"";
#将备份复制到从节点
[root@centos8 ~]#scp /data/all.sql 从节点:/data
#配置从节点
[root@centos8 ~]#vim /etc/my.cnf
[mysqld]
server-id=18
read-only
[root@centos8 ~]#systemctl restart mysqld
#从节点修改备份文件
[root@centos8 ~]#vim /data/all.sql
CHANGE MASTER TO
MASTER_HOST='主节点',
MASTER_USER='repluser',
MASTER_PASSWORD='123456',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=156;
#从节点还原备份
mysql> set sql_log_bin=0;
mysql> source /data/all.sql;
mysql>set sql_log_bin=1;
#从节点开始复制
mysql> start slave;
6.3.1.7 实战案例:当master服务器宕机,提升一个slave成为新的master
#找到哪个从节点的数据库是最新,让它成为新master
[root@centos8 ~]#cat /var/lib/mysql/relay-log.info
5
./mariadb-relay-bin.000002
1180
mysql-bin.000002
996
0
#新master修改配置文件,关闭read-only配置
[root@slave1 ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id=18
read-only=OFF
log-bin=/data/mysql/logbin/mysql-bin
#清除旧的master复制信息
MariaDB [hellodb]>set global read_only=off;
MariaDB [hellodb]>stop slave;
MariaDB [hellodb]>reset slave all;
#在新master上完全备份
[root@slave1 ~]#mysqldump -A --single-transaction --master-data=1 -F >
backup.sql
[root@slave1 ~]#scp backup.sql 10.0.0.28:
#分析旧的master 的二进制日志,将未同步到至新master的二进制日志导出来,恢复到新master,尽可能恢
复数据
#其它所有 slave 重新还原数据库,指向新的master
[root@slave2 ~]#vim backup.sql
CHANGE MASTER TO
MASTER_HOST='10.0.0.18',
MASTER_USER='repluser',
MASTER_PASSWORD='centos',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=371;
MariaDB [hellodb]>stop slave;
MariaDB [hellodb]>reset slave all;
MariaDB [hellodb]>set sql_log_bin=off;
MariaDB [hellodb]>source backup.sql;
MariaDB [hellodb]>set sql_log_bin=on;
MariaDB [hellodb]>start slave;
6.1.4 实现级联复制
需要在中间的从服务器启用以下配置 ,实现中间slave节点能将master的二进制日志在本机进行数据库
更新,并且也同时更新本机的二进制,从而实现级联复制
[mysqld]
server-id=18
log_bin
log_slave_updates
版本默认不开启
read-only
#级联复制中间节点的必选项,MySQL8.0此为默认值,可以不要人为添加,其它
案例:三台主机实现级联复制
#在10.0.0.8充当master
#在10.0.0.18充当级联slave
#在10.0.0.28充当slave
#在master实现
[root@centos8 ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id=8
log-bin
[root@centos8 ~]#systemctl restart mariadb
[root@centos8 ~]#mysql
MariaDB [(none)]> grant replication slave on *.* to repluser@'10.0.0.%'
identified by 'magedu';
[root@centos8 ~]#mysqldump -A -F --single-transaction --master-data=1
/data/all.sql
>
[root@centos8 ~]#scp /data/all.sql 10.0.0.18:/data
[root@centos8 ~]#scp /data/all.sql 10.0.0.28:/data
#在中间级联slave实现
[root@centos8 ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id=18
log-bin
read-only
log_slave_updates #级联复制中间节点的必选项,MySQL8.0此为默认值,可以不要人为添加
[root@centos8 ~]#systemctl restart mariadb
#还原数据库
[root@centos8 ~]#vim /data/all.sql
CHANGE MASTER TO
MASTER_HOST='master节点的iP',
MASTER_USER='repluser',
MASTER_PASSWORD='centos',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000004',
MASTER_LOG_POS=523;
[root@centos8 ~]#mysql
MariaDB [(none)]> set sql_log_bin=0;
MariaDB [(none)]> source /data/all.sql
MariaDB [(none)]> show master logs; #记录二进制位置,给第三个节点使用
MariaDB [(none)]> set sql_log_bin=0;
MariaDB [(none)]> start slave;
#在第三个节点slave上实现
[root@centos8 ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id=28
read-only
[root@centos8 ~]#systemctl restart mariadb
[root@centos8 ~]#vim /data/all.sql
CHANGE MASTER TO
MASTER_HOST='中间节点的IP',
MASTER_USER='repluser',
MASTER_PASSWORD='magedu',
MASTER_PORT=3306,
MASTER_LOG_FILE='mariadb-bin.000002', MASTER_LOG_POS=344;
[root@centos8 ~]#mysql < /data/all.sql
[root@centos8 ~]#mysql -e 'start slave;'
6.1.5 主主复制
主主复制:两个节点,都可以更新数据,并且互为主从
容易产生的问题:数据不一致;因此慎用
考虑要点:自动增长id
配置一个节点使用奇数id
auto_increment_offset=1
#开始点
auto_increment_increment=2
#增长幅度
另一个节点使用偶数id
auto_increment_offset=2
auto_increment_increment=2
主主复制的配置步骤:
(1) 各节点使用一个惟一server_id
(2) 都启动binary log和relay log
(3) 创建拥有复制权限的用户账号
(4) 定义自动增长id字段的数值范围各为奇偶
(5) 均把对方指定为主节点,并启动复制线程
范例:实现两个节点的主主复制模型
#在第一个master节点上实现
[root@master1 ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id=8
log-bin
auto_increment_offset=1
#开始点
auto_increment_increment=2
#增长幅度
[root@master1 ~]#systemctl start mariadb
[root@master1 ~]#mysql
MariaDB [(none)]>show master logs;
+--------------------+-----------+
| Log_name
| File_size |
+--------------------+-----------+
| mariadb-bin.000001 |
| mariadb-bin.000002 |
28303 |
386 |
+--------------------+-----------+
2 rows in set (0.000 sec)
MariaDB [(none)]> grant replication slave on *.* to repluser@'192.168.100.%'
identified by 'magedu';
#在第二个master节点上实现
[rootmaster2 ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id=18
log-bin
auto_increment_offset=2
#开始点
auto_increment_increment=2
#增长幅度
[root@master2 ~]#systemctl start mariadb
[root@master2 ~]#mysql
MariaDB [(none)]> CHANGE MASTER TO
->
->
->
->
->
->
MASTER_HOST='192.168.100.8',
MASTER_USER='repluser',
MASTER_PASSWORD='magedu',
MASTER_PORT=3306,
MASTER_LOG_FILE='mariadb-bin.000002',
MASTER_LOG_POS=386;
Query OK, 0 rows affected (0.019 sec)
MariaDB [(none)]> start slave;
Query OK, 0 rows affected (0.003 sec)
MariaDB [(none)]> show master logs; #查看二进制位置
+--------------------+-----------+
| Log_name
| File_size |
+--------------------+-----------+
| mariadb-bin.000001 |
| mariadb-bin.000002 |
28303 |
344 |
+--------------------+-----------+
2 rows in set (0.001 sec)
#在第一个master节点上实现
MariaDB [(none)]> CHANGE MASTER TO
->
->
->
->
->
->
MASTER_HOST='192.168.100.18',
MASTER_USER='repluser',
MASTER_PASSWORD='magedu',
MASTER_PORT=3306,
MASTER_LOG_FILE='mariadb-bin.000002',
MASTER_LOG_POS=344;
Query OK, 0 rows affected (0.007 sec)
MariaDB [(none)]> start slave;
Query OK, 0 rows affected (0.002 sec)
MariaDB [db1]> create table t1(id int auto_increment primary key,name char(10));
#两个节点分别插入数据
#在第一个节点上执行
MariaDB [db1]> create database db1;
MariaDB [db1]> insert t1 (name) values('user1');
#在第二个节点上执行
MariaDB [db1]> insert t1 (name) values('user2');
#两个节点同时插入数据
MariaDB [db1]> insert t1 (name) values('userX');
MariaDB [db1]> select * from t1;
+----+-------+
| id | name
|
+----+-------+
|
|
|
|
1 | user1 |
2 | user2 |
3 | userX |
4 | userX |
+----+-------+
4 rows in set (0.001 sec)
#两个节点同时创建数据库,发生复制冲突
MariaDB [db1]> create database db2;
MariaDB [db1]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.100.18
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mariadb-bin.000002
Read_Master_Log_Pos: 1029
Relay_Log_File: mariadb-relay-bin.000002
Relay_Log_Pos: 1110
Relay_Master_Log_File: mariadb-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: No
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 1007
Last_Error: Error 'Can't create database 'db2'; database
exists' on query. Default database: 'db2'. Query: 'create database db2'
Skip_Counter: 0
Exec_Master_Log_Pos: 897
Relay_Log_Space: 1553
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 1007
Last_SQL_Error: Error 'Can't create database 'db2'; database
exists' on query. Default database: 'db2'. Query: 'create database db2'
Replicate_Ignore_Server_Ids:
Master_Server_Id: 18
Master_SSL_Crl:
Master_SSL_Crlpath:
Using_Gtid: No
Gtid_IO_Pos:
Replicate_Do_Domain_Ids:
Replicate_Ignore_Domain_Ids:
Parallel_Mode: conservative
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State:
Slave_DDL_Groups: 2
Slave_Non_Transactional_Groups: 0
Slave_Transactional_Groups: 2
1 row in set (0.003 sec)
6.1.6 半同步复制
默认情况下,MySQL的复制功能是异步的,异步复制可以提供最佳的性能,主库把binlog日志发送给从
库即结束,并不验证从库是否接收完毕。这意味着当主服务器或从服务器端发生故障时,有可能从服务
器没有接收到主服务器发送过来的binlog日志,这就会造成主服务器和从服务器的数据不一致,甚至在
恢复时造成数据的丢失
MySQL5.5版本为了保证主从数据的一致性问题。加入了半同步复制的组件(插件),可以控制从库IO线程是
否将relaylog落盘,一旦落盘通过插件返回ACK给主库ACK_REC。接受到ACK之后,主库的事务才能提交
成功。在默认情况下,如果超过10秒没有返回ACK,此次复制行为会切换为异步复制
在MySQL5.6,5.7 当中也加入了一些比较好的特性,也不能完全保证的数据一致。如果生产业务比较关注
主从最终一致(比如:金融等)。推荐可以使用MGR的架构,或者PXC等一致性架构
半同步复制默认设置
rpl_semi_sync_master_wait_point=after_commit
缺点
缺点1: 幻读
当用户提交一个事务,该事务已经写入redo日志和binlog日志,但该事务还没写入从库,此时处在waiting
slave dump处,此时另一个用户可以读取到这条数据,而他自己却不能;
缺点2:数据丢失
一个提交的事务在waiting slave dump处crash后,主库将比从库多一条数据
增强半同步复制(MySQL5.7新增功能)
rpl_semi_rsync_master_wait_point=after_sync
优点
改善1:解决幻读
当用户发起一个事务,该事务先写入二进制后,再向从库进行同步,由于还没有完成提交,此时其他用户无法
读取到该数据,解决了幻读
改善2:解决数据丢失
一个事务在waiting slave dump处crash掉后,可以通过观察从库上是否存在主库的last gtid值,如果
存在,这条数据正常恢复,如果不存在则删除主库的那条多余的GTID值,然后恢复,保证了数据的完整性
半同步复制实现:
官方文档:
https://dev.mysql.com/doc/refman/8.0/en/replication-semisync.html
https://dev.mysql.com/doc/refman/5.7/en/replication-semisync.html
https://mariadb.com/kb/en/library/semisynchronous-replication/
范例: CentOS8 在MySQL8.0 实现半同步复制
#查看插件文件
[root@centos8 ~]#rpm -ql mysql-server |grep semisync
/usr/lib64/mysql/plugin/semisync_master.so
/usr/lib64/mysql/plugin/semisync_slave.so
#master服务器配置
[root@master ~]#vim /etc/my.cnf.d/mysql-server.cnf
[mysqld]
server-id=8
log-bin
rpl_semi_sync_master_enabled=ON
启,否则无法启动
#修改此行,需要先安装semisync_master.so插件后,再重
#设置3s内无法同步,也将返回成功信息给客户端
rpl_semi_sync_master_timeout=3000
#slave服务器配置
[root@slave1 ~]#vim /etc/my.cnf.d/mysql-server.cnf
[mysqld]
server-id=18
rpl_semi_sync_slave_enabled=ON #修改此行,需要先安装semisync_slave.so插件后,再重启,否则
无法启动
[root@slave2 ~]#vim /etc/my.cnf.d/mysql-server.cnf
[mysqld]
server-id=28
rpl_semi_sync_slave_enabled=ON #修改此行,需要先安装semisync_slave.so插件后,再重启,否则
无法启动
#主服务器配置:
mysql>INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so'; #永久安装插
件
mysql>UNINSTALL PLUGIN rpl_semi_sync_master ;
mysql>SHOW PLUGINS; #查看插件
mysql>SET GLOBAL rpl_semi_sync_master_enabled=1; #临时修改变量
mysql>SET GLOBAL rpl_semi_sync_master_timeout = 3000; #超时长1s,默认值为10s
mysql>SHOW GLOBAL VARIABLES LIKE '%semi%';
+-------------------------------------------+------------+
| Variable_name
| Value
|
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled
| rpl_semi_sync_master_timeout
| rpl_semi_sync_master_trace_level
| ON
|
| 10000
| 32
|
|
| rpl_semi_sync_master_wait_for_slave_count | 1
|
|
| rpl_semi_sync_master_wait_no_slave
| rpl_semi_sync_master_wait_point
| ON
| AFTER_SYNC |
+-------------------------------------------+------------+
6 rows in set (0.00 sec)
mysql> SHOW GLOBAL STATUS LIKE '%semi%';
+--------------------------------------------+-------+
| Variable_name
| Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients
| 2
| 0
| 0
| 0
| 1
| 2
| ON
| 0
| 0
| 0
| 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| Rpl_semi_sync_master_net_avg_wait_time
| Rpl_semi_sync_master_net_wait_time
| Rpl_semi_sync_master_net_waits
| Rpl_semi_sync_master_no_times
| Rpl_semi_sync_master_no_tx
| Rpl_semi_sync_master_status
| Rpl_semi_sync_master_timefunc_failures
| Rpl_semi_sync_master_tx_avg_wait_time
| Rpl_semi_sync_master_tx_wait_time
| Rpl_semi_sync_master_tx_waits
| Rpl_semi_sync_master_wait_pos_backtraverse | 0
| Rpl_semi_sync_master_wait_sessions
| Rpl_semi_sync_master_yes_tx
| 0
| 0
+--------------------------------------------+-------+
14 rows in set (0.00 sec)
#从服务器配置:
mysql>INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
mysql>SET GLOBAL rpl_semi_sync_slave_enabled=1; #临时修改变量
mysql> SHOW GLOBAL VARIABLES LIKE '%semi%';
+---------------------------------+-------+
| Variable_name
| Value |
+---------------------------------+-------+
| rpl_semi_sync_slave_enabled
| ON
|
|
| rpl_semi_sync_slave_trace_level | 32
+---------------------------------+-------+
2 rows in set (0.00 sec)
#注意:如果已经实现主从复制,需要stop slave;start slave;
mysql> stop slave;
mysql> start slave;
mysql> SHOW GLOBAL STATUS LIKE '%semi%';
+----------------------------+-------+
| Variable_name
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON
| Value |
|
+----------------------------+-------+
1 row in set (0.00 sec)
范例:CentOS 8 在Mariadb-10.3.11上实现 实现半同步复制
#在master实现,启用半同步功能
[root@master ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id=8
log-bin
plugin-load-add = semisync_master
rpl_semi_sync_master_enabled=ON
rpl_semi_sync_master_timeout=3000 #设置3s内无法同步,也将返回成功信息给客户端
[root@centos8 ~]#systemctl restart mariadb
MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE '%semi%';
+---------------------------------------+--------------+
| Variable_name
| Value
|
+---------------------------------------+--------------+
| rpl_semi_sync_master_enabled
| rpl_semi_sync_master_timeout
| rpl_semi_sync_master_trace_level
| rpl_semi_sync_master_wait_no_slave
| rpl_semi_sync_master_wait_point
| rpl_semi_sync_slave_delay_master
| rpl_semi_sync_slave_enabled
| ON
|
|
|
|
| 3000
| 32
| ON
| AFTER_COMMIT |
| OFF
| OFF
|
|
|
|
| rpl_semi_sync_slave_kill_conn_timeout | 5
| rpl_semi_sync_slave_trace_level | 32
+---------------------------------------+--------------+
9 rows in set (0.002 sec)
MariaDB [(none)]> SHOW GLOBAL STATUS LIKE '%semi%';
+--------------------------------------------+-------+
| Variable_name
| Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients
| 0
| 0
| 0
| 0
| 0
| 0
| 0
| 0
| ON
| 0
| 0
|
|
|
|
|
|
|
|
|
|
|
| Rpl_semi_sync_master_get_ack
| Rpl_semi_sync_master_net_avg_wait_time
| Rpl_semi_sync_master_net_wait_time
| Rpl_semi_sync_master_net_waits
| Rpl_semi_sync_master_no_times
| Rpl_semi_sync_master_no_tx
| Rpl_semi_sync_master_request_ack
| Rpl_semi_sync_master_status
| Rpl_semi_sync_master_timefunc_failures
| Rpl_semi_sync_master_tx_avg_wait_time
| Rpl_semi_sync_master_tx_wait_time
| Rpl_semi_sync_master_tx_waits
| 0
| 0
|
|
|
|
|
|
|
| Rpl_semi_sync_master_wait_pos_backtraverse | 0
| Rpl_semi_sync_master_wait_sessions
| Rpl_semi_sync_master_yes_tx
| Rpl_semi_sync_slave_send_ack
| Rpl_semi_sync_slave_status
| 0
| 0
| 0
| OFF
+--------------------------------------------+-------+
18 rows in set (0.001 sec)
#在其它所有slave节点上都实现,启用半同步功能
[root@slave ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id=18
plugin_load_add = semisync_slave
rpl_semi_sync_slave_enabled=ON
[root@slave ~]#systemctl restart mariadb
[root@slave ~]#mysql
MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE '%semi%';
+---------------------------------------+--------------+
| Variable_name
| Value
|
+---------------------------------------+--------------+
| rpl_semi_sync_master_enabled
| rpl_semi_sync_master_timeout
| rpl_semi_sync_master_trace_level
| rpl_semi_sync_master_wait_no_slave
| rpl_semi_sync_master_wait_point
| rpl_semi_sync_slave_delay_master
| rpl_semi_sync_slave_enabled
| OFF
| 10000
| 32
|
|
|
|
| ON
| AFTER_COMMIT |
| OFF
| ON
|
|
|
|
| rpl_semi_sync_slave_kill_conn_timeout | 5
| rpl_semi_sync_slave_trace_level | 32
+---------------------------------------+--------------+
9 rows in set (0.001 sec)
MariaDB [(none)]> SHOW GLOBAL STATUS LIKE '%semi%';
+--------------------------------------------+-------+
| Variable_name
| Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients
| 0
| 0
| 0
| 0
| 0
| 0
| 0
| 0
| OFF
| 0
| 0
| 0
| 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| Rpl_semi_sync_master_get_ack
| Rpl_semi_sync_master_net_avg_wait_time
| Rpl_semi_sync_master_net_wait_time
| Rpl_semi_sync_master_net_waits
| Rpl_semi_sync_master_no_times
| Rpl_semi_sync_master_no_tx
| Rpl_semi_sync_master_request_ack
| Rpl_semi_sync_master_status
| Rpl_semi_sync_master_timefunc_failures
| Rpl_semi_sync_master_tx_avg_wait_time
| Rpl_semi_sync_master_tx_wait_time
| Rpl_semi_sync_master_tx_waits
| Rpl_semi_sync_master_wait_pos_backtraverse | 0
| Rpl_semi_sync_master_wait_sessions
| Rpl_semi_sync_master_yes_tx
| Rpl_semi_sync_slave_send_ack
| Rpl_semi_sync_slave_status
| 0
| 0
| 0
| ON
+--------------------------------------------+-------+
18 rows in set (0.001 sec)
MariaDB [(none)]>
#在master上实现
MariaDB [db1]> SHOW GLOBAL STATUS LIKE '%semi%';
+--------------------------------------------+-------+
| Variable_name
| Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients
| 2
| 4
| 0
| 0
| 4
| 1
| 1
| 3
| ON
| 0
| #两个从节点
| Rpl_semi_sync_master_get_ack
|
|
|
|
|
|
|
|
|
| Rpl_semi_sync_master_net_avg_wait_time
| Rpl_semi_sync_master_net_wait_time
| Rpl_semi_sync_master_net_waits
| Rpl_semi_sync_master_no_times
| Rpl_semi_sync_master_no_tx
| Rpl_semi_sync_master_request_ack
| Rpl_semi_sync_master_status
| Rpl_semi_sync_master_timefunc_failures
| Rpl_semi_sync_master_tx_avg_wait_time
| Rpl_semi_sync_master_tx_wait_time
| Rpl_semi_sync_master_tx_waits
| 1177 |
| 2355 |
| 2
|
|
|
|
|
| Rpl_semi_sync_master_wait_pos_backtraverse | 0
| Rpl_semi_sync_master_wait_sessions
| Rpl_semi_sync_master_yes_tx
| Rpl_semi_sync_slave_send_ack
| Rpl_semi_sync_slave_status
| 0
| 2
| 0
| OFF |
+--------------------------------------------+-------+
18 rows in set (0.001 sec)
#测试
#在master实现,创建数据库,立即成功
MariaDB [db1]> create database db2;
Query OK, 1 row affected (0.004 sec)
#在所有slave节点实现,停止复制线程
MariaDB [(none)]> stop slave;
Query OK, 0 rows affected (0.011 sec)
#在master实现,创建数据库,等待3s才能成功
MariaDB [db1]> create database db3;
Query OK, 1 row affected (3.003 sec)
#在任意一个slave节点实现,恢复复制线程
MariaDB [(none)]> start slave;
Query OK, 0 rows affected (0.006 sec)
#在master实现,创建数据库,立即成功
MariaDB [db1]> create database db4;
Query OK, 1 row affected (0.002 sec)
#在所有从节点停止同步线程,在主节点可以看到以下日志信息
MariaDB [db1]> stop slave;
[root@centos8 ~]#tail /var/log/mariadb/mariadb.log
2020-08-29 10:11:19 15 [Warning] IP address '10.0.0.28' could not be resolved:
Name or service not known
2020-08-29 10:11:19 15 [Note] Start binlog_dump to slave_server(28),
pos(mariadb-bin.000001, 330)
2020-08-29 10:11:19 15 [Note] Start semi-sync binlog_dump to slave (server_id:
28), pos(mariadb-bin.000001, 330)
2020-08-29 10:12:34 15 [Note] Stop semi-sync binlog_dump to slave (server_id:
28)
2020-08-29 10:16:05 17 [Note] Start binlog_dump to slave_server(28),
pos(mariadb-bin.000002, 27378670)
2020-08-29 10:16:05 17 [Note] Start semi-sync binlog_dump to slave (server_id:
28), pos(mariadb-bin.000002, 27378670)
2020-08-29 10:16:31 12 [Note] Stop semi-sync binlog_dump to slave (server_id:
18)
2020-08-29 10:16:37 17 [Note] Stop semi-sync binlog_dump to slave (server_id:
28)
2020-08-29 10:17:19 14 [Warning] Timeout waiting for reply of binlog (file:
mariadb-bin.000002, pos: 27378922), semi-sync up to file mariadb-bin.000002,
position 27378795.
2020-08-29 10:17:19 14 [Note] Semi-sync replication switched OFF.
范例:CentOS 7 实现Mariadb 5.5.65 的半同步复制
#主服务器配置:
MariaDB [(none)]>INSTALL PLUGIN rpl_semi_sync_master SONAME
'semisync_master.so';
MariaDB [(none)]>UNINSTALL PLUGIN rpl_semi_sync_master ;
MariaDB [(none)]>SHOW PLUGINS; #查看插件
MariaDB [(none)]>SET GLOBAL rpl_semi_sync_master_enabled=1;
MariaDB [(none)]>SET GLOBAL rpl_semi_sync_master_timeout = 1000; #超时长1s,默认值
为10s
MariaDB [(none)]>SHOW GLOBAL VARIABLES LIKE '%semi%';
MariaDB [(none)]>SHOW GLOBAL STATUS LIKE '%semi%';
#从服务器配置:
MariaDB [(none)]>INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
MariaDB [(none)]>SET GLOBAL rpl_semi_sync_slave_enabled=1;
6.1.7 复制过滤器
让从节点仅复制指定的数据库,或指定数据库的指定表
复制过滤器两种实现方式:
(1) 服务器选项:主服务器仅向二进制日志中记录与特定数据库相关的事件
缺点:基于二进制还原将无法实现;不建议使用
优点: 只需要在主节点配置一次即可
注意:此项和 binlog_format相关
参看:https://mariadb.com/kb/en/library/mysqld-options/#-binlog-ignore-db
vim /etc/my.cnf
binlog-do-db=db1
binlog-do-db=db2
binlog-ignore-db=
#数据库白名单列表,不支持同时指定多个值,如果想实现多个数据库需多行实现
#数据库黑名单列表
注意:
This option will not work with cross-database updates with statement-based
logging. See the Statement-Based Logging section for more information.
This option can not be set dynamically.
When setting it on the command-line or in a server option group in an option
file, the option does not accept a comma-separated list. If you would like to
specify multiple filters, then you need to specify the option multiple times.
(2) 从服务器SQL_THREAD在relay log中的事件时,仅读取与特定数据库(特定表)相关的事件并应用于本
地
缺点:会造成网络及磁盘IO浪费,在所有从节点都要配置
优点: 不影响二进制备份还原
从服务器上的复制过滤器相关变量
replicate_do_db="db1,db2,db3"
项不支持多值,只能分别写多行实现
replicate_ignore_db=
#指定复制库的白名单,变量可以指定逗号分隔的多个值,选
#指定复制库黑名单
#指定复制表的白名单
#指定复制表的黑名单
replicate_do_table=
replicate_ignore_table=
replicate_wild_do_table= foo%.bar% #支持通配符
replicate_wild_ignore_table=
When setting it dynamically with SET GLOBAL, the system variable accepts a comma-
separated list of filters.
When setting it on the command-line or in a server option group in an option
file, the system variable does not accept a comma-separated list. If you would
like to specify multiple filters, then you need to specify the system variable
multiple times.
注意:跨库的更新将无法同步
范例:
[mysqld]
replicate_do_db=db1
replicate_do_db=db2
replicate_do_db=db3
范例: 通过二进制日志服务器选项实现过滤器
[mysqld]
server-id=8
log-bin
binlog-do-db=db1
binlog-do-db=db2
binlog-do-db=hellodb
范例: 通过系统变量实现过滤器
MariaDB [(none)]> set global replicate_do_db='db1,hellodb';
ERROR 1198 (HY000): This operation cannot be performed as you have a running
slave ''; run STOP SLAVE '' first
MariaDB [(none)]> stop slave;
Query OK, 0 rows affected (0.009 sec)
MariaDB [(none)]> set global replicate_do_db='db1,hellodb';
Query OK, 0 rows affected (0.000 sec)
MariaDB [(none)]> select @@replicate_do_db;
+-------------------+
| @@replicate_do_db |
+-------------------+
| db1,hellodb
|
+-------------------+
1 row in set (0.000 sec)
MariaDB [(none)]> start slave;
Query OK, 0 rows affected (0.001 sec)
6.1.8 GTID复制
GTID(Global Transaction ID 全局事务标识符) MySQL 5.6 版本开始支持,但不太成熟,建议使用
MySQL5.7以上版本的GTID功能
MySQL5.6版本出现没有默认开启,5.7中即使不开启也有匿名的GTID记录。
开启GTID功能可以支持多DUMP线程的并发复制,而且在MySQL5.6实现了基于库级别多SQL线程并发。
在MySQL5.7利用 GTID的 Logic clock 逻辑时钟。保证了同库级别下的事务顺序问题。即可以实现基于
事务级别的并发回放。从而大大减少了同步的延迟
同时GTID具有幂等性特性,即多次执行结果是一样的
利用 GTID复制不像传统的复制方式(异步复制、半同步复制)需要找到binlog文件名和POS点,只需知
道master的IP、端口、账号、密码即可。开启GTID后,执行change master to
master_auto_postion=1即可,它会自动寻找到相应的位置开始同步
GTID 优点:
保证事务全局统一
截取日志更加方便。跨多文件,判断起点终点更加方便
判断主从工作状态更加方便
传输日志,可以并发传输。SQL回放可以更高并发
主从复制构建更加方便
GTID 架构
GTID = server_uuid:transaction_id,在一组复制中,全局唯一
server_uuid 来源于 /var/lib/mysql/auto.cnf
GTID服务器相关选项
gtid_mode
#gtid模式
enforce_gtid_consistency
#保证GTID安全的参数
GTID配置范例
1. 主服务器
vim /etc/my.cnf
server-id=1
gtid_mode=ON
enforce_gtid_consistency
log-bin=mysql-bin #可选
systemctl restart mysqld
mysql> grant replication slave on *.* to 'repluser'@'10.0.0.%' identified by
'magedu';
2. 从服务器
vim /etc/my.cnf
server-id=2
gtid_mode=ON
enforce_gtid_consistency
systemctl restart mysqld
#如果主服务器和从服务器数据不一致,需要先将主库数据备份还原至从库,再执行下面操作
mysqldump -A --master-data=2 > /backup/full.sql
mysql>CHANGE MASTER TO MASTER_HOST='10.0.0.100',
MASTER_USER='repluser',
MASTER_PASSWORD='magedu',
MASTER_PORT=3306,
MASTER_AUTO_POSITION=1; #使用GTID
mysql>start slave;
#注意观察:Retrieved_Gtid_set和Executed_Gtid_Set这两个值,对比主节点执行show master
status的值,如果相同表示同步完成
6.1.9 复制的监控和维护
6.1.9.1 清理日志
PURGE { BINARY | MASTER } LOGS
RESET MASTER TO # #mysql 不支持
RESET SLAVE [ALL]
{ TO 'log_name' | BEFORE
datetime_expr }
6.1.9.2 复制监控
SHOW MASTER STATUS
SHOW BINARY LOGS
SHOW BINLOG EVENTS
SHOW SLAVE STATUS
SHOW PROCESSLIST
6.1.9.3 从服务器是否落后于主服务
Seconds_Behind_Master:0
6.1.9.4 如何确定主从节点数据是否一致
percona-toolkit
6.1.9.5 数据不一致如何修复
删除从数据库,重新复制
6.1.10 复制的问题和解决方案
6.1.10.1 数据损坏或丢失
Master:MHA + semisync replication
Slave: 重新复制
6.1.10.2 不惟一的 server id
重新复制
6.1.10.3 复制延迟
利用GTID(MySQL5.6需要手动开启,MySQL5.7以上默认开启)支持并发传输binlog及并行多个SQLl
线程
减少大事务,将大事务拆分成小事务
减少锁
sync_binlog=1 加快binlog更新时间,从而加快日志复制
升级到MySQL5.7以上版本(5.7之前的版本,没有开GTID之前,主库可以并发事务,但是dump传
输时是串行)
需要额外的监控工具的辅助
一从多主:Mariadb10 版后支持
多线程复制:对多个数据库复制
6.1.10.4 MySQL 主从数据不一致
6.1.10.4.1 造成主从不一致的原因
主库binlog格式为Statement,同步到从库执行后可能造成主从不一致。
主库执行更改前有执行set sql_log_bin=0,会使主库不记录binlog,从库也无法变更这部分数据。
从节点未设置只读,误操作写入数据
主库或从库意外宕机,宕机可能会造成binlog或者relaylog文件出现损坏,导致主从不一致
主从实例版本不一致,特别是高版本是主,低版本为从的情况下,主数据库上面支持的功能,从数
据库上面可能不支持该功能
主从sql_mode 不一致
MySQL自身bug导致
6.1.10.4.2 主从不一致修复方法
将从库重新实现
虽然这也是一种解决方法,但是这个方案恢复时间比较慢,而且有时候从库也是承担一部分的查询
操作的,不能贸然重建。
使用percona-toolkit工具辅助
PT工具包中包含pt-table-checksum和pt-table-sync两个工具,主要用于检测主从是否一致以及修
复数据不一致情况。这种方案优点是修复速度快,不需要停止主从辅助,缺点是需要知识积累,需
要时间去学习,去测试,特别是在生产环境,还是要小心使用
关于使用方法,可以参考下面链接:https://www.cnblogs.com/feiren/p/7777218.html
手动重建不一致的表
在从库发现某几张表与主库数据不一致,而这几张表数据量也比较大,手工比对数据不现实,并且
重做整个库也比较慢,这个时候可以只重做这几张表来修复主从不一致
这种方案缺点是在执行导入期间需要暂时停止从库复制,不过也是可以接受的
范例:A,B,C这三张表主从数据不一致
1、从库停止Slave复制
mysql>stop slave;
2、在主库上dump这三张表,并记录下同步的binlog和POS点
mysqldump -uroot -pmagedu -q --single-transaction --master-data=2 testdb A B
C >/backup/A_B_C.sql
3、查看A_B_C.sql文件,找出记录的binlog和POS点
head A_B_C.sql
例如:MASTERLOGFILE='mysql-bin.888888', MASTERLOGPOS=666666;
#以下指令是为了保障其他表的数据不丢失,一直同步直到那个点结束,A,B,C表的数据在之前的备份已
经生成了一份快照,只需要导入进入,然后开启同步即可
4、把A_B_C.sql拷贝到Slave机器上,并做指向新位置
mysql>start slave until MASTERLOGFILE='mysql-bin.888888',
MASTERLOGPOS=666666;
5、在Slave机器上导入A_B_C.sql
mysql -uroot -pmagedu testdb
mysql>set sql_log_bin=0;
mysql>source /backup/A_B_C.sql
mysql>set sql_log_bin=1;
6、导入完毕后,从库开启同步即可。
mysql>start slave;
6.1.10.4.3 如何避免主从不一致
主库binlog采用ROW格式
主从实例数据库版本保持一致
主库做好账号权限把控,不可以执行set sql_log_bin=0
从库开启只读,不允许人为写入
定期进行主从一致性检验
6.2 MySQL 中间件代理服务器
6.2.1 关系型数据库和 NoSQL 数据库
数据库主要分为两大类:关系型数据库与 NoSQL 数据库。
关系型数据库,是建立在关系模型基础上的数据库,其借助于集合代数等数学概念和方法来处理数据库
中的数据。主流的 MySQL、Oracle、MS SQL Server 和 DB2 都属于这类传统数据库。
NoSQL 数据库,全称为 Not Only SQL,意思就是适用关系型数据库的时候就使用关系型数据库,不适
用的时候也没有必要非使用关系型数据库不可,可以考虑使用更加合适的数据存储。主要分为临时性键
值存储(Redis、memcached)、永久性键值存储(ROMA、Redis)、面向文档的数据库
(MongoDB、CouchDB)、面向列的数据库(Cassandra、HBase),每种 NoSQL 都有其特有的使用
场景及优点。
Oracle,mysql 等传统的关系数据库非常成熟并且已大规模商用,为什么还要用 NoSQL 数据库呢?主
要是由于随着互联网发展,数据量越来越大,对性能要求越来越高,传统数据库存在着先天性的缺陷,
即单机(单库)性能瓶颈,并且扩展困难。这样既有单机单库瓶颈,却又扩展困难,自然无法满足日益
增长的海量数据存储及其性能要求,所以才会出现了各种不同的 NoSQL 产品,NoSQL 根本性的优势在
于在云计算时代,简单、易于大规模分布式扩展,并且读写性能非常高
RDBMS和NOSQL的特点及优缺点:
6.2.2 数据库切分方式
简单来说,就是指通过某种特定的条件,将我们存放在同一个数据库中的数据分散存放到多个数据库
(主机) 上面,以达到分散单台设备负载的效果。
数据的切分(Sharding)根据其切分规则的类型,可以分为两种切分模式。
一种是按照不同的表(或者 Schema)来切分到不同的数据库(主机)之上,这种切可以称之为数据的
垂直(纵向)切分;另外一种则是根据 表中的数据的逻辑关系,将同一个表中的数据按照某种条件拆分
到多台数据库(主机)上面,这种切分称之为数据的水平(横向)切分。
垂直切分的最大特点就是规则简单,实施也更为方便,尤其适合各业务之间的耦合度非常低,相互影响
很小, 业务逻辑非常清晰的系统。在这种系统中,可以很容易做到将不同业务模块所使用的表分拆到不
同的数据库中。 根据不同的表来进行拆分,对应用程序的影响也更小,拆分规则也会比较简单清晰。
水平切分于垂直切分相比,相对来说稍微复杂一些。因为要将同一个表中的不同数据拆分到不同的数据
库中, 对于应用程序来说,拆分规则本身就较根据表名来拆分更为复杂,后期的数据维护也会更为复杂
一些。
6.2.2.1 垂直切分
一个数据库由很多表的构成,每个表对应着不同的业务,垂直切分是指按照业务将表进行分类,分布到
不同的数据库上面,这样也就将数据或者说压力分担到不同的库上面,如下图:
系统被切分成了,用户,订单交易,支付几个模块。 一个架构设计较好的应用系统,其总体功能肯定是
由很多个功能模块所组成的,而每一个功能模块所需要的数据对应到数据库中就是一个或者多个表。而
在架构设计中,各个功能模块相互之间的交互点越统一越少,系统的耦合度就越低,系统各个模块的维
护性以及扩展性也就越好。这样的系统,实现数据的垂直切分也就越容易。
但是往往系统之有些表难以做到完全独立,存在着跨库 join 的情况,对于这类表,就需要去做平衡, 是
数据库让步业务,共用一个数据源,还是分成多个库,业务之间通过接口来做调用。在系统初期,数据
量比较 少,或者资源有限的情况下,会选择共用数据源,但是当数据发展到了一定的规模,负载很大的
情况,就需要必须去做分割。
一般来讲业务存在着复杂 join 的场景是难以切分的,往往业务独立的易于切分。如何切分,切分到何种
程度是考验技术架构的一个难题。
垂直切分的优缺点:
优点:
拆分后业务清晰,拆分规则明确
系统之间整合或扩展容易
数据维护简单
缺点:
部分业务表无法 join,只能通过接口方式解决,提高了系统复杂度
受每种业务不同的限制存在单库性能瓶颈,不易数据扩展跟性能提高
事务处理复杂
由于垂直切分是按照业务的分类将表分散到不同的库,所以有些业务表会过于庞大,存在单库读写与存
储瓶颈,所以就需要水平拆分来做解决。
6.2.2.2 水平切分
![image-
对应shard中查询相关数据
相对于垂直拆分,水平拆分不是将表做分类,而是按照某个字段的某种规则来分散到多个库之中,每个
表中包含一部分数据。简单来说,我们可以将数据的水平切分理解为是按照数据行的切分,就是将表中
的某些行切分 到一个数据库,而另外的某些行又切分到其他的数据库中,如图:
拆分数据就需要定义分片规则。关系型数据库是行列的二维模型,拆分的第一原则是找到拆分维度。比
如: 从会员的角度来分析,商户订单交易类系统中查询会员某天某月某个订单,那么就需要按照会员结
合日期来拆分, 不同的数据按照会员 ID 做分组,这样所有的数据查询 join 都会在单库内解决;如果从
商户的角度来讲,要查询某个商家某天所有的订单数,就需要按照商户 ID 做拆分;但是如果系统既想按
会员拆分,又想按商家数据,则会有 一定的困难。如何找到合适的分片规则需要综合考虑衡量。
几种典型的分片规则包括:
按照用户 ID 求模,将数据分散到不同的数据库,具有相同数据用户的数据都被分散到一个库中
按照日期,将不同月甚至日的数据分散到不同的库中
按照某个特定的字段求摸,或者根据特定范围段分散到不同的库中
如图,切分原则都是根据业务找到适合的切分规则分散到不同的库,下面用用户 ID 求模举例:
既然数据做了拆分有优点也就优缺点。
优点:
拆分规则抽象良好,join 操作基本都可以数据库完成
不存在单库大数据,高并发的性能瓶颈
应用端改造较少
提高了系统的稳定性跟负载能力
缺点:
拆分规则难以抽象
分片事务一致性难以解决
数据多次扩展难度跟维护量极大
跨库 join 性能较差
前面讲了垂直切分跟水平切分的不同跟优缺点,会发现每种切分方式都有缺点,但共同特点缺点有:
引入分布式事务的问题
跨节点 Join 的问题
跨节点合并排序分页问题
多数据源管理问题
针对数据源管理,目前主要有两种思路:
- 客户端模式,在每个应用程序模块中配置管理自己需要的一个(或者多个)数据源,直接访问各个数
据库, 在模块内完成数据的整合
- 通过中间代理层来统一管理所有的数据源,后端数据库集群对前端应用程序透明; 可能 90%以上的
人在面对上面这两种解决思路的时候都会倾向于选择第二种,尤其是系统不断变得庞大复杂 的时候。确
实,这是一个非常正确的选择,虽然短期内需要付出的成本可能会相对更大一些,但是对整个系统的 扩
展性来说,是非常有帮助的。
MySQL中间件服务器可以通过将数据切分解决传统数据库的缺陷,又有了 NoSQL 易于扩展的优点。通
过中间代理层规避了多数 据源的处理问题,对应用完全透明,同时对数据切分后存在的问题,也做了解
决方案。
由于数据切分后数据 Join 的难度在此也分享一下数据切分的经验:
第一原则:能不切分尽量不要切分
第二原则:如果要切分一定要选择合适的切分规则,提前规划好。
第三原则:数据切分尽量通过数据冗余或表分组(Table Group)来降低跨库 Join 的可能
第四原则:由于数据库中间件对数据 Join 实现的优劣难以把握,而且实现高性能难度极大,业务读取尽
量少使用多表 Join。
6.2.3 MySQL 中间件各种应用
mysql-proxy:Oracle,https://downloads.mysql.com/archives/proxy/
Atlas:Qihoo,https://github.com/Qihoo360/Atlas/blob/master/README_ZH.md
dbproxy:美团,https://github.com/Meituan-Dianping/DBProxy
Cetus:网易乐得,https://github.com/Lede-Inc/cetus
Amoeba:https://sourceforge.net/projects/amoeba/
Cobar:阿里巴巴,Amoeba的升级版, https://github.com/alibaba/cobar
Mycat:基于Cobar http://www.mycat.io/ (原网站)
https://github.com/MyCATApache/Mycat-Server
ProxySQL:https://proxysql.com/
MaxScale: 是 MariaDB 开发的一个数据库智能代理服务,允许根据数据库 SQL 语句将请求转向目
标一个到多个服务器,可设定各种复杂程度的转向规则。MaxScale 设计用于透明的提供数据库的
负载均衡和高可用性,同时提供高度可伸缩和灵活的架构,支持不同的协议和路由决策。
MaxScale 使用 C 语言开发,利用 Linux 下的异步 I/O 功能。使用 epoll 作为事件驱动框架。
https://mariadb.com/kb/en/maxscale/
6.2.4 Mycat
6.2.4.1 Mycat 介绍
在整个IT系统架构中,数据库是非常重要,通常又是访问压力较大的一个服务,除了在程序开发的本身
做优化,如:SQL语句优化、代码优化,数据库的处理本身优化也是非常重要的。主从、热备、分表分
库等都是系统发展迟早会遇到的技术问题问题。Mycat是一个广受好评的数据库中间件,已经在很多产
品上进行使用了。
Mycat是一个开源的分布式数据库系统,是一个实现了MySQL协议的服务器,前端用户可以把它看作是
一个数据库代理(类似于Mysql Proxy),用MySQL客户端工具和命令行访问,而其后端可以用MySQL
原生协议与多个MySQL服务器通信,也可以用JDBC协议与大多数主流数据库服务器通信,其核心功能是
分表分库,即将一个大表水平分割为N个小表,存储在后端MySQL服务器里或者其他数据库里。
Mycat发展到目前的版本,已经不是一个单纯的MySQL代理了,它的后端可以支持MySQL、SQL
Server、Oracle、DB2、PostgreSQL等主流数据库,也支持MongoDB这种新型NoSQL方式的存储,未
来还会支持更多类型的存储。而在最终用户看来,无论是那种存储方式,在MyCat里,都是一个传统的
数据库表,支持标准的SQL语句进行数据的操作,这样一来,对前端业务系统来说,可以大幅降低开发
难度,提升开发速度
Mycat 可以简单概括为
一个彻底开源的,面向企业应用开发的大数据库集群
支持事务、ACID、可以替代MySQL的加强版数据库
一个可以视为MySQL集群的企业级数据库,用来替代昂贵的Oracle集群
一个融合内存缓存技术、NoSQL技术、HDFS大数据的新型SQL Server
结合传统数据库和新型分布式数据仓库的新一代企业级数据库产品
一个新颖的数据库中间件产品
**Mycat 官网:**http://www.mycat.org.cn/
Mycat 关键特性
支持SQL92标准
遵守MySQL 原生协议,跨语言,跨平台,跨数据库的通用中间件代理
基于心跳的自动故障切换,支持读写分离,支持MySQL主从,以及galera cluster集群
支持Galera for MySQL集群,Percona Cluster或者MariaDB cluster
基于Nio实现,有效管理线程,高并发问题
支持数据的多片自动路由与聚合,支持sum,count,max等常用的聚合函数,支持跨库分页
支持单库内部任意join,支持跨库2表join,甚至基于caltlet的多表join
支持通过全局表,ER关系的分片策略,实现了高效的多表join查询
支持多租户方案
支持分布式事务(弱xa)
支持全局序列号,解决分布式下的主键生成问题
分片规则丰富,插件化开发,易于扩展
强大的web,命令行监控
支持前端作为mysq通用代理,后端JDBC方式支持Oracle、DB2、SQL Server 、 mongodb 、巨杉
支持密码加密
支持服务降级
支持IP白名单
支持SQL黑名单、sql注入攻击拦截
支持分表(1.6)
集群基于ZooKeeper管理,在线升级,扩容,智能优化,大数据处理(2.0开发版)
为什么要用MyCat
这里要先搞清楚Mycat和MySQL的区别(Mycat的核心作用)。我们可以把上层看作是对下层的抽象,
例如操作系统是对各类计算机硬件的抽象。那么我们什么时候需要抽象?假如只有一种硬件的时候,我
们需要开发一个操作系统吗?再比如一个项目只需要一个人完成的时候不需要leader,但是当需要几十
人完成时,就应该有一个管理者,发挥沟通协调等作用,而这个管理者对于他的上层来说就是对项目组
的抽象
同样的,当我们的应用只需要一台数据库服务器的时候我们并不需要Mycat,而如果你需要分库甚至分
表,这时候应用要面对很多个数据库的时候,这个时候就需要对数据库层做一个抽象,来管理这些数据
库,而最上面的应用只需要面对一个数据库层的抽象或者说数据库中间件就好了,这就是Mycat的核心
作用。所以可以这样理解:数据库是对底层存储文件的抽象,而Mycat是对数据库的抽象
Mycat工作原理
Mycat的原理中最重要的一个动词是"拦截",它拦截了用户发送过来的SQL语句,首先对SQL语句做了一
些特定的分析:如分片分析、路由分析、读写分离分析、缓存分析等,然后将此SQL发往后端的真实数
据库,并将返回的结果做适当的处理,最终再返回给用户
Mycat应用场景
Mycat适用的场景很丰富,以下是几个典型的应用场景
单纯的读写分离,此时配置最为简单,支持读写分离,主从切换
分表分库,对于超过1000万的表进行分片,最大支持1000亿的单表分片
多租户应用,每个应用一个库,但应用程序只连接Mycat,从而不改造程序本身,实现多租户化
报表系统,借助于Mycat的分表能力,处理大规模报表的统计
替代Hbase,分析大数据
作为海量数据实时查询的一种简单有效方案,比如100亿条频繁查询的记录需要在3秒内查询出来结
果,除了基于主键的查询,还可能存在范围查询或其他属性查询,此时Mycat可能是最简单有效的
选择
Mycat长期路线图
强化分布式数据库中间件的方面的功能,使之具备丰富的插件、强大的数据库智能优化功能、全面
的系统监控能力、以及方便的数据运维工具,实现在线数据扩容、迁移等高级功能
进一步挺进大数据计算领域,深度结合Spark Stream和Storm等分布式实时流引擎,能够完成快速
的巨表关联、排序、分组聚合等 OLAP方向的能力,并集成一些热门常用的实时分析算法,让工程
师以及DBA们更容易用Mycat实现一些高级数据分析处理功能
不断强化Mycat开源社区的技术水平,吸引更多的IT技术专家,使得Mycat社区成为中国的
Apache,并将Mycat推到Apache基金会,成为国内顶尖开源项目,最终能够让一部分志愿者成为
专职的Mycat开发者,荣耀跟实力一起提升
Mycat不适合的应用场景
设计使用Mycat时有非分片字段查询,请慎重使用Mycat,可以考虑放弃!
设计使用Mycat时有分页排序,请慎重使用Mycat,可以考虑放弃!
设计使用Mycat时如果要进行表JOIN操作,要确保两个表的关联字段具有相同的数据分布,否则请
慎重使用Mycat,可以考虑放弃!
设计使用Mycat时如果有分布式事务,得先看是否得保证事务得强一致性,否则请慎重使用
Mycat,可以考虑放弃!
MyCat的高可用性:
需要注意: 在生产环境中, Mycat节点最好使用双节点, 即双机热备环境, 防止Mycat这一层出现单点故障.
可以使用的高可用集群方式有:
Keepalived+Mycat+Mysql
Keepalived+LVS+Mycat+Mysql
Keepalived+Haproxy+Mycat+Mysql
6.2.4.2 Mycat 安装
下载安装JDK
yum -y install java
#确认安装成功
java -version
openjdk version "1.8.0_201"
OpenJDK Runtime Environment (build 1.8.0_201-b09)
OpenJDK 64-Bit Server VM (build 25.201-b09, mixed mode)
下载安装mycat
wget http://dl.mycat.org.cn/1.6.7.4/Mycat-server-1.6.7.4-release/Mycat-server-
1.6.7.4-release-20200105164103-linux.tar.gz
mkdir /apps
tar xvf Mycat-server-1.6.7.4-release-20200105164103-linux.tar.gz -C /apps
ls /apps/mycat/
bin catlet conf lib logs version.txt
mycat安装目录结构:
bin mycat命令,启动、重启、停止等
catlet catlet为Mycat的一个扩展功能
conf Mycat 配置信息,重点关注
lib
Mycat引用的jar包,Mycat是java开发的
logs 日志文件,包括Mycat启动的日志和运行的日志
version.txt mycat版本说明
logs目录:
wrapper.log
mycat.log
mycat启动日志
mycat详细工作日志
Mycat的配置文件都在conf目录里面,这里介绍几个常用的文件:
server.xml Mycat软件本身相关的配置文件,设置账号、参数等
schema.xml Mycat对应的物理数据库和数据库表的配置,读写分离、高可用、分布式策略定制、
节点控制
rule.xml
Mycat分片(分库分表)规则配置文件,记录分片规则列表、使用方法等
启动和连接
#配置环境变量
vim /etc/profile.d/mycat.sh
PATH=/apps/mycat/bin:$PATH
source /etc/profile.d/mycat.sh
#启动
mycat start
#查看日志,确定成功
cat /app/mycat/logs/wrapper.log
...省略...
INFO
| jvm 1
| 2019/11/01 21:41:02 | MyCAT Server startup successfully. see
logs in logs/mycat.log
#连接mycat:
mysql -uroot -p123456 -h 127.0.0.1 -P8066
6.2.4.3 Mycat 主要配置文件说明
server.xml
存放Mycat软件本身相关的配置文件,比如:连接Mycat的用户,密码,数据库名称等
server.xml文件中配置的参数解释说明:
参数
说明
user
用户配置节点
name
客户端登录MyCAT的用户名,也就是客户端用来连接Mycat的用户名。
password 客户端登录MyCAT的密码
schemas 数据库名,这里会和schema.xml中的配置关联,多个用逗号分开,例如:db1,db2
privileges 配置用户针对表的增删改查的权限
readOnly
mycat逻辑库所具有的权限。true为只读,false为读写都有,默认为false
注意:
server.xml文件里登录mycat的用户名和密码可以任意定义,这个账号和密码是为客户机登录
mycat时使用的账号信息
逻辑库名(如上面的TESTDB,也就是登录mycat后显示的库名,切换这个库之后,显示的就是代理
的真实mysql数据库的表)要在schema.xml里面也定义,否则会导致mycat服务启动失败!
这里只定义了一个标签,所以把多余的都注释了。如果定义多个标签,即设置多个连接mycat的用
户名和密码,那么就需要在schema.xml文件中定义多个对应的库!
schema.xml
是最主要的配置项,此文件关联mysql读写分离策略,读写分离、分库分表策略、分片节点都是在此文
件中配置的.MyCat作为中间件,它只是一个代理,本身并不进行数据存储,需要连接后端的MySQL物理
服务器,此文件就是用来连接MySQL服务器的
schema.xml文件中配置的参数解释说明:
参数
说明
schema
dataNode
dataHost
数据库设置,此数据库为逻辑数据库,name与server.xml中schema对应
分片信息,也就是分库相关配置
物理数据库,真正存储数据的数据库
配置说明
name属性唯一标识dataHost标签,供上层的标签使用。
maxCon属性指定每个读写实例连接池的最大连接。也就是说,标签内嵌套的writeHost、readHost标
签都会使用这个属性的值来实例化出连接池的最大连接数
minCon属性指定每个读写实例连接池的最小连接,初始化连接池的大小
每个节点的属性逐一说明
schema:
属性
说明
name
逻辑数据库名,与server.xml中的schema对应
checkSQLschema 数据库前缀相关设置,这里为false
sqlMaxLimit
select 时默认的limit,避免查询全表
table
属性
说明
name
dataNode
表名,物理数据库中表名
表存储到哪些节点,多个节点用逗号分隔。节点为下文dataNode设置的name
primaryKey 主键字段名,自动生成主键时需要设置
autoIncrement 是否自增
rule
分片规则名,具体规则下文rule详细介绍
dataNode
属性
说明
name
datahost
database
节点名,与table中dataNode对应
物理数据库名,与datahost中name对应
物理数据库中数据库名
dataHost
属性
说明
name
物理数据库名,与dataNode中dataHost对应
均衡负载的方式
写入方式
数据库类型
心跳检测语句,注意语句结尾的分号要加
balance
writeType
dbType
heartbeat
schema.xml文件中有三点需要注意:balance="1",writeType="0" ,switchType="1"
schema.xml中的balance的取值决定了负载均衡对非事务内的读操作的处理。balance 属性负载均衡类
型,目前的取值有 4 种:
balance="0":不开启读写分离机制,所有读操作都发送到当前可用的writeHost上,即读请求仅发送到
writeHost上
balance="1":一般用此模式,读请求随机分发到当前writeHost对应的readHost和standby的
writeHost上。即全部的readHost与stand by writeHost 参与 select 语句的负载均衡,简单的说,当双
主双从模式(M1 ->S1 , M2->S2,并且 M1 与 M2 互为主备),正常情况下, M2,S1, S2 都参与 select 语
句的负载均衡
balance="2":读请求随机分发到当前dataHost内所有的writeHost和readHost上。即所有读操作都随
机的在writeHost、 readhost 上分发
balance="3":读请求随机分发到当前writeHost对应的readHost上。即所有读请求随机的分发到
wiriterHost 对应的 readhost 执行, writerHost 不负担读压力,注意 balance=3 只在 1.4 及其以后版本
有,1.3 没有
writeHost和readHost 标签
这两个标签都指定后端数据库的相关配置给mycat,用于实例化后端连接池。
唯一不同的是:writeHost指定写实例、readHost指定读实例,组着这些读写实例来满足系统的要求。
在一个dataHost内可以定义多个writeHost和readHost。但是,如果writeHost指定的后端数据库宕机,
那么这个writeHost绑定的所有readHost都将不可用。另一方面,由于这个writeHost宕机系统会自动的
检测到,并切换到备用的writeHost上去
注意:
Mycat主从分离只是在读的时候做了处理,写入数据的时候,只会写入到writehost,需要通过mycat的
主从复制将数据复制到readhost
6.2.4.4 实战案例:利用 Mycat 实现 MySQL 的读写分离
所有主机的系统环境:
cat /etc/centos-release
CentOS Linux release 8.0.1905 (Core)
服务器共三台
mycat-server 10.0.0.8 #内存建议2G以上
mysql-master 10.0.0.18 MySQL 8.0 或者Mariadb 10.3.17
mysql-slave 10.0.0.28 MySQL 8.0 或者Mariadb 10.3.17
关闭SELinux和防火墙
systemctl stop firewalld
setenforce 0
时间同步
1、创建 MySQL 主从数据库
[root@centos8 ~]#yum -y install mysql-server
#或者
[root@centos8 ~]#yum -y install mariadb-server
1) 修改master和slave上的配置文件
#master上的my.cnf
[root@centos8 ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id = 1
log-bin
#slave上的my.cnf
[mysqld]
server-id = 2
[root@centos8 ~]#systemctl start mariadb
2) Master上创建复制用户
[root@centos8 ~]#mysql -uroot -p
MariaDB [(none)]>GRANT REPLICATION SLAVE ON *.* TO 'repluser'@'10.0.0.%'
IDENTIFIED BY 'replpass';
mysql> FLUSH PRIVILEGES;
mysql> show master status;
+------------------+----------+--------------+------------------+----------------
| File
| Position | Binlog_Do_DB | Binlog_Ignore_DB |
Executed_Gtid_Set |
+------------------+----------+--------------+------------------+----------------
|mariadb-bin.000001|
|
403 |
|
|
+------------------+----------+--------------+------------------+----------------
1 row in set (0.00 sec)
3) Slave上执行
[root@centos8 ~]#mysql -uroot -p
mysql> CHANGE MASTER TO
->
->
->
->
->
MASTER_HOST='10.0.0.%',
MASTER_USER='repluser',
MASTER_PASSWORD='replpass',
MASTER_LOG_FILE='mariadb-bin.000001',
MASTER_LOG_POS=403;
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 10.0.0.18
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mariadb-bin.000001
Read_Master_Log_Pos: 439
Relay_Log_File: mariadb-relay-bin.000002
Relay_Log_Pos: 689
Relay_Master_Log_File: mariadb-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...省略..,
2、在MySQL代理服务器10.0.0.8安装mycat并启动
root@centos8 ~]#yum -y install java
#确认安装成功
[root@centos8 ~]#java -version
openjdk version "1.8.0_201"
OpenJDK Runtime Environment (build 1.8.0_201-b09)
OpenJDK 64-Bit Server VM (build 25.201-b09, mixed mode)
#下载并安装
[root@centos8 ~]#wget http://dl.mycat.org.cn/1.6.7.6/20210303094759/Mycat-server-
1.6.7.6-release-20210303094759-linux.tar.gz
#wget http://dl.mycat.org.cn/1.6.7.4/Mycat-server-1.6.7.4-release/Mycat-server-
1.6.7.4-release-20200105164103-linux.tar.gz
[root@centos8 ~]#mkdir /apps
[root@centos8 ~]#tar xvf Mycat-server-1.6.7.6-release-20210303094759-linux.tar.gz
-C /apps/
#tar xvf Mycat-server-1.6.7.4-release-20200105164103-linux.tar.gz -C /apps
#配置环境变量
[root@centos8 ~]#echo 'PATH=/apps/mycat/bin:$PATH' > /etc/profile.d/mycat.sh
[root@centos8 ~]#source /etc/profile.d/mycat.sh
#查看端口
[root@centos8 ~]#ss -ntl
State
Recv-Q
Send-Q
128
Local Address:Port
0.0.0.0:22
Peer Address:Port
0.0.0.0:*
LISTEN
0
0
LISTEN
128
[::]:22
[::]:*
#启动mycat
[root@mycat ~]#file /apps/mycat/bin/mycat
/apps/mycat/bin/mycat: POSIX shell script, ASCII text executable
[root@mycat ~]#mycat
Usage: /apps/mycat/bin/mycat { console | start | stop | restart | status | dump
}
#注意: 此步启动较慢,需要等一会儿,另外如果内存太小,会导致无法启动
[root@centos8 ~]#mycat start
Starting Mycat-server...
#可以看到打开多个端口,其中8066端口用于连接MyCAT
[root@centos8 ~]#ss -ntlp
State
Recv-Q
0
Send-Q Local Address:Port
Peer Address:Port
LISTEN
LISTEN
LISTEN
LISTEN
LISTEN
LISTEN
LISTEN
LISTEN
128
0.0.0.0:22
127.0.0.1:32000
[::]:22
0.0.0.0:*
0.0.0.0:*
[::]:*
*:*
users:(("sshd",pid=791,fd=5))
0
1
users:(("java",pid=4640,fd=4))
128
users:(("sshd",pid=791,fd=7))
50
users:(("java",pid=4640,fd=57))
100
users:(("java",pid=4640,fd=87))
50
users:(("java",pid=4640,fd=58))
100
users:(("java",pid=4640,fd=83))
50
users:(("java",pid=4640,fd=56))
0
0
*:1984
0
*:8066
*:*
0
*:43465
*:*
0
*:9066
*:*
0
*:45259
*:*
#查看日志,确定成功,可能需要等一会儿才能看到成功的提示
[root@centos8 ~]#tail /apps/mycat/logs/wrapper.log
ERROR | wrapper | 2020/02/28 15:21:48 | Startup failed: Timed out waiting for
a signal from the JVM.
ERROR | wrapper | 2020/02/28 15:21:48 | JVM did not exit on request,
terminated
INFO
| wrapper | 2020/02/28 15:21:48 | JVM exited on its own while waiting to
kill the application.
STATUS | wrapper | 2020/02/28 15:21:48 | JVM exited in response to signal
SIGKILL (9).
STATUS | wrapper | 2020/02/28 15:21:52 | Launching a JVM...
INFO
ignoring option MaxPermSize=64M; support was removed in 8.0
INFO | jvm 2 | 2020/02/28 15:22:13 | Wrapper (Version 3.2.3)
http://wrapper.tanukisoftware.org
INFO | jvm 2 | 2020/02/28 15:22:13 |
Inc. All Rights Reserved.
| jvm 2
| 2020/02/28 15:21:52 | OpenJDK 64-Bit Server VM warning:
Copyright 1999-2006 Tanuki Software,
INFO
INFO
| jvm 2
| jvm 2
| 2020/02/28 15:22:13 |
| 2020/02/28 15:22:31 | MyCAT Server startup successfully. see
logs in logs/mycat.log
#用默认密码123456来连接mycat
[root@centos8 ~]#mysql -uroot -p123456 -h 10.0.0.8 -P8066
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.6.29-mycat-1.6-RELEASE-20161028204710 MyCat Server
(OpenCloundDB)
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MySQL [(none)]> show databases;
+----------+
| DATABASE |
+----------+
| TESTDB |
+----------+
1 row in set (0.01 sec)
MySQL [TESTDB]> show tables;
+------------------+
| Tables in TESTDB |
+------------------+
| address
|
|
| travelrecord
+------------------+
2 rows in set (0.01 sec)
MySQL [TESTDB]> select * from travelrecord ;
ERROR 1105 (HY000): backend connect: java.lang.IllegalArgumentException: Invalid
DataSource:0
MySQL [TESTDB]>
4、在mycat 服务器上修改server.xml文件配置Mycat的连接信息
[root@centos8 ~]#vim /apps/mycat/conf/server.xml
...省略...
#修改下面行的8066改为3306复制到到独立非注释行
<property name="serverPort">3306</property>
<property name="handlelDistributedTransactions">0</property> #将上面行放在此行前面
#或者删除注释,并修改下面行的8066改为3306
<property name="serverPort">3306</property>
<property name="managerPort">9066</property>
<property name="idleTimeout">300000</property>
<property name="authTimeout">15000</property>
<property name="bindIp">0.0.0.0</property>
<property name="dataNodeIdleCheckPeriod">300000</property> #5 * 60 * 1000L; //连
接空闲检查 删除#后面此部分
<property name="frontWriteQueueSize">4096</property> <property
name="processors">32</property> #--> 删除#后面此部分
.....
<user name="root">
#连接Mycat的用户名
<property name="password">magedu</property>
#连接Mycat的密码
<property name="schemas">TESTDB</property>
#数据库名要和schema.xml相
对应
</user>
</mycat:server>
这里使用的是root,密码为magedu,逻辑数据库为TESTDB,这些信息都可以自己随意定义,读写权限都
有,没有针对表做任何特殊的权限。重点关注上面这段配置,其他默认即可。
5、修改schema.xml实现读写分离策略
[root@centos8 ~]#vim /apps/mycat/conf/schema.xml
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="***false***" sqlMaxLimit="100"
dataNode="***dn1***"></schema>
<dataNode name="dn1" dataHost="localhost1" database="***mycat***" /> #其中mycat表
示后端服务器实际的数据库名称
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="***1***"
writeType="0" dbType="mysql" dbDriver="native" switchType="1"
slaveThreshold="100">
<heartbeat>select user()</heartbeat>
***<writeHost host="host1" url="10.0.0.18:3306" user="root"
password="123456">***
***<readHost host="host2" url="10.0.0.28:3306" user="root" password="123456"
/>***
</writeHost>
</dataHost>
</mycat:schema>
#以上***部分表示原配置文件中需要修改的内容
#注意大小写
#最终文件内容
[root@mycat ~]#cat /apps/mycat/conf/schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100"
dataNode="dn1">
</schema>
<dataNode name="dn1" dataHost="localhost1" database="hellodb" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="1"
slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="host1" url="10.0.0.18:3306" user="root"
password="123456">
<readHost host="host2" url="10.0.0.28:3306" user="root"
password="123456" />
</writeHost>
</dataHost>
</mycat:schema>
#重新启动mycat
[root@centos8 ~]#mycat restart
上面配置中,balance改为1,表示读写分离。以上配置达到的效果就是10.0.0.18为主库,10.0.0.28为
从库
注意:要保证能使用root/123456权限成功登录10.0.0.18和10.0.0.28机器上面的mysql数据库。同时,
也一定要授权mycat机器能使用root/123456权限成功登录这两台机器的mysql数据库!!这很重要,否
则会导致登录mycat后,对库和表操作失败!
范例:schema.xml
6、在后端主服务器创建用户并对mycat授权
[root@centos8 ~]#mysql -uroot -p
mysql> create database mycat;
mysql>GRANT ALL ON *.* TO 'root'@'10.0.0.%' IDENTIFIED BY '123456' ;
mysql> flush privileges;
7、在Mycat服务器上连接并测试
[root@centos8 ~]#mysql -uroot -pmagedu -h127.0.0.1 TESTDB
mysql> show databases;
+----------+
| DATABASE |
+----------+
| TESTDB |
+----------+
//只能看一个虚拟数据库
mysql> use TESTDB;
mysql> create table t1(id int);
MySQL> select @@server_id;
MySQL> select @@hostname;
8、通过通用日志确认实现读写分离
在mysql中查看通用日志
show variables like 'general_log'; #查看日志是否开启
set global general_log=on;
#开启日志功能
show variables like 'general_log_file'; #查看日志文件保存位置
set global general_log_file='tmp/general.log'; #设置日志文件保存位置
在主和从服务器分别启用通用日志,查看读写分离
[root@centos8 ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
general_log=ON
[root@centos8 ~]#systemctl restart mariadb
[root@centos8 ~]#tail -f /var/lib/mysql/centos8.log
9、停止从节点,MyCAT自动调度读请求至主节点
[root@slave ~]#systemctl stop mariadb
[root@client ~]#mysql -uroot -pmagedu -h10.0.0.8 -P8066
MySQL [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|
1 |
+-------------+
1 row in set (0.00 sec)
MySQL [(none)]>
#停止主节点,MyCAT不会自动调度写请求至从节点
MySQL [TESTDB]> insert teachers values(5,'wang',30,'M');
ERROR 1184 (HY000): java.net.ConnectException: Connection refused
10、MyCAT对后端服务器的健康性检查方法select user()
#开启通用日志
[root@master ~]#mysql
mysql> set global general_log=1;
[root@slave ~]#mysql
mysql> set global general_log=1;
#查看通用日志
[root@master ~]#tail -f /var/lib/mysql/master.log
/usr/libexec/mysqld, Version: 8.0.17 (Source distribution). started with:
Tcp port: 3306 Unix socket: /var/lib/mysql/mysql.sock
Time
Id Command
Argument
2021-02-22T08:52:57.086198Z
2021-02-22T08:53:07.086340Z
2021-02-22T08:53:17.086095Z
2021-02-22T08:53:27.086629Z
17 Query select user()
24 Query select user()
16 Query select user()
18 Query select user()
[root@slave ~]#tail -f /var/lib/mysql/slave.log
/usr/libexec/mysqld, Version: 8.0.17 (Source distribution). started with:
Tcp port: 3306 Unix socket: /var/lib/mysql/mysql.sock
Time
Id Command
Argument
2021-02-22T08:46:01.437376Z
2021-02-22T08:46:11.438172Z
2021-02-22T08:46:21.437458Z
2021-02-22T08:46:31.437742Z
10 Query select user()
11 Query select user()
12 Query select user()
13 Query select user()
6.2.5 ProxySQL
6.2.5.1 ProxySQL 介绍
ProxySQL: MySQL中间件
两个版本:官方版和percona版,percona版是基于官方版基础上修改
C++语言开发,轻量级但性能优异,支持处理千亿级数据
具有中间件所需的绝大多数功能,包括:
多种方式的读/写分离
定制基于用户、基于schema、基于语句的规则对SQL语句进行路由
缓存查询结果
后端节点监控
官方站点:https://proxysql.com/
官方手册:https://github.com/sysown/proxysql/wiki
6.2.5.2 ProxySQL 安装
基于YUM仓库安装
cat <<EOF | tee /etc/yum.repos.d/proxysql.repo
[proxysql_repo]
name= ProxySQL YUM repository
baseurl=http://repo.proxysql.com/ProxySQL/proxysql-1.4.x/centos/\releasever
gpgcheck=1
gpgkey=http://repo.proxysql.com/ProxySQL/repo_pub_key
EOF
#基于RPM下载安装:https://github.com/sysown/proxysql/releases
yum install proxysql
ProxySQL组成
服务脚本:/etc/init.d/proxysql
配置文件:/etc/proxysql.cnf
主程序:/usr/bin/proxysql
基于SQLITE的数据库文件:/var/lib/proxysql/
启动ProxySQL:
service proxysql start
启动后会监听两个默认端口
6032:ProxySQL的管理端口
6033:ProxySQL对外提供服务的端口
连接ProxySQL的管理端口
使用mysql客户端连接到ProxySQL的管理接口6032,默认管理员用户和密码都是admin:
mysql -uadmin -padmin -P6032 -h127.0.0.1
数据库说明:
main 是默认的"数据库"名,表里存放后端db实例、用户验证、路由规则等信息。表名以 runtime
开头的表示
proxysql当前运行的配置内容,不能通过dml语句修改,只能修改对应的不以 runtime_ 开头的
(在内存)里的表,然后 LOAD 使其生效, SAVE 使其存到硬盘以供下次重启加载
disk 是持久化到硬盘的配置,sqlite数据文件
stats 是proxysql运行抓取的统计信息,包括到后端各命令的执行次数、流量、processlist、查询
种类汇总/执行时间,等等
monitor 库存储 monitor 模块收集的信息,主要是对后端db的健康/延迟检查
说明:
在main和monitor数据库中的表, runtime开头的是运行时的配置,不能修改,只能修改非
runtime表
修改后必须执行LOAD … TO RUNTIME才能加载到RUNTIME生效
执行save … to disk 才将配置持久化保存到磁盘,即保存在proxysql.db文件中
global_variables 有许多变量可以设置,其中就包括监听的端口、管理账号等
参考: https://github.com/sysown/proxysql/wiki/Global-variables
7.2.5.3 实战案例:利用 ProxySQL 实现读写分离
1. 环境准备:
准备三台主机,一台ProxySQL服务器:192.168.8.7,另外两台主机实现主从复制192.168.8.17,27
注意:slave节点需要设置read_only=1
2. 安装ProxySQL,并向ProxySQL中添加MySQL节点,以下操作不需要use main也可成功
MySQL> show tables;
MySQL > select * from sqlite_master where name='mysql_servers'\G
MySQL > select * from mysql_servers;
MySQL > insert into mysql_servers(hostgroup_id,hostname,port)
values(10,'192.168.8.17',3306);
MySQL > insert into mysql_servers(hostgroup_id,hostname,port)
values(10,'192.168.8.27',3306);
MySQL > load mysql servers to runtime;
MySQL > save mysql servers to disk;
3. 添加监控后端节点的用户,连接每个节点的read_only值来自动调整主从节点是属于读组还是写组
#在master上执行
MySQL> grant replication client on *.* to monitor@'192.168.8.%' identified
by 'magedu';
#ProxySQL上配置监控
MySQL [(none)]> set mysql-monitor_username='monitor';
MySQL [(none)]> set mysql-monitor_password='magedu';
#加载到RUNTIME,并保存到disk
MySQL [(none)]> load mysql variables to runtime;
MySQL [(none)]> save mysql variables to disk;
4. 查看监控
监控模块的指标保存在monitor库的log表中
#查看监控连接是否正常的 (对connect指标的监控),如果connect_error的结果为NULL则表示正
常
MySQL> select * from mysql_server_connect_log;
#查看监控心跳信息 (对ping指标的监控):
MySQL> select * from mysql_server_ping_log;
5. 设置分组信息
需要修改的是main库中的mysql_replication_hostgroups表,该表有3个字段:
writer_hostgroup,reader_hostgroup,comment, 指定写组的id为10,读组的id为20
MySQL> insert into mysql_replication_hostgroups values(10,20,"test");
#将mysql_replication_hostgroups表的修改加载到RUNTIME生效
MySQL> load mysql servers to runtime;
MySQL> save mysql servers to disk;
#Monitor模块监控后端的read_only值,按照read_only的值将节点自动移动到读/写组
MySQL> select hostgroup_id,hostname,port,status,weight from mysql_servers;
+--------------+--------------+------+--------+--------+
| hostgroup_id | hostname
| port | status | weight |
+--------------+--------------+------+--------+--------+
| 10
| 20
| 192.168.8.17 | 3306 | ONLINE | 1
| 192.168.8.27 | 3306 | ONLINE | 1
|
|
6. 配置访问数据库的SQL 用户
#在master节点上创建访问用户
MySQL> grant all on *.* to sqluser@'192.168.8.%' identified by 'magedu';
#在ProxySQL配置,将用户sqluser添加到mysql_users表中, default_hostgroup默认组设置为
写组10,当读写分离的路由规则不符合时,会访问默认组的数据库
MySQL> insert into mysql_users(username,password,default_hostgroup)
values('sqluser','magedu',10);
MySQL> load mysql users to runtime;
MySQL> save mysql users to disk;
#使用sqluser用户测试是否能路由到默认的10写组实现读、写数据
mysql -usqluser -pmagedu -P6033 -h127.0.0.1 -e 'select @@server_id'
mysql -usqluser -pmagedu -P6033 -h127.0.0.1 -e 'create database testdb'
mysql -usqluser -pmagedu testdb -P6033 -h127.0.0.1 -e 'create table t(id
int)'
7. 在proxysql上配置路由规则,实现读写分离
与规则有关的表:mysql_query_rules和mysql_query_rules_fast_routing,后者是前者的扩展
表,1.4.7之后支持
插入路由规则:将select语句分离到20的读组,select语句中有一个特殊语句SELECT...FOR
UPDATE它会申请写锁,应路由到10的写组
MySQL> insert into mysql_query_rules
(rule_id,active,match_digest,destination_hostgroup,apply)VALUES
(1,1,'^SELECT.*FOR UPDATE$',10,1),(2,1,'^SELECT',20,1);
MySQL> load mysql query rules to runtime;
MySQL> save mysql query rules to disk;
#注意:因ProxySQL根据rule_id顺序进行规则匹配,select ... for update规则的rule_id必
须要小于普通的select规则的rule_id
8. 测试ProxySQL
#读操作是否路由给20的读组
mysql -usqluser -pmagedu -P6033 -h127.0.0.1 -e 'select @@server_id'
#测试写操作,以事务方式进行测试
mysql -usqluser -pmagedu -P6033 -h127.0.0.1 \
-e 'start transaction;select @@server_id;commit;select @@server_id'
mysql -usqluser -pmagedu -P6033 -h127.0.0.1 -e 'insert testdb.t values (1)'
mysql -usqluser -pmagedu -P6033 -h127.0.0.1 -e 'select id from testdb.t'
#路由的信息:查询stats库中的stats_mysql_query_digest表
MySQL > SELECT hostgroup hg,sum_time, count_star, digest_text
stats_mysql_query_digest ORDER BY sum_time DESC;
FROM
#测试读操作是否路由给20的读组
mysql -usqluser -pmagedu -P6033 -h127.0.0.1 -e 'select @@server_id'
#测试写操作,以事务方式进行测试
mysql -usqluser -pmagedu -P6033 -h127.0.0.1 \
-e 'start transaction;select @@server_id;commit;select @@server_id'
mysql -usqluser -pmagedu -P6033 -h127.0.0.1 -e 'insert testdb.t values (1)'
mysql -usqluser -pmagedu -P6033 -h127.0.0.1 -e 'select id from testdb.t'
#路由的信息:查询stats库中的stats_mysql_query_digest表
MySQL > SELECT hostgroup hg,sum_time, count_star, digest_text
stats_mysql_query_digest ORDER BY sum_time DESC;
FROM
6.3 MySQL 高可用
6.3.1 MySQL 高可用解决方案
MySQL官方和社区里推出了很多高可用的解决方案,大体如下,仅供参考(数据引用自Percona)
MMM: Multi-Master Replication Manager for MySQL,Mysql主主复制管理器是一套灵活的脚本
程序,基于perl实现,用来对mysql replication进行监控和故障迁移,并能管理mysql Master-
Master复制的配置(同一时间只有一个节点是可写的)
https://code.google.com/archive/p/mysql-master-master/downloads
MHA:Master High Availability,对主节点进行监控,可实现自动故障转移至其它从节点;通过提
升某一从节点为新的主节点,基于主从复制实现,还需要客户端配合实现,目前MHA主要支持一主
多从的架构,要搭建MHA,要求一个复制集群中必须最少有三台数据库服务器,一主二从,即一台
充当master,一台充当备用master,另外一台充当从库,出于机器成本的考虑,淘宝进行了改
造,目前淘宝TMHA已经支持一主一从
官方网站:https://code.google.com/archive/p/mysql-master-ha/
https://github.com/yoshinorim/mha4mysql-manager/wiki/Downloads
https://github.com/yoshinorim/mha4mysql-node/releases/tag/v0.58
以下技术可以达到金融级的高可用性要求
Galera Cluster:wsrep(MySQL extended with the Write Set Replication)
通过wsrep协议在全局实现复制;任何一节点都可读写,不需要主从复制,实现多主读写
GR(Group Replication):MySQL官方提供的组复制技术(MySQL 5.7.17引入的技术),基于原生
复制技术Paxos算法,实现了多主更新,复制组由多个server成员构成,组中的每个server可独立
地执行事务,但所有读写事务只在冲突检测成功后才会提交
这3个节点互相通信,每当有事件发生,都会向其他节点传播该事件,然后协商,如果大多数节点
都同意这次的事件,那么该事件将通过,否则该事件将失败或回滚。这些节点可以是单主模型的
(single-primary),也可以是多主模型的(multi-primary)。单主模型只有一个主节点可以接受写操
作,主节点故障时可以自动选举主节点。多主模型下,所有节点都可以接受写操作,所以没有
master-slave的概念。
6.3.2 MHA Master High Availability
6.3.2.1 MHA 工作原理和架构
官方文档
https://github.com/yoshinorim/mha4mysql-manager/wiki
MHA集群架构
MHA工作原理
1. MHA利用 SELECT 1 As Value 指令判断master服务器的健康性,一旦master 宕机,MHA 从宕机崩溃
的master保存二进制日志事件(binlog events)
2. 识别含有最新更新的slave
3. 应用差异的中继日志(relay log)到其他的slave
4. 应用从master保存的二进制日志事件(binlog events)到所有slave节点
5. 提升一个slave为新的master
6. 使其他的slave连接新的master进行复制
7. 故障服务器自动被剔除集群(masterha_conf_host),将配置信息去掉
8. MHA是一次性的高可用性解决方案,Manager会自动退出
选举新的Master
如果设定权重(candidate_master=1),按照权重强制指定新主,但是默认情况下如果一个slave落后
master 二进制日志超过100M的relay logs,即使有权重,也会失效.如果设置check_repl_delay=0,
即使落后很多日志,也强制选择其为新主
如果从库数据之间有差异,最接近于Master的slave成为新主
如果所有从库数据都一致,按照配置文件顺序最前面的当新主
数据恢复
当主服务器的SSH还能连接,从库对比主库position 或者GTID号,将二进制日志保存至各个从节点并
且应用(执行save_binary_logs 实现)
当主服务器的SSH不能连接, 对比从库之间的relaylog的差异(执行apply_diff_relay_logs[实现])
注意:
为了尽可能的减少主库硬件损坏宕机造成的数据丢失,因此在配置MHA的同时建议配置成MySQL的半同
步复制
MHA软件
MHA软件由两部分组成,Manager工具包和Node工具包
Manager工具包主要包括以下几个工具:
masterha_check_ssh
masterha_check_repl
masterha_manger
检查MHA的SSH配置状况
检查MySQL复制状况
启动MHA
masterha_check_status
masterha_master_monitor
masterha_master_switch
masterha_conf_host
检测当前MHA运行状态
检测master是否宕机
故障转移(自动或手动)
添加或删除配置的server信息
masterha_stop --conf=app1.cnf 停止MHA
masterha_secondary_check
两个或多个网络线路检查MySQL主服务器的可用
**Node工具包:**这些工具通常由MHA Manager的脚本触发,无需人为操作)主要包括以下几个工具:
save_binary_logs
#保存和复制master的二进制日志
apply_diff_relay_logs
filter_mysqlbinlog
purge_relay_logs
#识别差异的中继日志事件并将其差异的事件应用于其他的slave
#去除不必要的ROLLBACK事件(MHA已不再使用此工具)
#清除中继日志(不会阻塞SQL线程)
MHA自定义扩展:
secondary_check_script
master_ip_ailover_script
shutdown_script
#通过多条网络路由检测master的可用性
#更新Application使用的masterip
#强制关闭master节点
report_script
#发送报告
init_conf_load_script
#加载初始配置参数
master_ip_online_change_script #更新master节点ip地址
MHA配置文件:
global配置,为各application提供默认配置,默认文件路径 /etc/masterha_default.cnf
application配置:为每个主从复制集群
6.3.2.2 实现 MHA 实战案例
环境:四台主机
10.0.0.7 CentOS7 MHA管理端
10.0.0.8 CentOS8 MySQL8.0 Master
10.0.0.18 CentOS8 MySQL8.0 Slave1
10.0.0.28 CentOS8 MySQL8.0 Slave2
6.3.2.2.1 在管理节点上安装两个包mha4mysql-manager和mha4mysql-node
说明:
mha4mysql-manager-0.56-0.el6.noarch.rpm 不支持CentOS 8,只支持CentOS7 以下版本
mha4mysql-manager-0.58-0.el7.centos.noarch.rpm 支持MySQL5.7和MySQL8.0 ,但和CentOS8
版本上的Mariadb -10.3.17不兼容
两个安装包
mha4mysql-manager
mha4mysql-node
#下载
https://github.com/yoshinorim/mha4mysql-manager/wiki/Downloads
https://github.com/yoshinorim/mha4mysql-node/releases/tag/v0.58
https://github.com/yoshinorim/mha4mysql-node/releases/tag/v0.58
范例:
[root@mha-manager ~]#yum -y install mha4mysql-manager-0.58-
0.el7.centos.noarch.rpm
[root@mha-manager ~]#yum -y install mha4mysql-node-0.58-0.el7.centos.noarch.rpm
6.3.2.2.2 在所有MySQL服务器上安装mha4mysql-node包
此包支持CentOS 8,7,6
mha4mysql-node
范例:
[root@master ~]#yum -y install mha4mysql-node-0.58-0.el7.centos.noarch.rpm
6.3.2.2.3 在所有节点实现相互之间ssh key验证
[root@mha-manager ~]#ssh-keygen
[root@mha-manager ~]#ssh-copy-id 127.0.0.1
[root@mha-manager ~]#rsync -av .ssh 10.0.0.8:/root/
[root@mha-manager ~]#rsync -av .ssh 10.0.0.18:/root/
[root@mha-manager ~]#rsync -av .ssh 10.0.0.28:/root/
6.3.2.2.4 在管理节点建立配置文件
注意: 此文件的行尾不要加空格等符号
[root@mha-manager ~]#mkdir /etc/mastermha/
[root@mha-manager ~]#vim /etc/mastermha/app1.cnf
[server default]
user=mhauser
#用于远程连接MySQL所有节点的用户,需要有管理员的权限
password=magedu
manager_workdir=/data/mastermha/app1/
manager_log=/data/mastermha/app1/manager.log
remote_workdir=/data/mastermha/app1/
#目录会自动生成,无需手动创建
ssh_user=root
#用于实现远程ssh基于KEY的连接,访问二进制日志
repl_user=repluser #主从复制的用户信息
repl_password=magedu
ping_interval=1
#健康性检查的时间间隔
master_ip_failover_script=/usr/local/bin/master_ip_failover #切换VIP的perl脚本,不
支持跨网络,也可用Keepalived实现
report_script=/usr/local/bin/sendmail.sh
#当执行报警脚本
check_repl_delay=0 #默认值为1,表示如果slave中从库落后主库relay log超过100M,主库不会选
择这个从库为新的master,因为这个从库进行恢复需要很长的时间.通过设置参数check_repl_delay=0,
mha触发主从切换时会忽略复制的延时,对于设置candidate_master=1的从库非常有用,这样确保这个从库
一定能成为最新的master
master_binlog_dir=/data/mysql/ #指定二进制日志存放的目录,mha4mysql-manager-0.58必须指
定,之前版本不需要指定
[server1]
hostname=10.0.0.8
port=3306
candidate_master=1
[server2]
hostname=10.0.0.18
port=3306
candidate_master=1 #设置为优先候选master,即使不是集群中事件最新的slave,也会优先当
master
[server3]
hostname=10.0.0.28
port=3306
#最终文件内容
[root@mha-manager ~]#cat /etc/mastermha/app1.cnf
[server default]
user=mhauser
password=magedu
manager_workdir=/data/mastermha/app1/
manager_log=/data/mastermha/app1/manager.log
remote_workdir=/data/mastermha/app1/
ssh_user=root
repl_user=repluser
repl_password=magedu
ping_interval=1
master_ip_failover_script=/usr/local/bin/master_ip_failover
report_script=/usr/local/bin/sendmail.sh
check_repl_delay=0
master_binlog_dir=/data/mysql/
[server1]
hostname=10.0.0.8
candidate_master=1
[server2]
hostname=10.0.0.18
candidate_master=1
[server3]
hostname=10.0.0.28
说明: 主库宕机谁来接管新的master
1. 所有从节点日志都是一致的,默认会以配置文件的顺序去选择一个新主
2. 从节点日志不一致,自动选择最接近于主库的从库充当新主
3. 如果对于某节点设定了权重(candidate_master=1),权重节点会优先选择。但是此节点日志量落后主
库超过100M日志的话,也不会被选择。可以配合check_repl_delay=0,关闭日志量的检查,强制选择候选
节点
6.3.2.2.5 相关脚本
[root@mha-manager ~]#cat /usr/local/bin/sendmail.sh
#!/bin/bash
echo "MHA is failover!" | mail -s "MHA Warning" root@wangxiaochun.com
[root@mha-manager ~]#chmod +x /usr/local/bin/sendmail.sh
[root@mha-manager ~]#vim /usr/local/bin/master_ip_failover
#!/usr/bin/env perl
#
#
#
#
#
#
#
#
#
#
#
Copyright (C) 2011 DeNA Co.,Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
## Note: This is a sample script and is not complete. Modify the script based on
your environment.
use strict;
use warnings FATAL => 'all';
use Getopt::Long;
use MHA::DBHelper;
my (
$command,
$ssh_user,
$orig_master_host,
$orig_master_ip, $orig_master_port, $new_master_host,
$new_master_ip, $new_master_port, $new_master_user,
$new_master_password
);
#执行时必须删除下面三行注释
my $vip = '10.0.0.100/24'; #设置Virtual IP
my $key = "1";
#指定VIP所在网卡的别名
my $ssh_start_vip = "/sbin/ifconfig eth0:$key $vip"; #指定VIP所在网卡
my $ssh_stop_vip = "/sbin/ifconfig eth0:$key down";
GetOptions(
'command=s'
=> \command,
'ssh_user=s'
=> \ssh_user,
'orig_master_host=s'
'orig_master_ip=s'
'orig_master_port=i'
'new_master_host=s'
'new_master_ip=s'
'new_master_port=i'
'new_master_user=s'
=> \orig_master_host,
=> \orig_master_ip,
=> \orig_master_port,
=> \new_master_host,
=> \new_master_ip,
=> \new_master_port,
=> \new_master_user,
'new_master_password=s' => \new_master_password,
);
exit &main();
sub main {
if ( $command eq "stop" || $command eq "stopssh" ) {
# $orig_master_host, $orig_master_ip, $orig_master_port are passed.
# If you manage master ip address at global catalog database,
# invalidate orig_master_ip here.
my $exit_code = 1;
eval {
# updating global catalog, etc
$exit_code = 0;
};
if ($@) {
warn "Got Error: $@\n";
exit $exit_code;
}
exit $exit_code;
}
elsif ( $command eq "start" ) {
# all arguments are passed.
# If you manage master ip address at global catalog database,
# activate new_master_ip here.
# You can also grant write access (create user, set read_only=0, etc)
here.
\n";
my $exit_code = 10;
eval {
print "Enabling the VIP - $vip on the new master - $new_master_host
&start_vip();
&stop_vip();
$exit_code = 0;
};
if ($@) {
warn $@;
exit $exit_code;
}
exit $exit_code;
}
elsif ( $command eq "status" ) {
print "Checking the Status of the script.. OK \n";
`ssh $ssh_user\$orig_master_host \ $ssh_start_vip \`;
exit 0;
}
else {
&usage();
exit 1;
}
}
sub start_vip() {
`ssh $ssh_user\$new_master_host \ $ssh_start_vip \`;
}
# A simple system call that disable the VIP on the old_master
sub stop_vip() {
`ssh $ssh_user\$orig_master_host \ $ssh_stop_vip \`;
}
sub usage {
"Usage: master_ip_failover --command=start|stop|stopssh|status --
orig_master_host=host --orig_master_ip=ip --orig_master_port=port --
new_master_host=host --new_master_ip=ip --new_master_port=port\n";
}
[root@mha-manager ~]#chmod +x /usr/local/bin/master_ip_failover
6.3.2.2.6 实现Master
[root@master ~]#dnf -y install mysql-server
[root@master ~]#mkdir /data/mysql/
[root@master ~]#chown mysql.mysql /data/mysql/
[root@master ~]#vim /etc/my.cnf
[mysqld]
server_id=1
log-bin=/data/mysql/mysql-bin
skip_name_resolve=1
general_log
#观察结果,非必须项,生产无需启用
[root@master ~]#systemctl enable --now mysqld
[root@master ~]#mysql
mysql>show master logs;
#如果是MySQL8.0执行下面操操作
mysql> create user repluser@'10.0.0.%' identified by 'magedu';
mysql> grant replication slave on *.* to repluser@'10.0.0.%';
mysql> create user mhauser@'10.0.0.%' identified by 'magedu';
mysql> grant all on *.* to mhauser@'10.0.0.%';
#如果是MySQL8.0以前版本执行下面操操作
mysql>grant replication slave on *.* to repluser@'10.0.0.%' identified by
'magedu';
mysql>grant all on *.* to mhauser@'10.0.0.%' identified by 'magedu';
#配置VIP
[root@master ~]#ifconfig eth0:1 10.0.0.100/24
6.3.2.2.7 实现slave
[root@slave ~]#dnf -y install mysql-server
[root@slave ~]#mkdir /data/mysql
[root@slave ~]#chown mysql.mysql /data/mysql/
[root@slave ~]#vim /etc/my.cnf
[mysqld]
server_id=2
#不同节点此值各不相同
log-bin=/data/mysql/mysql-bin
read_only
relay_log_purge=0
skip_name_resolve=1
#禁止反向解析
general_log #方便观察的设置,生产无需启用
[root@slave ~]#systemctl enable --now mysqld
[root@slave ~]#mysql
mysql>CHANGE MASTER TO MASTER_HOST='10.0.0.8', MASTER_USER='repluser',
MASTER_PASSWORD='magedu', MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=156;
mysql>START SLAVE;
6.3.2.2.8 检查MHA的环境
#检查环境
[root@mha-manager ~]#masterha_check_ssh --conf=/etc/mastermha/app1.cnf
[root@mha-manager ~]#masterha_check_repl --conf=/etc/mastermha/app1.cnf
#查看状态
[root@mha-manager ~]#masterha_check_status --conf=/etc/mastermha/app1.cnf
范例:
[root@mha-manager ~]#masterha_check_ssh --conf=/etc/mastermha/app1.cnf
Wed Jun 17 09:59:41 2020 - [warning] Global configuration file
/etc/masterha_default.cnf not found. Skipping.
Wed Jun 17 09:59:41 2020 - [info] Reading application default configuration from
/etc/mastermha/app1.cnf..
Wed Jun 17 09:59:41 2020 - [info] Reading server configuration from
/etc/mastermha/app1.cnf..
Wed Jun 17 09:59:41 2020 - [info] Starting SSH connection tests..
Wed Jun 17 09:59:42 2020 - [debug]
Wed Jun 17 09:59:41 2020 - [debug] Connecting via SSH from
root@10.0.0.8(10.0.0.8:22) to root@10.0.0.18(10.0.0.18:22)..
Wed Jun 17 09:59:42 2020 - [debug] ok.
Wed Jun 17 09:59:42 2020 - [debug] Connecting via SSH from
root@10.0.0.8(10.0.0.8:22) to root@10.0.0.28(10.0.0.28:22)..
Wed Jun 17 09:59:42 2020 - [debug] ok.
Wed Jun 17 09:59:43 2020 - [debug]
Wed Jun 17 09:59:42 2020 - [debug] Connecting via SSH from
root@10.0.0.18(10.0.0.18:22) to root@10.0.0.8(10.0.0.8:22)..
Wed Jun 17 09:59:42 2020 - [debug] ok.
Wed Jun 17 09:59:42 2020 - [debug] Connecting via SSH from
root@10.0.0.18(10.0.0.18:22) to root@10.0.0.28(10.0.0.28:22)..
Wed Jun 17 09:59:43 2020 - [debug] ok.
Wed Jun 17 09:59:44 2020 - [debug]
Wed Jun 17 09:59:42 2020 - [debug] Connecting via SSH from
root@10.0.0.28(10.0.0.28:22) to root@10.0.0.8(10.0.0.8:22)..
Wed Jun 17 09:59:43 2020 - [debug] ok.
Wed Jun 17 09:59:43 2020 - [debug] Connecting via SSH from
root@10.0.0.28(10.0.0.28:22) to root@10.0.0.18(10.0.0.18:22)..
Wed Jun 17 09:59:43 2020 - [debug] ok.
Wed Jun 17 09:59:44 2020 - [info] All SSH connection tests passed successfully.
[root@mha-manager ~]#masterha_check_repl --conf=/etc/mastermha/app1.cnf
Wed Jun 17 10:00:56 2020 - [warning] Global configuration file
/etc/masterha_default.cnf not found. Skipping.
Wed Jun 17 10:00:56 2020 - [info] Reading application default configuration from
/etc/mastermha/app1.cnf..
Wed Jun 17 10:00:56 2020 - [info] Reading server configuration from
/etc/mastermha/app1.cnf..
Wed Jun 17 10:00:56 2020 - [info] MHA::MasterMonitor version 0.56.
Creating directory /data/mastermha/app1/.. done.
Wed Jun 17 10:00:58 2020 - [info] GTID failover mode = 0
Wed Jun 17 10:00:58 2020 - [info] Dead Servers:
Wed Jun 17 10:00:58 2020 - [info] Alive Servers:
Wed Jun 17 10:00:58 2020 - [info] 10.0.0.8(10.0.0.8:3306)
Wed Jun 17 10:00:58 2020 - [info] 10.0.0.18(10.0.0.18:3306)
Wed Jun 17 10:00:58 2020 - [info] 10.0.0.28(10.0.0.28:3306)
Wed Jun 17 10:00:58 2020 - [info] Alive Slaves:
Wed Jun 17 10:00:58 2020 - [info] 10.0.0.18(10.0.0.18:3306) Version=10.3.17-
MariaDB-log (oldest major version between slaves) log-bin:enabled
Wed Jun 17 10:00:58 2020 - [info]
Wed Jun 17 10:00:58 2020 - [info]
(candidate_master is set)
Replicating from 10.0.0.8(10.0.0.8:3306)
Primary candidate for the new Master
Wed Jun 17 10:00:58 2020 - [info] 10.0.0.28(10.0.0.28:3306) Version=10.3.17-
MariaDB-log (oldest major version between slaves) log-bin:enabled
Wed Jun 17 10:00:58 2020 - [info]
Replicating from 10.0.0.8(10.0.0.8:3306)
Wed Jun 17 10:00:58 2020 - [info] Current Alive Master: 10.0.0.8(10.0.0.8:3306)
Wed Jun 17 10:00:58 2020 - [info] Checking slave configurations..
Wed Jun 17 10:00:58 2020 - [info] Checking replication filtering settings..
Wed Jun 17 10:00:58 2020 - [info] binlog_do_db= , binlog_ignore_db=
Wed Jun 17 10:00:58 2020 - [info] Replication filtering check ok.
Wed Jun 17 10:00:58 2020 - [info] GTID (with auto-pos) is not supported
Wed Jun 17 10:00:58 2020 - [info] Starting SSH connection tests..
Wed Jun 17 10:01:00 2020 - [info] All SSH connection tests passed successfully.
Wed Jun 17 10:01:00 2020 - [info] Checking MHA Node version..
Wed Jun 17 10:01:01 2020 - [info] Version check ok.
Wed Jun 17 10:01:01 2020 - [info] Checking SSH publickey authentication settings
on the current master..
Wed Jun 17 10:01:01 2020 - [info] HealthCheck: SSH to 10.0.0.8 is reachable.
Wed Jun 17 10:01:01 2020 - [info] Master MHA Node version is 0.56.
Wed Jun 17 10:01:01 2020 - [info] Checking recovery script configurations on
10.0.0.8(10.0.0.8:3306)..
Wed Jun 17 10:01:01 2020 - [info] Executing command: save_binary_logs --
command=test --start_pos=4 --binlog_dir=/var/lib/mysql,/var/log/mysql --
output_file=/data/mastermha/app1//save_binary_logs_test --manager_version=0.56 -
-start_file=mariadb-bin.000002
Wed Jun 17 10:01:01 2020 - [info] Connecting to root@10.0.0.8(10.0.0.8:22)..
Creating /data/mastermha/app1 if not exists.. Creating directory
/data/mastermha/app1.. done.
ok.
Checking output directory is accessible or not..
ok.
Binlog found at /var/lib/mysql, up to mariadb-bin.000002
Wed Jun 17 10:01:02 2020 - [info] Binlog setting check done.
Wed Jun 17 10:01:02 2020 - [info] Checking SSH publickey authentication and
checking recovery script configurations on all alive slave servers..
Wed Jun 17 10:01:02 2020 - [info] Executing command : apply_diff_relay_logs --
command=test --slave_user='mhauser' --slave_host=10.0.0.18 --slave_ip=10.0.0.18
--slave_port=3306 --workdir=/data/mastermha/app1/ --target_version=10.3.17-
MariaDB-log --manager_version=0.56 --relay_log_info=/var/lib/mysql/relay-
log.info --relay_dir=/var/lib/mysql/ --slave_pass=xxx
Wed Jun 17 10:01:02 2020 - [info] Connecting to root@10.0.0.18(10.0.0.18:22)..
Creating directory /data/mastermha/app1/.. done.
Checking slave recovery environment settings..
Opening /var/lib/mysql/relay-log.info ... ok.
Relay log found at /var/lib/mysql, up to mariadb-relay-bin.000002
Temporary relay log file is /var/lib/mysql/mariadb-relay-bin.000002
Testing mysql connection and privileges.. done.
Testing mysqlbinlog output.. done.
Cleaning up test file(s).. done.
Wed Jun 17 10:01:02 2020 - [info] Executing command : apply_diff_relay_logs --
command=test --slave_user='mhauser' --slave_host=10.0.0.28 --slave_ip=10.0.0.28
--slave_port=3306 --workdir=/data/mastermha/app1/ --target_version=10.3.17-
MariaDB-log --manager_version=0.56 --relay_log_info=/var/lib/mysql/relay-
log.info --relay_dir=/var/lib/mysql/ --slave_pass=xxx
Wed Jun 17 10:01:02 2020 - [info] Connecting to root@10.0.0.28(10.0.0.28:22)..
Creating directory /data/mastermha/app1/.. done.
Checking slave recovery environment settings..
Opening /var/lib/mysql/relay-log.info ... ok.
Relay log found at /var/lib/mysql, up to mariadb-relay-bin.000002
Temporary relay log file is /var/lib/mysql/mariadb-relay-bin.000002
Testing mysql connection and privileges.. done.
Testing mysqlbinlog output.. done.
Cleaning up test file(s).. done.
Wed Jun 17 10:01:03 2020 - [info] Slaves settings check done.
Wed Jun 17 10:01:03 2020 - [info]
10.0.0.8(10.0.0.8:3306) (current master)
+--10.0.0.18(10.0.0.18:3306)
+--10.0.0.28(10.0.0.28:3306)
Wed Jun 17 10:01:03 2020 - [info] Checking replication health on 10.0.0.18..
Wed Jun 17 10:01:03 2020 - [info] ok.
Wed Jun 17 10:01:03 2020 - [info] Checking replication health on 10.0.0.28..
Wed Jun 17 10:01:03 2020 - [info] ok.
Wed Jun 17 10:01:03 2020 - [warning] master_ip_failover_script is not defined.
Wed Jun 17 10:01:03 2020 - [warning] shutdown_script is not defined.
Wed Jun 17 10:01:03 2020 - [info] Got exit code 0 (Not master dead).
MySQL Replication Health is OK.
[root@mha-manager ~]#masterha_check_status --conf=/etc/mastermha/app1.cnf
app1 is stopped(2:NOT_RUNNING).
6.3.2.2.9 启动MHA
#开启MHA,默认是前台运行,生产环境一般为后台执行
nohup masterha_manager --conf=/etc/mastermha/app1.cnf --remove_dead_master_conf
--ignore_last_failover &> /dev/null
#如果想停止后台执行的MHA,可以执行下面命令
[root@mha-master ~]#masterha_stop --conf=/etc/mastermha/app1.cnf
Stopped app1 successfully.
#查看状态
masterha_check_status --conf=/etc/mastermha/app1.cnf
范例:
[root@mha-manager ~]#masterha_manager --conf=/etc/mastermha/app1.cnf --
remove_dead_master_conf --ignore_last_failover
Wed Jun 17 10:02:58 2020 - [warning] Global configuration file
/etc/masterha_default.cnf not found. Skipping.
Wed Jun 17 10:02:58 2020 - [info] Reading application default configuration from
/etc/mastermha/app1.cnf..
Wed Jun 17 10:02:58 2020 - [info] Reading server configuration from
/etc/mastermha/app1.cnf..
#查看到健康性检查
[root@master ~]#tail -f /var/lib/mysql/centos8.log
200617 20:14:16
200617 20:14:17
200617 20:14:18
200617 20:14:19
200617 20:14:20
200617 20:14:21
28 Query
28 Query
28 Query
28 Query
28 Query
28 Query
SELECT 1 As Value
SELECT 1 As Value
SELECT 1 As Value
SELECT 1 As Value
SELECT 1 As Value
SELECT 1 As Value
[root@mha-manager ~]#masterha_check_status --conf=/etc/mastermha/app1.cnf
app1 (pid:25994) is running(0:PING_OK), master:10.0.0.8
6.3.2.2.10 排错日志
tail /data/mastermha/app1/manager.log
范例:
[root@mha-manager ~]#cat /data/mastermha/app1/manager.log
Wed Jun 17 10:02:58 2020 - [info] MHA::MasterMonitor version 0.56.
Wed Jun 17 10:03:00 2020 - [info] GTID failover mode = 0
Wed Jun 17 10:03:00 2020 - [info] Dead Servers:
Wed Jun 17 10:03:00 2020 - [info] Alive Servers:
Wed Jun 17 10:03:00 2020 - [info] 10.0.0.8(10.0.0.8:3306)
Wed Jun 17 10:03:00 2020 - [info] 10.0.0.18(10.0.0.18:3306)
Wed Jun 17 10:03:00 2020 - [info] 10.0.0.28(10.0.0.28:3306)
Wed Jun 17 10:03:00 2020 - [info] Alive Slaves:
Wed Jun 17 10:03:00 2020 - [info] 10.0.0.18(10.0.0.18:3306) Version=10.3.17-
MariaDB-log (oldest major version between slaves) log-bin:enabled
Wed Jun 17 10:03:00 2020 - [info]
Wed Jun 17 10:03:00 2020 - [info]
(candidate_master is set)
Replicating from 10.0.0.8(10.0.0.8:3306)
Primary candidate for the new Master
Wed Jun 17 10:03:00 2020 - [info] 10.0.0.28(10.0.0.28:3306) Version=10.3.17-
MariaDB-log (oldest major version between slaves) log-bin:enabled
Wed Jun 17 10:03:00 2020 - [info]
Replicating from 10.0.0.8(10.0.0.8:3306)
Wed Jun 17 10:03:00 2020 - [info] Current Alive Master: 10.0.0.8(10.0.0.8:3306)
Wed Jun 17 10:03:00 2020 - [info] Checking slave configurations..
Wed Jun 17 10:03:00 2020 - [info] Checking replication filtering settings..
Wed Jun 17 10:03:00 2020 - [info] binlog_do_db= , binlog_ignore_db=
Wed Jun 17 10:03:00 2020 - [info] Replication filtering check ok.
Wed Jun 17 10:03:00 2020 - [info] GTID (with auto-pos) is not supported
Wed Jun 17 10:03:00 2020 - [info] Starting SSH connection tests..
Wed Jun 17 10:03:02 2020 - [info] All SSH connection tests passed successfully.
Wed Jun 17 10:03:02 2020 - [info] Checking MHA Node version..
Wed Jun 17 10:03:03 2020 - [info] Version check ok.
Wed Jun 17 10:03:03 2020 - [info] Checking SSH publickey authentication settings
on the current master..
Wed Jun 17 10:03:03 2020 - [info] HealthCheck: SSH to 10.0.0.8 is reachable.
Wed Jun 17 10:03:03 2020 - [info] Master MHA Node version is 0.56.
Wed Jun 17 10:03:03 2020 - [info] Checking recovery script configurations on
10.0.0.8(10.0.0.8:3306)..
Wed Jun 17 10:03:03 2020 - [info] Executing command: save_binary_logs --
command=test --start_pos=4 --binlog_dir=/var/lib/mysql,/var/log/mysql --
output_file=/data/mastermha/app1//save_binary_logs_test --manager_version=0.56 -
-start_file=mariadb-bin.000002
Wed Jun 17 10:03:03 2020 - [info] Connecting to root@10.0.0.8(10.0.0.8:22)..
Creating /data/mastermha/app1 if not exists..
Checking output directory is accessible or not..
ok.
ok.
Binlog found at /var/lib/mysql, up to mariadb-bin.000002
Wed Jun 17 10:03:04 2020 - [info] Binlog setting check done.
Wed Jun 17 10:03:04 2020 - [info] Checking SSH publickey authentication and
checking recovery script configurations on all alive slave servers..
Wed Jun 17 10:03:04 2020 - [info] Executing command : apply_diff_relay_logs --
command=test --slave_user='mhauser' --slave_host=10.0.0.18 --slave_ip=10.0.0.18
--slave_port=3306 --workdir=/data/mastermha/app1/ --target_version=10.3.17-
MariaDB-log --manager_version=0.56 --relay_log_info=/var/lib/mysql/relay-
log.info --relay_dir=/var/lib/mysql/ --slave_pass=xxx
Wed Jun 17 10:03:04 2020 - [info] Connecting to root@10.0.0.18(10.0.0.18:22)..
Checking slave recovery environment settings..
Opening /var/lib/mysql/relay-log.info ... ok.
Relay log found at /var/lib/mysql, up to mariadb-relay-bin.000002
Temporary relay log file is /var/lib/mysql/mariadb-relay-bin.000002
Testing mysql connection and privileges.. done.
Testing mysqlbinlog output.. done.
Cleaning up test file(s).. done.
Wed Jun 17 10:03:05 2020 - [info] Executing command : apply_diff_relay_logs --
command=test --slave_user='mhauser' --slave_host=10.0.0.28 --slave_ip=10.0.0.28
--slave_port=3306 --workdir=/data/mastermha/app1/ --target_version=10.3.17-
MariaDB-log --manager_version=0.56 --relay_log_info=/var/lib/mysql/relay-
log.info --relay_dir=/var/lib/mysql/ --slave_pass=xxx
Wed Jun 17 10:03:05 2020 - [info] Connecting to root@10.0.0.28(10.0.0.28:22)..
Checking slave recovery environment settings..
Opening /var/lib/mysql/relay-log.info ... ok.
Relay log found at /var/lib/mysql, up to mariadb-relay-bin.000002
Temporary relay log file is /var/lib/mysql/mariadb-relay-bin.000002
Testing mysql connection and privileges.. done.
Testing mysqlbinlog output.. done.
Cleaning up test file(s).. done.
Wed Jun 17 10:03:05 2020 - [info] Slaves settings check done.
Wed Jun 17 10:03:05 2020 - [info]
10.0.0.8(10.0.0.8:3306) (current master)
+--10.0.0.18(10.0.0.18:3306)
+--10.0.0.28(10.0.0.28:3306)
Wed Jun 17 10:03:05 2020 - [warning] master_ip_failover_script is not defined.
Wed Jun 17 10:03:05 2020 - [warning] shutdown_script is not defined.
Wed Jun 17 10:03:05 2020 - [info] Set master ping interval 1 seconds.
Wed Jun 17 10:03:05 2020 - [warning] secondary_check_script is not defined. It
is highly recommended setting it to check master reachability from two or more
routes.
Wed Jun 17 10:03:05 2020 - [info] Starting ping health check on
10.0.0.8(10.0.0.8:3306)..
Wed Jun 17 10:03:05 2020 - [info] Ping(SELECT) succeeded, waiting until MySQL
doesn't respond..
6.3.2.2.11 模拟故障
#模拟故障
[root@master ~]#systemctl stop mysqld
#当 master down机后,mha管理程序自动退出
[root@mha-manager ~]#masterha_manager --conf=/etc/mastermha/app1.cnf
Wed Jun 17 10:02:58 2020 - [warning] Global configuration file
/etc/masterha_default.cnf not found. Skipping.
Wed Jun 17 10:02:58 2020 - [info] Reading application default configuration
from /etc/mastermha/app1.cnf..
Wed Jun 17 10:02:58 2020 - [info] Reading server configuration from
/etc/mastermha/app1.cnf..
Wed Jun 17 10:06:37 2020 - [warning] Global configuration file
/etc/masterha_default.cnf not found. Skipping.
Wed Jun 17 10:06:37 2020 - [info] Reading application default configuration
from /etc/mastermha/app1.cnf..
Wed Jun 17 10:06:37 2020 - [info] Reading server configuration from
/etc/mastermha/app1.cnf..
[root@mha-manager ~]#cat /data/mastermha/app1/manager.log
Wed Jun 17 10:02:58 2020 - [info] MHA::MasterMonitor version 0.56.
Wed Jun 17 10:03:00 2020 - [info] GTID failover mode = 0
Wed Jun 17 10:03:00 2020 - [info] Dead Servers:
Wed Jun 17 10:03:00 2020 - [info] Alive Servers:
Wed Jun 17 10:03:00 2020 - [info] 10.0.0.8(10.0.0.8:3306)
Wed Jun 17 10:03:00 2020 - [info] 10.0.0.18(10.0.0.18:3306)
Wed Jun 17 10:03:00 2020 - [info] 10.0.0.28(10.0.0.28:3306)
Wed Jun 17 10:03:00 2020 - [info] Alive Slaves:
Wed Jun 17 10:03:00 2020 - [info] 10.0.0.18(10.0.0.18:3306)
Version=10.3.17-MariaDB-log (oldest major version between slaves) log-
bin:enabled
Wed Jun 17 10:03:00 2020 - [info]
10.0.0.8(10.0.0.8:3306)
Replicating from
Wed Jun 17 10:03:00 2020 - [info]
(candidate_master is set)
Primary candidate for the new Master
Wed Jun 17 10:03:00 2020 - [info] 10.0.0.28(10.0.0.28:3306)
Version=10.3.17-MariaDB-log (oldest major version between slaves) log-
bin:enabled
Wed Jun 17 10:03:00 2020 - [info]
10.0.0.8(10.0.0.8:3306)
Replicating from
Wed Jun 17 10:03:00 2020 - [info] Current Alive Master:
10.0.0.8(10.0.0.8:3306)
Wed Jun 17 10:03:00 2020 - [info] Checking slave configurations..
Wed Jun 17 10:03:00 2020 - [info] Checking replication filtering settings..
Wed Jun 17 10:03:00 2020 - [info] binlog_do_db= , binlog_ignore_db=
Wed Jun 17 10:03:00 2020 - [info] Replication filtering check ok.
Wed Jun 17 10:03:00 2020 - [info] GTID (with auto-pos) is not supported
Wed Jun 17 10:03:00 2020 - [info] Starting SSH connection tests..
Wed Jun 17 10:03:02 2020 - [info] All SSH connection tests passed
successfully.
Wed Jun 17 10:03:02 2020 - [info] Checking MHA Node version..
Wed Jun 17 10:03:03 2020 - [info] Version check ok.
Wed Jun 17 10:03:03 2020 - [info] Checking SSH publickey authentication
settings on the current master..
Wed Jun 17 10:03:03 2020 - [info] HealthCheck: SSH to 10.0.0.8 is reachable.
Wed Jun 17 10:03:03 2020 - [info] Master MHA Node version is 0.56.
Wed Jun 17 10:03:03 2020 - [info] Checking recovery script configurations on
10.0.0.8(10.0.0.8:3306)..
Wed Jun 17 10:03:03 2020 - [info] Executing command: save_binary_logs --
command=test --start_pos=4 --binlog_dir=/var/lib/mysql,/var/log/mysql --
output_file=/data/mastermha/app1//save_binary_logs_test --manager_version=0.56 -
-start_file=mariadb-bin.000002
Wed Jun 17 10:03:03 2020 - [info] Connecting to
root@10.0.0.8(10.0.0.8:22)..
Creating /data/mastermha/app1 if not exists..
Checking output directory is accessible or not..
ok.
ok.
Binlog found at /var/lib/mysql, up to mariadb-bin.000002
Wed Jun 17 10:03:04 2020 - [info] Binlog setting check done.
Wed Jun 17 10:03:04 2020 - [info] Checking SSH publickey authentication and
checking recovery script configurations on all alive slave servers..
Wed Jun 17 10:03:04 2020 - [info] Executing command :
apply_diff_relay_logs --command=test --slave_user='mhauser' --
slave_host=10.0.0.18 --slave_ip=10.0.0.18 --slave_port=3306 --
workdir=/data/mastermha/app1/ --target_version=10.3.17-MariaDB-log --
manager_version=0.56 --relay_log_info=/var/lib/mysql/relay-log.info --
relay_dir=/var/lib/mysql/ --slave_pass=xxx
Wed Jun 17 10:03:04 2020 - [info] Connecting to
root@10.0.0.18(10.0.0.18:22)..
Checking slave recovery environment settings..
Opening /var/lib/mysql/relay-log.info ... ok.
Relay log found at /var/lib/mysql, up to mariadb-relay-bin.000002
Temporary relay log file is /var/lib/mysql/mariadb-relay-bin.000002
Testing mysql connection and privileges.. done.
Testing mysqlbinlog output.. done.
Cleaning up test file(s).. done.
Wed Jun 17 10:03:05 2020 - [info] Executing command :
apply_diff_relay_logs --command=test --slave_user='mhauser' --
slave_host=10.0.0.28 --slave_ip=10.0.0.28 --slave_port=3306 --
workdir=/data/mastermha/app1/ --target_version=10.3.17-MariaDB-log --
manager_version=0.56 --relay_log_info=/var/lib/mysql/relay-log.info --
relay_dir=/var/lib/mysql/ --slave_pass=xxx
Wed Jun 17 10:03:05 2020 - [info] Connecting to
root@10.0.0.28(10.0.0.28:22)..
Checking slave recovery environment settings..
Opening /var/lib/mysql/relay-log.info ... ok.
Relay log found at /var/lib/mysql, up to mariadb-relay-bin.000002
Temporary relay log file is /var/lib/mysql/mariadb-relay-bin.000002
Testing mysql connection and privileges.. done.
Testing mysqlbinlog output.. done.
Cleaning up test file(s).. done.
Wed Jun 17 10:03:05 2020 - [info] Slaves settings check done.
Wed Jun 17 10:03:05 2020 - [info]
10.0.0.8(10.0.0.8:3306) (current master)
+--10.0.0.18(10.0.0.18:3306)
+--10.0.0.28(10.0.0.28:3306)
Wed Jun 17 10:03:05 2020 - [warning] master_ip_failover_script is not
defined.
Wed Jun 17 10:03:05 2020 - [warning] shutdown_script is not defined.
Wed Jun 17 10:03:05 2020 - [info] Set master ping interval 1 seconds.
Wed Jun 17 10:03:05 2020 - [warning] secondary_check_script is not defined.
It is highly recommended setting it to check master reachability from two or more
routes.
Wed Jun 17 10:03:05 2020 - [info] Starting ping health check on
10.0.0.8(10.0.0.8:3306)..
Wed Jun 17 10:03:05 2020 - [info] Ping(SELECT) succeeded, waiting until
MySQL doesn't respond..
Wed Jun 17 10:06:31 2020 - [warning] Got timeout on MySQL Ping(SELECT) child
process and killed it! at /usr/share/perl5/vendor_perl/MHA/HealthCheck.pm line
431.
Wed Jun 17 10:06:31 2020 - [info] Executing SSH check script:
save_binary_logs --command=test --start_pos=4 --
binlog_dir=/var/lib/mysql,/var/log/mysql --
output_file=/data/mastermha/app1//save_binary_logs_test --manager_version=0.56 -
-binlog_prefix=mariadb-bin
Wed Jun 17 10:06:32 2020 - [warning] Got error on MySQL connect: 2003 (Can't
connect to MySQL server on '10.0.0.8' (4))
Wed Jun 17 10:06:32 2020 - [warning] Connection failed 2 time(s)..
Wed Jun 17 10:06:33 2020 - [warning] Got error on MySQL connect: 2003 (Can't
connect to MySQL server on '10.0.0.8' (4))
Wed Jun 17 10:06:33 2020 - [warning] Connection failed 3 time(s)..
Wed Jun 17 10:06:34 2020 - [warning] Got error on MySQL connect: 2003 (Can't
connect to MySQL server on '10.0.0.8' (4))
Wed Jun 17 10:06:34 2020 - [warning] Connection failed 4 time(s)..
Wed Jun 17 10:06:36 2020 - [warning] HealthCheck: Got timeout on checking
SSH connection to 10.0.0.8! at /usr/share/perl5/vendor_perl/MHA/HealthCheck.pm
line 342.
Wed Jun 17 10:06:36 2020 - [warning] Master is not reachable from health
checker!
Wed Jun 17 10:06:36 2020 - [warning] Master 10.0.0.8(10.0.0.8:3306) is not
reachable!
Wed Jun 17 10:06:36 2020 - [warning] SSH is NOT reachable.
Wed Jun 17 10:06:36 2020 - [info] Connecting to a master server failed.
Reading configuration file /etc/masterha_default.cnf and /etc/mastermha/app1.cnf
again, and trying to connect to all servers to check server status..
Wed Jun 17 10:06:36 2020 - [warning] Global configuration file
/etc/masterha_default.cnf not found. Skipping.
Wed Jun 17 10:06:36 2020 - [info] Reading application default configuration
from /etc/mastermha/app1.cnf..
Wed Jun 17 10:06:36 2020 - [info] Reading server configuration from
/etc/mastermha/app1.cnf..
Wed Jun 17 10:06:37 2020 - [info] GTID failover mode = 0
Wed Jun 17 10:06:37 2020 - [info] Dead Servers:
Wed Jun 17 10:06:37 2020 - [info]
10.0.0.8(10.0.0.8:3306)
Wed Jun 17 10:06:37 2020 - [info] Alive Servers:
Wed Jun 17 10:06:37 2020 - [info]
Wed Jun 17 10:06:37 2020 - [info]
10.0.0.18(10.0.0.18:3306)
10.0.0.28(10.0.0.28:3306)
Wed Jun 17 10:06:37 2020 - [info] Alive Slaves:
Wed Jun 17 10:06:37 2020 - [info]
Version=10.3.17-MariaDB-log (oldest major version between slaves) log-
bin:enabled
10.0.0.18(10.0.0.18:3306)
Wed Jun 17 10:06:37 2020 - [info]
10.0.0.8(10.0.0.8:3306)
Replicating from
Wed Jun 17 10:06:37 2020 - [info]
(candidate_master is set)
Primary candidate for the new Master
10.0.0.28(10.0.0.28:3306)
Wed Jun 17 10:06:37 2020 - [info]
Version=10.3.17-MariaDB-log (oldest major version between slaves) log-
bin:enabled
Wed Jun 17 10:06:37 2020 - [info]
10.0.0.8(10.0.0.8:3306)
Replicating from
Wed Jun 17 10:06:37 2020 - [info] Checking slave configurations..
Wed Jun 17 10:06:37 2020 - [info] Checking replication filtering settings..
Wed Jun 17 10:06:37 2020 - [info] Replication filtering check ok.
Wed Jun 17 10:06:37 2020 - [info] Master is down!
Wed Jun 17 10:06:37 2020 - [info] Terminating monitoring script.
Wed Jun 17 10:06:37 2020 - [info] Got exit code 20 (Master dead).
Wed Jun 17 10:06:37 2020 - [info] MHA::MasterFailover version 0.56.
Wed Jun 17 10:06:37 2020 - [info] Starting master failover.
Wed Jun 17 10:06:37 2020 - [info]
Wed Jun 17 10:06:37 2020 - [info] * Phase 1: Configuration Check Phase..
Wed Jun 17 10:06:37 2020 - [info]
Wed Jun 17 10:06:38 2020 - [info] GTID failover mode = 0
Wed Jun 17 10:06:38 2020 - [info] Dead Servers:
Wed Jun 17 10:06:38 2020 - [info]
10.0.0.8(10.0.0.8:3306)
Wed Jun 17 10:06:38 2020 - [info] Checking master reachability via
MySQL(double check)...
Wed Jun 17 10:06:39 2020 - [info] ok.
Wed Jun 17 10:06:39 2020 - [info] Alive Servers:
Wed Jun 17 10:06:39 2020 - [info]
Wed Jun 17 10:06:39 2020 - [info]
10.0.0.18(10.0.0.18:3306)
10.0.0.28(10.0.0.28:3306)
Wed Jun 17 10:06:39 2020 - [info] Alive Slaves:
Wed Jun 17 10:06:39 2020 - [info]
Version=10.3.17-MariaDB-log (oldest major version between slaves) log-
bin:enabled
10.0.0.18(10.0.0.18:3306)
Wed Jun 17 10:06:39 2020 - [info]
10.0.0.8(10.0.0.8:3306)
Replicating from
Wed Jun 17 10:06:39 2020 - [info]
(candidate_master is set)
Primary candidate for the new Master
Wed Jun 17 10:06:39 2020 - [info]
10.0.0.28(10.0.0.28:3306)
Version=10.3.17-MariaDB-log (oldest major version between slaves) log-
bin:enabled
Wed Jun 17 10:06:39 2020 - [info]
10.0.0.8(10.0.0.8:3306)
Replicating from
Wed Jun 17 10:06:39 2020 - [info] Starting Non-GTID based failover.
Wed Jun 17 10:06:39 2020 - [info]
Wed Jun 17 10:06:39 2020 - [info] ** Phase 1: Configuration Check Phase
completed.
Wed Jun 17 10:06:39 2020 - [info]
Wed Jun 17 10:06:39 2020 - [info] * Phase 2: Dead Master Shutdown Phase..
Wed Jun 17 10:06:39 2020 - [info]
Wed Jun 17 10:06:39 2020 - [info] Forcing shutdown so that applications
never connect to the current master..
Wed Jun 17 10:06:39 2020 - [warning] master_ip_failover_script is not set.
Skipping invalidating dead master IP address.
Wed Jun 17 10:06:39 2020 - [warning] shutdown_script is not set. Skipping
explicit shutting down of the dead master.
Wed Jun 17 10:06:40 2020 - [info] * Phase 2: Dead Master Shutdown Phase
completed.
Wed Jun 17 10:06:40 2020 - [info]
Wed Jun 17 10:06:40 2020 - [info] * Phase 3: Master Recovery Phase..
Wed Jun 17 10:06:40 2020 - [info]
Wed Jun 17 10:06:40 2020 - [info] * Phase 3.1: Getting Latest Slaves Phase..
Wed Jun 17 10:06:40 2020 - [info]
Wed Jun 17 10:06:40 2020 - [info] The latest binary log file/position on all
slaves is mariadb-bin.000002:3062073
Wed Jun 17 10:06:40 2020 - [info] Latest slaves (Slaves that received relay
log files to the latest):
Wed Jun 17 10:06:40 2020 - [info] 10.0.0.18(10.0.0.18:3306)
Version=10.3.17-MariaDB-log (oldest major version between slaves) log-
bin:enabled
Wed Jun 17 10:06:40 2020 - [info]
10.0.0.8(10.0.0.8:3306)
Replicating from
Wed Jun 17 10:06:40 2020 - [info]
(candidate_master is set)
Primary candidate for the new Master
Wed Jun 17 10:06:40 2020 - [info] 10.0.0.28(10.0.0.28:3306)
Version=10.3.17-MariaDB-log (oldest major version between slaves) log-
bin:enabled
Wed Jun 17 10:06:40 2020 - [info]
10.0.0.8(10.0.0.8:3306)
Replicating from
Wed Jun 17 10:06:40 2020 - [info] The oldest binary log file/position on all
slaves is mariadb-bin.000002:3062073
Wed Jun 17 10:06:40 2020 - [info] Oldest slaves:
Wed Jun 17 10:06:40 2020 - [info] 10.0.0.18(10.0.0.18:3306)
Version=10.3.17-MariaDB-log (oldest major version between slaves) log-
bin:enabled
Wed Jun 17 10:06:40 2020 - [info]
10.0.0.8(10.0.0.8:3306)
Replicating from
Wed Jun 17 10:06:40 2020 - [info]
(candidate_master is set)
Primary candidate for the new Master
Wed Jun 17 10:06:40 2020 - [info] 10.0.0.28(10.0.0.28:3306)
Version=10.3.17-MariaDB-log (oldest major version between slaves) log-
bin:enabled
Wed Jun 17 10:06:40 2020 - [info]
10.0.0.8(10.0.0.8:3306)
Replicating from
Wed Jun 17 10:06:40 2020 - [info]
Wed Jun 17 10:06:40 2020 - [info] * Phase 3.2: Saving Dead Master's Binlog
Phase..
Wed Jun 17 10:06:40 2020 - [info]
Wed Jun 17 10:06:40 2020 - [warning] Dead Master is not SSH reachable. Could
not save it's binlogs. Transactions that were not sent to the latest slave
(Read_Master_Log_Pos to the tail of the dead master's binlog) were lost.
Wed Jun 17 10:06:40 2020 - [info]
Wed Jun 17 10:06:40 2020 - [info] * Phase 3.3: Determining New Master
Phase..
Wed Jun 17 10:06:40 2020 - [info]
Wed Jun 17 10:06:40 2020 - [info] Finding the latest slave that has all
relay logs for recovering other slaves..
Wed Jun 17 10:06:40 2020 - [info] All slaves received relay logs to the same
position. No need to resync each other.
Wed Jun 17 10:06:40 2020 - [info] Searching new master from slaves..
Wed Jun 17 10:06:40 2020 - [info] Candidate masters from the configuration
file:
Wed Jun 17 10:06:40 2020 - [info] 10.0.0.18(10.0.0.18:3306)
Version=10.3.17-MariaDB-log (oldest major version between slaves) log-
bin:enabled
Wed Jun 17 10:06:40 2020 - [info]
10.0.0.8(10.0.0.8:3306)
Replicating from
Wed Jun 17 10:06:40 2020 - [info]
(candidate_master is set)
Primary candidate for the new Master
Wed Jun 17 10:06:40 2020 - [info] Non-candidate masters:
Wed Jun 17 10:06:40 2020 - [info] Searching from candidate_master slaves
which have received the latest relay log events..
Wed Jun 17 10:06:40 2020 - [info] New master is 10.0.0.18(10.0.0.18:3306)
Wed Jun 17 10:06:40 2020 - [info] Starting master failover..
Wed Jun 17 10:06:40 2020 - [info]
From:
10.0.0.8(10.0.0.8:3306) (current master)
+--10.0.0.18(10.0.0.18:3306)
+--10.0.0.28(10.0.0.28:3306)
To:
10.0.0.18(10.0.0.18:3306) (new master)
+--10.0.0.28(10.0.0.28:3306)
Wed Jun 17 10:06:40 2020 - [info]
Wed Jun 17 10:06:40 2020 - [info] * Phase 3.3: New Master Diff Log
Generation Phase..
Wed Jun 17 10:06:40 2020 - [info]
Wed Jun 17 10:06:40 2020 - [info] This server has all relay logs. No need
to generate diff files from the latest slave.
Wed Jun 17 10:06:40 2020 - [info]
Wed Jun 17 10:06:40 2020 - [info] * Phase 3.4: Master Log Apply Phase..
Wed Jun 17 10:06:40 2020 - [info]
Wed Jun 17 10:06:40 2020 - [info] *NOTICE: If any error happens from this
phase, manual recovery is needed.
Wed Jun 17 10:06:40 2020 - [info] Starting recovery on
10.0.0.18(10.0.0.18:3306)..
Wed Jun 17 10:06:40 2020 - [info] This server has all relay logs. Waiting
all logs to be applied..
Wed Jun 17 10:06:40 2020 - [info] done.
Wed Jun 17 10:06:40 2020 - [info] All relay logs were successfully applied.
Wed Jun 17 10:06:40 2020 - [info] Getting new master's binlog name and
position..
Wed Jun 17 10:06:40 2020 - [info] mariadb-bin.000002:344
Wed Jun 17 10:06:40 2020 - [info] All other slaves should start replication
from here. Statement should be: CHANGE MASTER TO MASTER_HOST='10.0.0.18',
MASTER_PORT=3306, MASTER_LOG_FILE='mariadb-bin.000002', MASTER_LOG_POS=344,
MASTER_USER='repluser', MASTER_PASSWORD='xxx';
Wed Jun 17 10:06:40 2020 - [warning] master_ip_failover_script is not set.
Skipping taking over new master IP address.
Wed Jun 17 10:06:40 2020 - [info] Setting read_only=0 on
10.0.0.18(10.0.0.18:3306)..
Wed Jun 17 10:06:40 2020 - [info] ok.
Wed Jun 17 10:06:40 2020 - [info] ** Finished master recovery successfully.
Wed Jun 17 10:06:40 2020 - [info] * Phase 3: Master Recovery Phase
completed.
Wed Jun 17 10:06:40 2020 - [info]
Wed Jun 17 10:06:40 2020 - [info] * Phase 4: Slaves Recovery Phase..
Wed Jun 17 10:06:40 2020 - [info]
Wed Jun 17 10:06:40 2020 - [info] * Phase 4.1: Starting Parallel Slave Diff
Log Generation Phase..
Wed Jun 17 10:06:40 2020 - [info]
Wed Jun 17 10:06:40 2020 - [info] -- Slave diff file generation on host
10.0.0.28(10.0.0.28:3306) started, pid: 24706. Check tmp log
/data/mastermha/app1//10.0.0.28_3306_20200617100637.log if it takes time..
Wed Jun 17 10:06:41 2020 - [info]
Wed Jun 17 10:06:41 2020 - [info] Log messages from 10.0.0.28 ...
Wed Jun 17 10:06:41 2020 - [info]
Wed Jun 17 10:06:40 2020 - [info] This server has all relay logs. No need
to generate diff files from the latest slave.
Wed Jun 17 10:06:41 2020 - [info] End of log messages from 10.0.0.28.
Wed Jun 17 10:06:41 2020 - [info] -- 10.0.0.28(10.0.0.28:3306) has the
latest relay log events.
Wed Jun 17 10:06:41 2020 - [info] Generating relay diff files from the
latest slave succeeded.
Wed Jun 17 10:06:41 2020 - [info]
Wed Jun 17 10:06:41 2020 - [info] * Phase 4.2: Starting Parallel Slave Log
Apply Phase..
Wed Jun 17 10:06:41 2020 - [info]
Wed Jun 17 10:06:41 2020 - [info] -- Slave recovery on host
10.0.0.28(10.0.0.28:3306) started, pid: 24708. Check tmp log
/data/mastermha/app1//10.0.0.28_3306_20200617100637.log if it takes time..
Wed Jun 17 10:06:42 2020 - [info]
Wed Jun 17 10:06:42 2020 - [info] Log messages from 10.0.0.28 ...
Wed Jun 17 10:06:42 2020 - [info]
Wed Jun 17 10:06:41 2020 - [info] Starting recovery on
10.0.0.28(10.0.0.28:3306)..
Wed Jun 17 10:06:41 2020 - [info] This server has all relay logs. Waiting
all logs to be applied..
Wed Jun 17 10:06:41 2020 - [info]
done.
Wed Jun 17 10:06:41 2020 - [info] All relay logs were successfully applied.
Wed Jun 17 10:06:41 2020 - [info] Resetting slave 10.0.0.28(10.0.0.28:3306)
and starting replication from the new master 10.0.0.18(10.0.0.18:3306)..
Wed Jun 17 10:06:41 2020 - [info] Executed CHANGE MASTER.
Wed Jun 17 10:06:42 2020 - [info] Slave started.
Wed Jun 17 10:06:42 2020 - [info] End of log messages from 10.0.0.28.
Wed Jun 17 10:06:42 2020 - [info] -- Slave recovery on host
10.0.0.28(10.0.0.28:3306) succeeded.
Wed Jun 17 10:06:42 2020 - [info] All new slave servers recovered
successfully.
Wed Jun 17 10:06:42 2020 - [info]
Wed Jun 17 10:06:42 2020 - [info] * Phase 5: New master cleanup phase..
Wed Jun 17 10:06:42 2020 - [info]
Wed Jun 17 10:06:42 2020 - [info] Resetting slave info on the new master..
Wed Jun 17 10:06:42 2020 - [info] 10.0.0.18: Resetting slave info
succeeded.
Wed Jun 17 10:06:42 2020 - [info] Master failover to
10.0.0.18(10.0.0.18:3306) completed successfully.
Wed Jun 17 10:06:42 2020 - [info]
----- Failover Report -----
app1: MySQL Master failover 10.0.0.8(10.0.0.8:3306) to
10.0.0.18(10.0.0.18:3306) succeeded
Master 10.0.0.8(10.0.0.8:3306) is down!
Check MHA Manager logs at mha-manager:/data/mastermha/app1/manager.log for
details.
Started automated(non-interactive) failover.
The latest slave 10.0.0.18(10.0.0.18:3306) has all relay logs for recovery.
Selected 10.0.0.18(10.0.0.18:3306) as a new master.
10.0.0.18(10.0.0.18:3306): OK: Applying all logs succeeded.
10.0.0.28(10.0.0.28:3306): This host has the latest relay log events.
Generating relay diff files from the latest slave succeeded.
10.0.0.28(10.0.0.28:3306): OK: Applying all logs succeeded. Slave started,
replicating from 10.0.0.18(10.0.0.18:3306)
10.0.0.18(10.0.0.18:3306): Resetting slave info succeeded.
Master failover to 10.0.0.18(10.0.0.18:3306) completed successfully.
[root@mha-manager ~]#masterha_check_status --conf=/etc/mastermha/app1.cnf
app1 is stopped(2:NOT_RUNNING).
#验证VIP漂移至新的Master上
[root@slave1 ~]#ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group
default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP
group default qlen 1000
link/ether 00:0c:29:e1:0e:53 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.18/24 brd 10.0.0.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet 10.0.0.100/8 brd 10.255.255.255 scope global eth0:1
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fee1:e53/64 scope link
valid_lft forever preferred_lft forever
#自动修改manager节点上的配置文件,将master剔除
[root@mha-manager ~]#cat /etc/mastermha/app1.cnf
[server2]
hostname=10.0.0.18
port=3306
candidate_master=1
[server3]
hostname=10.0.0.28
port=3306
收到报警邮件
注意: 如果出错,需要删除下面文件再执行MHA
[root@mha-manager ~]#rm -f /data/mastermha/app1/app1.failover.error
6.3.2.2.12 修复主从
修复故障的主库,保证数据同步
修复主从,手工新故障库加入新的主,设为为从库
修复manager的配置文件
清理相关目录
检查ssh互信和replication的复制是否成功
检查VIP,如果有问题,重新配置VIP
重新运行MHA,查询MHA状态,确保运行正常
#####
6.3.2.2.13 如果再次运行MHA,需要先删除下面文件
MHA只能漂移一次,如果多次使用必须删除以下文件,要不MHA不可重用
[root@mha-manager ~]#rm -rf /data/mastermha/app1/
[root@mha-manager ~]#rm -rf /data/mastermha/app1/manager.log
日志文件
#mha_master自己的工作路径
#mha_master自己的
[root@master ~]#rm -rf /data/mastermha/app1/
#每个远程主机即三个节点的的工作目录
6.3.3 Galera Cluster
6.3.3.1 Galera Cluster 介绍
Galera Cluster:集成了Galera插件的MySQL集群,是一种新型的,数据不共享的,高度冗余的高可用
方案,目前Galera Cluster有两个版本,分别是Percona Xtradb Cluster及MariaDB Cluster,Galera本
身是具有多主特性的,即采用multi-master的集群架构,是一个既稳健,又在数据一致性、完整性及高
性能方面有出色表现的高可用解决方案
Galera Cluster特点
多主架构:真正的多点读写的集群,在任何时候读写数据,都是最新的
同步复制:改善了主从复制延迟问题,基本上达到了实时同步
并发复制:从节点APPLY数据时,支持并行执行,更好的性能
故障切换:在出现数据库故障时,因支持多点写入,切换容易
热插拔:在服务期间,如果数据库挂了,只要监控程序发现的够快,不可服务时间就会非常少。在
节点故障期间,节点本身对集群的影响非常小
自动节点克隆:在新增节点,或者停机维护时,增量数据或者基础数据不需要人工手动备份提供,
Galera Cluster会自动拉取在线节点数据,最终集群会变为一致
对应用透明:集群的维护,对应用程序是透明的
Galera Cluster 缺点
任何更新的事务都需要全局验证通过,才会在其他节点上执行,则集群性能由集群中最差性能节点
决定(一般集群节点配置都是一样的)
新节点加入或延后较大的节点重新加入需全量拷贝数据(SST,State Snapshot Transfer),作为
donor( 贡献者,如: 同步数据时的提供者)的节点在同步过程中无法提供读写
只支持innodb存储引擎的表
Galera Cluster工作过程
Galera Cluster官方文档:
http://galeracluster.com/documentation-webpages/galera-documentation.pdf
http://galeracluster.com/documentation-webpages/index.html
https://www.percona.com/doc/percona-xtradb-cluster/LATEST/index.html
https://mariadb.com/kb/en/library/getting-started-with-mariadb-galera-cluster/
Galera Cluster 包括两个组件
Galera replication library (galera-3)
WSREP:MySQL extended with the Write Set Replication
WSREP复制实现:
PXC:Percona XtraDB Cluster,是Percona对Galera的实现
参考仓库:
https://mirrors.tuna.tsinghua.edu.cn/percona/release/\$releasever/RPMS/\$basea
rch
MariaDB Galera Cluster:
参考仓库:
https://mirrors.tuna.tsinghua.edu.cn/mariadb/mariadb-5.5.X/yum/centos7-
amd64/
注意:两者都需要至少三个节点,不能安装mysql server 或 mariadb-server
6.3.3.2 PXC 原理
PXC最常使用如下4个端口号:
3306:数据库对外服务的端口号
4444:请求SST的端口号
4567:组成员之间进行沟通的端口号
4568:用于传输IST的端口号
PXC中涉及到的重要概念和核心参数:
(1)集群中节点的数量:整个集群中节点数量应该控制在最少3个、最多8个的范围内。最少3个节点是
为了防止出现脑裂现象,因为只有在2个节点下才会出现此现象。脑裂现象的标志就是输入任何命令,返
回的结果都是unknown command。节点在集群中,会因新节点的加入或故障、同步失效等原因发生状
态的切换。
(2)节点状态的变化阶段:
open:节点启动成功,尝试连接到集群时的状态
primary:节点已处于集群中,在新节点加入并选取donor进行数据同步时的状态
joiner:节点处于等待接收同步文件时的状态
joined:节点完成数据同步工作,尝试保持和集群进度一致时的状态
synced:节点正常提供服务时的状态,表示已经同步完成并和集群进度保持一致
donor:节点处于为新加入的节点提供全量数据时的状态
备注:donor节点就是数据的贡献者,如果一个新节点加入集群,此时又需要大量数据的SST数据传输,
就有可能因此而拖垮整个集群的性能,所以在生产环境中,如果数据量较小,还可以使用SST全量数据
传输,但如果数据量很大就不建议使用这种方式,可以考虑先建立主从关系,然后再加入集群。
(3)节点的数据传输方式:
SST:State Snapshot Transfer,全量数据传输
IST:Incremental State Transfer,增量数据传输
SST数据传输有xtrabackup、mysqldump和rsync三种方式,而增量数据传输就只有一种方式
xtrabackup,但生产环境中一般数据量较小时,可以使用SST全量数据传输,但也只使用xtrabackup方
法。
(4)GCache模块:在PXC中一个特别重要的模块,它的核心功能就是为每个节点缓存当前最新的写
集。如果有新节点加入进来,就可以把新数据的增量传递给新节点,而不需要再使用SST传输方式,这
样可以让节点更快地加入集群中,涉及如下参数:
gcache.size:缓存写集增量信息的大小,它的默认大小是128MB,通过wsrep_provider_options
参数设置,建议调整为2GB~4GB范围,足够的空间便于缓存更多的增量信息。
gcache.mem_size:GCache中内存缓存的大小,适度调大可以提高整个集群的性能
gcache.page_size:如果内存不够用(GCache不足),就直接将写集写入磁盘文件中
6.3.3.3 实战案例:Percona XtraDB Cluster(PXC 5.7)
1 环境准备
四台主机:
pxc1:10.0.0.7
pxc2:10.0.0.17
pxc3:10.0.0.27
pxc4:10.0.0.37
OS 版本目前不支持CentOS 8
[root@pxc1 ~]#cat /etc/redhat-release
CentOS Linux release 7.6.1810 (Core)
关闭防火墙和SELinux,保证时间同步
注意:如果已经安装MySQL,必须卸载
2 安装 Percona XtraDB Cluster 5.7
#此处使用清华大学yum源,官方源太慢了
[root@pxc1 ~]#vim /etc/yum.repos.d/pxc.repo
[percona]
name=percona_repo
baseurl =
https://mirrors.tuna.tsinghua.edu.cn/percona/release/\$releasever/RPMS/\$basearch
enabled = 1
gpgcheck = 0
[root@pxc1 ~]#scp /etc/yum.repos.d/pxc.repo 10.0.0.17:/etc/yum.repos.d
[root@pxc1 ~]#scp /etc/yum.repos.d/pxc.repo 10.0.0.27:/etc/yum.repos.d
#在三个节点都安装好PXC 5.7
[root@pxc1 ~]#yum install Percona-XtraDB-Cluster-57 -y
[root@pxc2 ~]#yum install Percona-XtraDB-Cluster-57 -y
[root@pxc3 ~]#yum install Percona-XtraDB-Cluster-57 -y
[root@pxc1 ~]#rpm -ql Percona-XtraDB-Cluster-server-57
/etc/logrotate.d/mysql
/etc/my.cnf
/etc/my.cnf.d
/etc/percona-xtradb-cluster.cnf
/etc/percona-xtradb-cluster.conf.d
/etc/percona-xtradb-cluster.conf.d/mysqld.cnf
/etc/percona-xtradb-cluster.conf.d/mysqld_safe.cnf
/etc/percona-xtradb-cluster.conf.d/wsrep.cnf
/etc/sysconfig/mysql.bootstrap
/etc/xinetd.d/mysqlchk
/usr/bin/clustercheck
/usr/bin/innochecksum
/usr/bin/lz4_decompress
/usr/bin/my_print_defaults
/usr/bin/myisam_ftdump
/usr/bin/myisamchk
/usr/bin/myisamlog
/usr/bin/myisampack
/usr/bin/mysql-systemd
/usr/bin/mysql_install_db
/usr/bin/mysql_plugin
/usr/bin/mysql_secure_installation
/usr/bin/mysql_ssl_rsa_setup
/usr/bin/mysql_tzinfo_to_sql
/usr/bin/mysql_upgrade
/usr/bin/mysqld_multi
/usr/bin/mysqld_safe
/usr/bin/mysqldumpslow
/usr/bin/mysqltest
/usr/bin/perror
/usr/bin/ps_mysqld_helper
/usr/bin/pyclustercheck
/usr/bin/replace
/usr/bin/resolve_stack_dump
/usr/bin/resolveip
/usr/bin/wsrep_sst_common
/usr/bin/wsrep_sst_mysqldump
/usr/bin/wsrep_sst_rsync
/usr/bin/wsrep_sst_rsync_wan
/usr/bin/wsrep_sst_xtrabackup-v2
/usr/bin/zlib_decompress
/usr/lib/systemd/system/mysql.service
/usr/lib/systemd/system/mysql@.service
/usr/lib64/galera3/libgalera_smm.so
/usr/lib64/libgalera_smm.so
/usr/lib64/mysql/mecab
/usr/lib64/mysql/mecab/dic
/usr/lib64/mysql/mecab/dic/ipadic
/usr/lib64/mysql/mecab/dic/ipadic/char.bin
/usr/lib64/mysql/mecab/dic/ipadic/dicrc
/usr/lib64/mysql/mecab/dic/ipadic/left-id.def
/usr/lib64/mysql/mecab/dic/ipadic/matrix.bin
/usr/lib64/mysql/mecab/dic/ipadic/pos-id.def
/usr/lib64/mysql/mecab/dic/ipadic/rewrite.def
/usr/lib64/mysql/mecab/dic/ipadic/right-id.def
/usr/lib64/mysql/mecab/dic/ipadic/sys.dic
/usr/lib64/mysql/mecab/dic/ipadic/unk.dic
/usr/lib64/mysql/mecab/etc
/usr/lib64/mysql/mecab/etc/mecabrc
/usr/lib64/mysql/plugin/adt_null.so
/usr/lib64/mysql/plugin/audit_log.so
/usr/lib64/mysql/plugin/auth.so
/usr/lib64/mysql/plugin/auth_pam.so
/usr/lib64/mysql/plugin/auth_pam_compat.so
/usr/lib64/mysql/plugin/auth_socket.so
/usr/lib64/mysql/plugin/auth_test_plugin.so
/usr/lib64/mysql/plugin/authentication_ldap_sasl_client.so
/usr/lib64/mysql/plugin/connection_control.so
/usr/lib64/mysql/plugin/daemon_example.ini
/usr/lib64/mysql/plugin/data_masking.ini
/usr/lib64/mysql/plugin/data_masking.so
/usr/lib64/mysql/plugin/debug/adt_null.so
/usr/lib64/mysql/plugin/debug/audit_log.so
/usr/lib64/mysql/plugin/debug/auth.so
/usr/lib64/mysql/plugin/debug/auth_pam.so
/usr/lib64/mysql/plugin/debug/auth_pam_compat.so
/usr/lib64/mysql/plugin/debug/auth_socket.so
/usr/lib64/mysql/plugin/debug/auth_test_plugin.so
/usr/lib64/mysql/plugin/debug/authentication_ldap_sasl_client.so
/usr/lib64/mysql/plugin/debug/connection_control.so
/usr/lib64/mysql/plugin/debug/data_masking.so
/usr/lib64/mysql/plugin/debug/dialog.so
/usr/lib64/mysql/plugin/debug/group_replication.so
/usr/lib64/mysql/plugin/debug/ha_example.so
/usr/lib64/mysql/plugin/debug/innodb_engine.so
/usr/lib64/mysql/plugin/debug/keyring_file.so
/usr/lib64/mysql/plugin/debug/keyring_udf.so
/usr/lib64/mysql/plugin/debug/keyring_vault.so
/usr/lib64/mysql/plugin/debug/libdaemon_example.so
/usr/lib64/mysql/plugin/debug/libfnv1a_udf.so
/usr/lib64/mysql/plugin/debug/libfnv_udf.so
/usr/lib64/mysql/plugin/debug/libmemcached.so
/usr/lib64/mysql/plugin/debug/libmurmur_udf.so
/usr/lib64/mysql/plugin/debug/libpluginmecab.so
/usr/lib64/mysql/plugin/debug/libtest_framework.so
/usr/lib64/mysql/plugin/debug/libtest_services.so
/usr/lib64/mysql/plugin/debug/libtest_services_threaded.so
/usr/lib64/mysql/plugin/debug/libtest_session_detach.so
/usr/lib64/mysql/plugin/debug/libtest_session_in_thd.so
/usr/lib64/mysql/plugin/debug/libtest_session_info.so
/usr/lib64/mysql/plugin/debug/libtest_sql_2_sessions.so
/usr/lib64/mysql/plugin/debug/libtest_sql_all_col_types.so
/usr/lib64/mysql/plugin/debug/libtest_sql_cmds_1.so
/usr/lib64/mysql/plugin/debug/libtest_sql_commit.so
/usr/lib64/mysql/plugin/debug/libtest_sql_complex.so
/usr/lib64/mysql/plugin/debug/libtest_sql_errors.so
/usr/lib64/mysql/plugin/debug/libtest_sql_lock.so
/usr/lib64/mysql/plugin/debug/libtest_sql_processlist.so
/usr/lib64/mysql/plugin/debug/libtest_sql_replication.so
/usr/lib64/mysql/plugin/debug/libtest_sql_shutdown.so
/usr/lib64/mysql/plugin/debug/libtest_sql_sqlmode.so
/usr/lib64/mysql/plugin/debug/libtest_sql_stored_procedures_functions.so
/usr/lib64/mysql/plugin/debug/libtest_sql_views_triggers.so
/usr/lib64/mysql/plugin/debug/libtest_x_sessions_deinit.so
/usr/lib64/mysql/plugin/debug/libtest_x_sessions_init.so
/usr/lib64/mysql/plugin/debug/locking_service.so
/usr/lib64/mysql/plugin/debug/mypluglib.so
/usr/lib64/mysql/plugin/debug/mysql_no_login.so
/usr/lib64/mysql/plugin/debug/mysqlx.so
/usr/lib64/mysql/plugin/debug/qa_auth_client.so
/usr/lib64/mysql/plugin/debug/qa_auth_interface.so
/usr/lib64/mysql/plugin/debug/qa_auth_server.so
/usr/lib64/mysql/plugin/debug/query_response_time.so
/usr/lib64/mysql/plugin/debug/replication_observers_example_plugin.so
/usr/lib64/mysql/plugin/debug/rewrite_example.so
/usr/lib64/mysql/plugin/debug/rewriter.so
/usr/lib64/mysql/plugin/debug/scalability_metrics.so
/usr/lib64/mysql/plugin/debug/semisync_master.so
/usr/lib64/mysql/plugin/debug/semisync_slave.so
/usr/lib64/mysql/plugin/debug/test_security_context.so
/usr/lib64/mysql/plugin/debug/test_udf_services.so
/usr/lib64/mysql/plugin/debug/udf_example.so
/usr/lib64/mysql/plugin/debug/validate_password.so
/usr/lib64/mysql/plugin/debug/version_token.so
/usr/lib64/mysql/plugin/dialog.so
/usr/lib64/mysql/plugin/group_replication.so
/usr/lib64/mysql/plugin/ha_example.so
/usr/lib64/mysql/plugin/innodb_engine.so
/usr/lib64/mysql/plugin/keyring_file.so
/usr/lib64/mysql/plugin/keyring_udf.so
/usr/lib64/mysql/plugin/keyring_vault.so
/usr/lib64/mysql/plugin/libdaemon_example.so
/usr/lib64/mysql/plugin/libfnv1a_udf.so
/usr/lib64/mysql/plugin/libfnv_udf.so
/usr/lib64/mysql/plugin/libmemcached.so
/usr/lib64/mysql/plugin/libmurmur_udf.so
/usr/lib64/mysql/plugin/libpluginmecab.so
/usr/lib64/mysql/plugin/libtest_framework.so
/usr/lib64/mysql/plugin/libtest_services.so
/usr/lib64/mysql/plugin/libtest_services_threaded.so
/usr/lib64/mysql/plugin/libtest_session_detach.so
/usr/lib64/mysql/plugin/libtest_session_in_thd.so
/usr/lib64/mysql/plugin/libtest_session_info.so
/usr/lib64/mysql/plugin/libtest_sql_2_sessions.so
/usr/lib64/mysql/plugin/libtest_sql_all_col_types.so
/usr/lib64/mysql/plugin/libtest_sql_cmds_1.so
/usr/lib64/mysql/plugin/libtest_sql_commit.so
/usr/lib64/mysql/plugin/libtest_sql_complex.so
/usr/lib64/mysql/plugin/libtest_sql_errors.so
/usr/lib64/mysql/plugin/libtest_sql_lock.so
/usr/lib64/mysql/plugin/libtest_sql_processlist.so
/usr/lib64/mysql/plugin/libtest_sql_replication.so
/usr/lib64/mysql/plugin/libtest_sql_shutdown.so
/usr/lib64/mysql/plugin/libtest_sql_sqlmode.so
/usr/lib64/mysql/plugin/libtest_sql_stored_procedures_functions.so
/usr/lib64/mysql/plugin/libtest_sql_views_triggers.so
/usr/lib64/mysql/plugin/libtest_x_sessions_deinit.so
/usr/lib64/mysql/plugin/libtest_x_sessions_init.so
/usr/lib64/mysql/plugin/locking_service.so
/usr/lib64/mysql/plugin/mypluglib.so
/usr/lib64/mysql/plugin/mysql_no_login.so
/usr/lib64/mysql/plugin/mysqlx.so
/usr/lib64/mysql/plugin/qa_auth_client.so
/usr/lib64/mysql/plugin/qa_auth_interface.so
/usr/lib64/mysql/plugin/qa_auth_server.so
/usr/lib64/mysql/plugin/query_response_time.so
/usr/lib64/mysql/plugin/replication_observers_example_plugin.so
/usr/lib64/mysql/plugin/rewrite_example.so
/usr/lib64/mysql/plugin/rewriter.so
/usr/lib64/mysql/plugin/scalability_metrics.so
/usr/lib64/mysql/plugin/semisync_master.so
/usr/lib64/mysql/plugin/semisync_slave.so
/usr/lib64/mysql/plugin/test_security_context.so
/usr/lib64/mysql/plugin/test_udf_services.so
/usr/lib64/mysql/plugin/udf_example.so
/usr/lib64/mysql/plugin/validate_password.so
/usr/lib64/mysql/plugin/version_token.so
/usr/sbin/mysqld
/usr/sbin/mysqld-debug
/usr/share/doc/Percona-XtraDB-Cluster-server-57-5.7.32
/usr/share/doc/Percona-XtraDB-Cluster-server-57-5.7.32/INFO_BIN
/usr/share/doc/Percona-XtraDB-Cluster-server-57-5.7.32/INFO_SRC
/usr/share/doc/Percona-XtraDB-Cluster-server-57-5.7.32/README
/usr/share/doc/Percona-XtraDB-Cluster-server-57-5.7.32/README-wsrep
/usr/share/doc/Percona-XtraDB-Cluster-server-57-5.7.32/wsrep.cnf
/usr/share/doc/percona-xtradb-cluster-galera
/usr/share/doc/percona-xtradb-cluster-galera/COPYING
/usr/share/doc/percona-xtradb-cluster-galera/LICENSE.asio
/usr/share/doc/percona-xtradb-cluster-galera/LICENSE.chromium
/usr/share/doc/percona-xtradb-cluster-galera/README
/usr/share/doc/percona-xtradb-cluster-galera/README-MySQL
/usr/share/man/man1/innochecksum.1.gz
/usr/share/man/man1/lz4_decompress.1.gz
/usr/share/man/man1/my_print_defaults.1.gz
/usr/share/man/man1/myisam_ftdump.1.gz
/usr/share/man/man1/myisamchk.1.gz
/usr/share/man/man1/myisamlog.1.gz
/usr/share/man/man1/myisampack.1.gz
/usr/share/man/man1/mysql.server.1.gz
/usr/share/man/man1/mysql_install_db.1.gz
/usr/share/man/man1/mysql_plugin.1.gz
/usr/share/man/man1/mysql_secure_installation.1.gz
/usr/share/man/man1/mysql_ssl_rsa_setup.1.gz
/usr/share/man/man1/mysql_tzinfo_to_sql.1.gz
/usr/share/man/man1/mysql_upgrade.1.gz
/usr/share/man/man1/mysqld_multi.1.gz
/usr/share/man/man1/mysqld_safe.1.gz
/usr/share/man/man1/mysqldumpslow.1.gz
/usr/share/man/man1/mysqlman.1.gz
/usr/share/man/man1/perror.1.gz
/usr/share/man/man1/replace.1.gz
/usr/share/man/man1/resolve_stack_dump.1.gz
/usr/share/man/man1/resolveip.1.gz
/usr/share/man/man1/zlib_decompress.1.gz
/usr/share/man/man8/mysqld.8.gz
/usr/share/percona-xtradb-cluster
/usr/share/percona-xtradb-cluster/bulgarian
/usr/share/percona-xtradb-cluster/bulgarian/errmsg.sys
/usr/share/percona-xtradb-cluster/charsets
/usr/share/percona-xtradb-cluster/charsets/Index.xml
/usr/share/percona-xtradb-cluster/charsets/README
/usr/share/percona-xtradb-cluster/charsets/armscii8.xml
/usr/share/percona-xtradb-cluster/charsets/ascii.xml
/usr/share/percona-xtradb-cluster/charsets/cp1250.xml
/usr/share/percona-xtradb-cluster/charsets/cp1251.xml
/usr/share/percona-xtradb-cluster/charsets/cp1256.xml
/usr/share/percona-xtradb-cluster/charsets/cp1257.xml
/usr/share/percona-xtradb-cluster/charsets/cp850.xml
/usr/share/percona-xtradb-cluster/charsets/cp852.xml
/usr/share/percona-xtradb-cluster/charsets/cp866.xml
/usr/share/percona-xtradb-cluster/charsets/dec8.xml
/usr/share/percona-xtradb-cluster/charsets/geostd8.xml
/usr/share/percona-xtradb-cluster/charsets/greek.xml
/usr/share/percona-xtradb-cluster/charsets/hebrew.xml
/usr/share/percona-xtradb-cluster/charsets/hp8.xml
/usr/share/percona-xtradb-cluster/charsets/keybcs2.xml
/usr/share/percona-xtradb-cluster/charsets/koi8r.xml
/usr/share/percona-xtradb-cluster/charsets/koi8u.xml
/usr/share/percona-xtradb-cluster/charsets/latin1.xml
/usr/share/percona-xtradb-cluster/charsets/latin2.xml
/usr/share/percona-xtradb-cluster/charsets/latin5.xml
/usr/share/percona-xtradb-cluster/charsets/latin7.xml
/usr/share/percona-xtradb-cluster/charsets/macce.xml
/usr/share/percona-xtradb-cluster/charsets/macroman.xml
/usr/share/percona-xtradb-cluster/charsets/swe7.xml
/usr/share/percona-xtradb-cluster/czech
/usr/share/percona-xtradb-cluster/czech/errmsg.sys
/usr/share/percona-xtradb-cluster/danish
/usr/share/percona-xtradb-cluster/danish/errmsg.sys
/usr/share/percona-xtradb-cluster/dictionary.txt
/usr/share/percona-xtradb-cluster/dutch
/usr/share/percona-xtradb-cluster/dutch/errmsg.sys
/usr/share/percona-xtradb-cluster/english
/usr/share/percona-xtradb-cluster/english/errmsg.sys
/usr/share/percona-xtradb-cluster/errmsg-utf8.txt
/usr/share/percona-xtradb-cluster/estonian
/usr/share/percona-xtradb-cluster/estonian/errmsg.sys
/usr/share/percona-xtradb-cluster/fill_help_tables.sql
/usr/share/percona-xtradb-cluster/french
/usr/share/percona-xtradb-cluster/french/errmsg.sys
/usr/share/percona-xtradb-cluster/german
/usr/share/percona-xtradb-cluster/german/errmsg.sys
/usr/share/percona-xtradb-cluster/greek
/usr/share/percona-xtradb-cluster/greek/errmsg.sys
/usr/share/percona-xtradb-cluster/hungarian
/usr/share/percona-xtradb-cluster/hungarian/errmsg.sys
/usr/share/percona-xtradb-cluster/innodb_memcached_config.sql
/usr/share/percona-xtradb-cluster/install_rewriter.sql
/usr/share/percona-xtradb-cluster/italian
/usr/share/percona-xtradb-cluster/italian/errmsg.sys
/usr/share/percona-xtradb-cluster/japanese
/usr/share/percona-xtradb-cluster/japanese/errmsg.sys
/usr/share/percona-xtradb-cluster/korean
/usr/share/percona-xtradb-cluster/korean/errmsg.sys
/usr/share/percona-xtradb-cluster/magic
/usr/share/percona-xtradb-cluster/mysql-log-rotate
/usr/share/percona-xtradb-cluster/mysql.server
/usr/share/percona-xtradb-cluster/mysql_security_commands.sql
/usr/share/percona-xtradb-cluster/mysql_sys_schema.sql
/usr/share/percona-xtradb-cluster/mysql_system_tables.sql
/usr/share/percona-xtradb-cluster/mysql_system_tables_data.sql
/usr/share/percona-xtradb-cluster/mysql_test_data_timezone.sql
/usr/share/percona-xtradb-cluster/mysqld_multi.server
/usr/share/percona-xtradb-cluster/norwegian
/usr/share/percona-xtradb-cluster/norwegian-ny
/usr/share/percona-xtradb-cluster/norwegian-ny/errmsg.sys
/usr/share/percona-xtradb-cluster/norwegian/errmsg.sys
/usr/share/percona-xtradb-cluster/polish
/usr/share/percona-xtradb-cluster/polish/errmsg.sys
/usr/share/percona-xtradb-cluster/portuguese
/usr/share/percona-xtradb-cluster/portuguese/errmsg.sys
/usr/share/percona-xtradb-cluster/pxc_cluster_view.sql
/usr/share/percona-xtradb-cluster/romanian
/usr/share/percona-xtradb-cluster/romanian/errmsg.sys
/usr/share/percona-xtradb-cluster/russian
/usr/share/percona-xtradb-cluster/russian/errmsg.sys
/usr/share/percona-xtradb-cluster/serbian
/usr/share/percona-xtradb-cluster/serbian/errmsg.sys
/usr/share/percona-xtradb-cluster/slovak
/usr/share/percona-xtradb-cluster/slovak/errmsg.sys
/usr/share/percona-xtradb-cluster/spanish
/usr/share/percona-xtradb-cluster/spanish/errmsg.sys
/usr/share/percona-xtradb-cluster/swedish
/usr/share/percona-xtradb-cluster/swedish/errmsg.sys
/usr/share/percona-xtradb-cluster/ukrainian
/usr/share/percona-xtradb-cluster/ukrainian/errmsg.sys
/usr/share/percona-xtradb-cluster/uninstall_rewriter.sql
/usr/share/percona-xtradb-cluster/wsrep_notify
/var/lib/galera
/var/lib/mysql
/var/lib/mysql-files
/var/lib/mysql-keyring
/var/run/mysqld
3 在各个节点上分别配置mysql及集群配置文件
/etc/my.cnf为主配置文件,当前版本中,其余的配置文件都放在/etc/percona-xtradb-cluster.conf.d目
录里,包括mysqld.cnf,mysqld_safe.cnf,wsrep.cnf 三个文件
#主配置文件不需要修改
[root@pxc1 ~]#cat /etc/my.cnf
# The Percona XtraDB Cluster 5.7 configuration file.
...省略...
!includedir /etc/my.cnf.d/
!includedir /etc/percona-xtradb-cluster.conf.d/
[root@pxc1 ~]#ls /etc/my.cnf.d/
[root@pxc1 ~]#ls /etc/percona-xtradb-cluster.conf.d/
mysqld.cnf mysqld_safe.cnf wsrep.cnf
#下面配置文件不需要修改
[root@pxc1 ~]#cat /etc/percona-xtradb-cluster.conf.d/mysqld.cnf
...省略...
[client]
socket=/var/lib/mysql/mysql.sock
[mysqld]
server-id=1
#建议各个节点不同
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
log-bin
#建议启用,非必须项
log_slave_updates
expire_logs_days=7
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
#下面配置文件不需要修改
[root@pxc1 ~]#cat /etc/percona-xtradb-cluster.conf.d/mysqld_safe.cnf
...省略...
[mysqld_safe]
pid-file = /var/run/mysqld/mysqld.pid
socket
nice
= /var/lib/mysql/mysql.sock
= 0
#PXC的配置文件必须修改
[root@pxc1 ~]#vim /etc/percona-xtradb-cluster.conf.d/wsrep.cnf
[root@pxc1 ~]#grep -Ev "#|$" /etc/percona-xtradb-cluster.conf.d/wsrep.cnf
[mysqld]
wsrep_provider=/usr/lib64/galera3/libgalera_smm.so
wsrep_cluster_address=gcomm://10.0.0.7,10.0.0.17,10.0.0.27 #三个节点的IP
binlog_format=ROW
default_storage_engine=InnoDB
wsrep_slave_threads= 8
wsrep_log_conflicts
innodb_autoinc_lock_mode=2
wsrep_node_address=10.0.0.7
wsrep_cluster_name=pxc-cluster
wsrep_node_name=pxc-cluster-node-1
pxc_strict_mode=ENFORCING
#各个节点,指定自已的IP
#各个节点,指定自已节点名称
wsrep_sst_method=xtrabackup-v2
wsrep_sst_auth="sstuser:s3cretPass"
码信息必须一致
#取消本行注释,同一集群内多个节点的验证用户和密
[root@pxc2 ~]#grep -Ev "#|$" /etc/percona-xtradb-cluster.conf.d/wsrep.cnf
[mysqld]
wsrep_provider=/usr/lib64/galera3/libgalera_smm.so
wsrep_cluster_address=gcomm://10.0.0.7,10.0.0.17,10.0.0.27
binlog_format=ROW
default_storage_engine=InnoDB
wsrep_slave_threads= 8
wsrep_log_conflicts
innodb_autoinc_lock_mode=2
wsrep_node_address=10.0.0.17
wsrep_cluster_name=pxc-cluster
#各个节点,指定自已的IP
wsrep_node_name=pxc-cluster-node-2
pxc_strict_mode=ENFORCING
#各个节点,指定自已节点名称
#取消本行注释
wsrep_sst_method=xtrabackup-v2
wsrep_sst_auth="sstuser:s3cretPass"
[root@pxc3 ~]#grep -Ev "#|$" /etc/percona-xtradb-cluster.conf.d/wsrep.cnf
[mysqld]
wsrep_provider=/usr/lib64/galera3/libgalera_smm.so
wsrep_cluster_address=gcomm://10.0.0.7,10.0.0.17,10.0.0.27
binlog_format=ROW
default_storage_engine=InnoDB
wsrep_slave_threads= 8
wsrep_log_conflicts
innodb_autoinc_lock_mode=2
wsrep_node_address=10.0.0.27
wsrep_cluster_name=pxc-cluster
wsrep_node_name=pxc-cluster-node-3
pxc_strict_mode=ENFORCING
#各个节点,指定自已的IP
#各个节点,指定自已的IP
wsrep_sst_method=xtrabackup-v2
wsrep_sst_auth="sstuser:s3cretPass"
#取消本行注释
注意:尽管Galera Cluster不再需要通过binlog的形式进行同步,但还是建议在配置文件中开启二进制日
志功能,原因是后期如果有新节点需要加入,老节点通过SST全量传输的方式向新节点传输数据,很可
能会拖垮集群性能,所以让新节点先通过binlog方式完成同步后再加入集群会是一种更好的选择
配置文件各项配置意义
配置
说明
wsrep_provider
wsrep_cluster_name
指定Galera库的路径
Galera集群的名称
Galera集群中各节点地址。地址使用组通信协议gcomm://(group
communication)
wsrep_cluster_address
wsrep_node_name
本节点在Galera集群中的名称
wsrep_node_address
本节点在Galera集群中的通信地址
state_snapshot_transfer(SST)使用的传输方法,可用方法有
mysqldump、rsync和xtrabackup,前两者在传输时都需要对
Donor加全局只读锁(FLUSH TABLES WITH READ LOCK),
xtrabackup则不需要(它使用percona自己提供的backup lock)。
强烈建议采用xtrabackup
wsrep_sst_method
wsrep_sst_auth
pxc_strict_mode
在SST传输时需要用到的认证凭据,格式为:"用户:密码"
是否限制PXC启用正在试用阶段的功能,ENFORCING是默认值,
表示不启用
binlog_format
二进制日志的格式。Galera只支持row格式的二进制日志
指定默认存储引擎。Galera的复制功能只支持InnoDB
只能设置为2,设置为0或1时会无法正确处理死锁问题
default_storage_engine
innodb_autoinc_lock_mode
4 启动PXC集群中第一个节点
root@pxc1 ~]#ss -ntul
Netid State
Address:Port
Recv-Q Send-Q
Local Address:Port
127.0.0.1:323
::1:323
Peer
udp
udp
tcp
UNCONN
*:*
0
0
0
0
UNCONN
0
LISTEN
*:*
128
*:22
tcp
LISTEN
0
100
127.0.0.1:25
*:*
tcp
LISTEN
0
0
128
100
tcp
LISTEN
::1:25
#启动第一个节点
[root@pxc1 ~]#systemctl start mysql@bootstrap.service
[root@pxc1 ~]#ss -ntul
Netid State
Address:Port
Recv-Q Send-Q
Local Address:Port
127.0.0.1:323
::1:323
Peer
udp
UNCONN
UNCONN
LISTEN
0
0
0
0
*:*
udp
0
tcp
128
*:22
*:*
tcp LISTEN
*:*
0
0
0
0
0
128
100
80
*:4567
tcp LISTEN
*:*
127.0.0.1:25
tcp LISTEN
tcp LISTEN
128
100
tcp LISTEN
::1:25
#查看root密码
[root@pxc1 ~]#grep "temporary password" /var/log/mysqld.log
2019-11-30T02:53:54.292659Z 1 [Note] A temporary password is generated for
root@localhost: =tWFP0oRJl8t
[root@pxc1 ~]#mysql -uroot -p'=tWFP0oRJl8t'
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 5.7.27-30-57-log
Copyright (c) 2009-2019 Percona LLC and/or its affiliates
Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
#修改root密码
mysql> alter user 'root'@'localhost' identified by 'magedu';
Query OK, 0 rows affected (0.01 sec)
#创建相关用户并授权
mysql> CREATE USER 'sstuser'@'localhost' IDENTIFIED BY 's3cretPass';
Query OK, 0 rows affected (0.00 sec)
mysql> GRANT RELOAD, LOCK TABLES, PROCESS, REPLICATION CLIENT ON *.* TO
'sstuser'@'localhost';
Query OK, 0 rows affected (0.01 sec)
#查看相关变量
mysql> SHOW VARIABLES LIKE 'wsrep%'\G
*************************** 1. row ***************************
Variable_name: wsrep_OSU_method
Value: TOI
*************************** 2. row ***************************
Variable_name: wsrep_RSU_commit_timeout
Value: 5000
*************************** 3. row ***************************
Variable_name: wsrep_auto_increment_control
Value: ON
*************************** 4. row ***************************
Variable_name: wsrep_causal_reads
Value: OFF
*************************** 5. row ***************************
Variable_name: wsrep_certification_rules
Value: strict
*************************** 6. row ***************************
Variable_name: wsrep_certify_nonPK
Value: ON
*************************** 7. row ***************************
Variable_name: wsrep_cluster_address
Value: gcomm://10.0.0.7,10.0.0.17,10.0.0.27
*************************** 8. row ***************************
Variable_name: wsrep_cluster_name
Value: pxc-cluster
*************************** 9. row ***************************
Variable_name: wsrep_convert_LOCK_to_trx
Value: OFF
*************************** 10. row ***************************
Variable_name: wsrep_data_home_dir
Value: /var/lib/mysql/
*************************** 11. row ***************************
Variable_name: wsrep_dbug_option
Value:
*************************** 12. row ***************************
Variable_name: wsrep_debug
Value: OFF
*************************** 13. row ***************************
Variable_name: wsrep_desync
Value: OFF
*************************** 14. row ***************************
Variable_name: wsrep_dirty_reads
Value: OFF
*************************** 15. row ***************************
Variable_name: wsrep_drupal_282555_workaround
Value: OFF
*************************** 16. row ***************************
Variable_name: wsrep_forced_binlog_format
Value: NONE
*************************** 17. row ***************************
Variable_name: wsrep_load_data_splitting
Value: ON
*************************** 18. row ***************************
Variable_name: wsrep_log_conflicts
Value: ON
*************************** 19. row ***************************
Variable_name: wsrep_max_ws_rows
Value: 0
*************************** 20. row ***************************
Variable_name: wsrep_max_ws_size
Value: 2147483647
*************************** 21. row ***************************
Variable_name: wsrep_node_address
Value: 10.0.0.7
*************************** 22. row ***************************
Variable_name: wsrep_node_incoming_address
Value: AUTO
*************************** 23. row ***************************
Variable_name: wsrep_node_name
Value: pxc-cluster-node-1
*************************** 24. row ***************************
Variable_name: wsrep_notify_cmd
Value:
*************************** 25. row ***************************
Variable_name: wsrep_on
Value: ON
*************************** 26. row ***************************
Variable_name: wsrep_preordered
Value: OFF
*************************** 27. row ***************************
Variable_name: wsrep_provider
Value: /usr/lib64/galera3/libgalera_smm.so
*************************** 28. row ***************************
Variable_name: wsrep_provider_options
Value: base_dir = /var/lib/mysql/; base_host = 10.0.0.7; base_port =
4567; cert.log_conflicts = no; cert.optimistic_pa = yes; debug = no;
evs.auto_evict = 0; evs.causal_keepalive_period = PT1S; evs.debug_log_mask =
0x1; evs.delay_margin = PT1S; evs.delayed_keep_period = PT30S;
evs.inactive_check_period = PT0.5S; evs.inactive_timeout = PT15S;
evs.info_log_mask = 0; evs.install_timeout = PT7.5S; evs.join_retrans_period =
PT1S; evs.keepalive_period = PT1S; evs.max_install_timeouts = 3; evs.send_window
= 10; evs.stats_report_period = PT1M; evs.suspect_timeout = PT5S;
evs.use_aggregate = true; evs.user_send_window = 4; evs.version = 0;
evs.view_forget_timeout = P1D; gcache.dir = /var/lib/mysql/;
gcache.freeze_purge_at_seqno = -1; gcache.keep_pages_count = 0;
gcache.keep_pages_size = 0; gcache.mem_size = 0; gcache.name =
/var/lib/mysql//galera.cache; gcache.page_size = 128M; gcache.recover = no;
gcache.size = 128M; gcomm.thread_prio = ; gcs.fc_debug = 0; gcs.fc_factor = 1;
gcs.fc_limit = 100; gcs.fc_master_slave = no; gcs
*************************** 29. row ***************************
Variable_name: wsrep_recover
Value: OFF
*************************** 30. row ***************************
Variable_name: wsrep_reject_queries
Value: NONE
*************************** 31. row ***************************
Variable_name: wsrep_replicate_myisam
Value: OFF
*************************** 32. row ***************************
Variable_name: wsrep_restart_slave
Value: OFF
*************************** 33. row ***************************
Variable_name: wsrep_retry_autocommit
Value: 1
*************************** 34. row ***************************
Variable_name: wsrep_slave_FK_checks
Value: ON
*************************** 35. row ***************************
Variable_name: wsrep_slave_UK_checks
Value: OFF
*************************** 36. row ***************************
Variable_name: wsrep_slave_threads
Value: 8
*************************** 37. row ***************************
Variable_name: wsrep_sst_auth
Value: ********
*************************** 38. row ***************************
Variable_name: wsrep_sst_donor
Value:
*************************** 39. row ***************************
Variable_name: wsrep_sst_donor_rejects_queries
Value: OFF
*************************** 40. row ***************************
Variable_name: wsrep_sst_method
Value: xtrabackup-v2
*************************** 41. row ***************************
Variable_name: wsrep_sst_receive_address
Value: AUTO
*************************** 42. row ***************************
Variable_name: wsrep_start_position
Value: 00000000-0000-0000-0000-000000000000:-1
*************************** 43. row ***************************
Variable_name: wsrep_sync_wait
Value: 0
43 rows in set (0.01 sec)
#查看相关状态变量
mysql> SHOW STATUS LIKE 'wsrep%'\G
*************************** 1. row ***************************
Variable_name: wsrep_local_state_uuid
Value: aad2c02e-131c-11ea-9294-b2e80a6c08c4
*************************** 2. row ***************************
Variable_name: wsrep_protocol_version
Value: 9
*************************** 3. row ***************************
Variable_name: wsrep_last_applied
Value: 3
*************************** 4. row ***************************
Variable_name: wsrep_last_committed
Value: 3
*************************** 5. row ***************************
Variable_name: wsrep_replicated
Value: 3
*************************** 6. row ***************************
Variable_name: wsrep_replicated_bytes
Value: 760
*************************** 7. row ***************************
Variable_name: wsrep_repl_keys
Value: 3
*************************** 8. row ***************************
Variable_name: wsrep_repl_keys_bytes
Value: 96
*************************** 9. row ***************************
Variable_name: wsrep_repl_data_bytes
Value: 465
*************************** 10. row ***************************
Variable_name: wsrep_repl_other_bytes
Value: 0
*************************** 11. row ***************************
Variable_name: wsrep_received
Value: 2
*************************** 12. row ***************************
Variable_name: wsrep_received_bytes
Value: 150
*************************** 13. row ***************************
Variable_name: wsrep_local_commits
Value: 0
*************************** 14. row ***************************
Variable_name: wsrep_local_cert_failures
Value: 0
*************************** 15. row ***************************
Variable_name: wsrep_local_replays
Value: 0
*************************** 16. row ***************************
Variable_name: wsrep_local_send_queue
Value: 0
*************************** 17. row ***************************
Variable_name: wsrep_local_send_queue_max
Value: 1
*************************** 18. row ***************************
Variable_name: wsrep_local_send_queue_min
Value: 0
*************************** 19. row ***************************
Variable_name: wsrep_local_send_queue_avg
Value: 0.000000
*************************** 20. row ***************************
Variable_name: wsrep_local_recv_queue
Value: 0
*************************** 21. row ***************************
Variable_name: wsrep_local_recv_queue_max
Value: 2
*************************** 22. row ***************************
Variable_name: wsrep_local_recv_queue_min
Value: 0
*************************** 23. row ***************************
Variable_name: wsrep_local_recv_queue_avg
Value: 0.500000
*************************** 24. row ***************************
Variable_name: wsrep_local_cached_downto
Value: 1
*************************** 25. row ***************************
Variable_name: wsrep_flow_control_paused_ns
Value: 0
*************************** 26. row ***************************
Variable_name: wsrep_flow_control_paused
Value: 0.000000
*************************** 27. row ***************************
Variable_name: wsrep_flow_control_sent
Value: 0
*************************** 28. row ***************************
Variable_name: wsrep_flow_control_recv
Value: 0
*************************** 29. row ***************************
Variable_name: wsrep_flow_control_interval
Value: [ 100, 100 ]
*************************** 30. row ***************************
Variable_name: wsrep_flow_control_interval_low
Value: 100
*************************** 31. row ***************************
Variable_name: wsrep_flow_control_interval_high
Value: 100
*************************** 32. row ***************************
Variable_name: wsrep_flow_control_status
Value: OFF
*************************** 33. row ***************************
Variable_name: wsrep_cert_deps_distance
Value: 1.000000
*************************** 34. row ***************************
Variable_name: wsrep_apply_oooe
Value: 0.000000
*************************** 35. row ***************************
Variable_name: wsrep_apply_oool
Value: 0.000000
*************************** 36. row ***************************
Variable_name: wsrep_apply_window
Value: 1.000000
*************************** 37. row ***************************
Variable_name: wsrep_commit_oooe
Value: 0.000000
*************************** 38. row ***************************
Variable_name: wsrep_commit_oool
Value: 0.000000
*************************** 39. row ***************************
Variable_name: wsrep_commit_window
Value: 1.000000
*************************** 40. row ***************************
Variable_name: wsrep_local_state
Value: 4
*************************** 41. row ***************************
Variable_name: wsrep_local_state_comment
Value: Synced
*************************** 42. row ***************************
Variable_name: wsrep_cert_index_size
Value: 1
*************************** 43. row ***************************
Variable_name: wsrep_cert_bucket_count
Value: 22
*************************** 44. row ***************************
Variable_name: wsrep_gcache_pool_size
Value: 2200
*************************** 45. row ***************************
Variable_name: wsrep_causal_reads
Value: 0
*************************** 46. row ***************************
Variable_name: wsrep_cert_interval
Value: 0.000000
*************************** 47. row ***************************
Variable_name: wsrep_open_transactions
Value: 0
*************************** 48. row ***************************
Variable_name: wsrep_open_connections
Value: 0
*************************** 49. row ***************************
Variable_name: wsrep_ist_receive_status
Value:
*************************** 50. row ***************************
Variable_name: wsrep_ist_receive_seqno_start
Value: 0
*************************** 51. row ***************************
Variable_name: wsrep_ist_receive_seqno_current
Value: 0
*************************** 52. row ***************************
Variable_name: wsrep_ist_receive_seqno_end
Value: 0
*************************** 53. row ***************************
Variable_name: wsrep_incoming_addresses
Value: 10.0.0.7:3306
*************************** 54. row ***************************
Variable_name: wsrep_cluster_weight
Value: 1
*************************** 55. row ***************************
Variable_name: wsrep_desync_count
Value: 0
*************************** 56. row ***************************
Variable_name: wsrep_evs_delayed
Value:
*************************** 57. row ***************************
Variable_name: wsrep_evs_evict_list
Value:
*************************** 58. row ***************************
Variable_name: wsrep_evs_repl_latency
Value: 0/0/0/0/0
*************************** 59. row ***************************
Variable_name: wsrep_evs_state
Value: OPERATIONAL
*************************** 60. row ***************************
Variable_name: wsrep_gcomm_uuid
Value: aad1f935-131c-11ea-910a-ce3ee95c675e
*************************** 61. row ***************************
Variable_name: wsrep_cluster_conf_id
Value: 1
*************************** 62. row ***************************
Variable_name: wsrep_cluster_size
Value: 1
*************************** 63. row ***************************
Variable_name: wsrep_cluster_state_uuid
Value: aad2c02e-131c-11ea-9294-b2e80a6c08c4
*************************** 64. row ***************************
Variable_name: wsrep_cluster_status
Value: Primary
*************************** 65. row ***************************
Variable_name: wsrep_connected
Value: ON
*************************** 66. row ***************************
Variable_name: wsrep_local_bf_aborts
Value: 0
*************************** 67. row ***************************
Variable_name: wsrep_local_index
Value: 0
*************************** 68. row ***************************
Variable_name: wsrep_provider_name
Value: Galera
*************************** 69. row ***************************
Variable_name: wsrep_provider_vendor
Value: Codership Oy <info@codership.com>
*************************** 70. row ***************************
Variable_name: wsrep_provider_version
Value: 3.39(rb3295e6)
*************************** 71. row ***************************
Variable_name: wsrep_ready
Value: ON
71 rows in set (0.00 sec)
#重点关注下面内容
mysql> show status like 'wsrep%';
+----------------------------+--------------------------------------+
| Variable_name
| Value
|
+----------------------------+--------------------------------------+
| wsrep_local_state_uuid
| ...
| aad2c02e-131c-11ea-9294-b2e80a6c08c4 |
| ...
| 4
|
|
|
|
|
|
|
|
|
| wsrep_local_state
| wsrep_local_state_comment | Synced
| ...
| ...
| 1
| wsrep_cluster_size
| wsrep_cluster_status
| wsrep_connected
| ...
| Primary
| ON
| ...
| ON
| wsrep_ready
+----------------------------+--------------------------------------+
说明:
wsrep_cluster_size表示,该Galera集群中只有一个节点
wsrep_local_state_comment 状态为Synced(4),表示数据已同步完成(因为是第一个引导节点,无数据
需要同步)。 如果状态是Joiner, 意味着 SST 没有完成. 只有所有节点状态是Synced,才可以加新节点
wsrep_cluster_status为Primary,且已经完全连接并准备好
5 启动PXC集群中其它所有节点
[root@pxc2 ~]#ss -ntul
Netid State
Address:Port
Recv-Q Send-Q
Local Address:Port
127.0.0.1:323
::1:323
Peer
udp
UNCONN
UNCONN
LISTEN
0
0
0
0
0
0
0
*:*
udp
0
tcp
128
100
128
100
*:22
*:*
LISTEN
*:*
LISTEN
LISTEN
tcp
tcp
tcp
127.0.0.1:25
::1:25
[root@pxc2 ~]#systemctl start mysql
[root@pxc2 ~]#ss -ntulp
Netid State
Address:Port
Recv-Q Send-Q
Local Address:Port
Peer
udp
UNCONN
UNCONN
LISTEN
0
0
0
0
0
127.0.0.1:323
users:(("chronyd",pid=6289,fd=1))
::1:323
*:*
udp
users:(("chronyd",pid=6289,fd=2))
tcp
128
*:22
*:*
users:(("sshd",pid=6617,fd=3))
tcp LISTEN
*:*
0
0
0
0
0
128
*:4567
users:(("mysqld",pid=7754,fd=11))
tcp LISTEN
*:*
100
127.0.0.1:25
users:(("master",pid=6752,fd=13))
80 :::3306
tcp LISTEN
users:(("mysqld",pid=7754,fd=34))
tcp LISTEN
128
users:(("sshd",pid=6617,fd=4))
tcp LISTEN
100
::1:25
users:(("master",pid=6752,fd=14))
[root@pxc3 ~]#systemctl start mysql
6 查看集群状态,验证集群是否成功
#在任意节点,查看集群状态
[root@pxc1 ~]#mysql -uroot -pmagedu
mysql> SHOW VARIABLES LIKE 'wsrep_node_name';
+-----------------+--------------------+
| Variable_name | Value
|
+-----------------+--------------------+
| wsrep_node_name | pxc-cluster-node-1 |
+-----------------+--------------------+
1 row in set (0.00 sec)
mysql> SHOW VARIABLES LIKE 'wsrep_node_address';
+--------------------+----------+
| Variable_name
| Value
|
+--------------------+----------+
| wsrep_node_address | 10.0.0.7 |
+--------------------+----------+
1 row in set (0.01 sec)
mysql> SHOW VARIABLES LIKE 'wsrep_on';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wsrep_on
| ON
|
+---------------+-------+
1 row in set (0.00 sec)
mysql> SHOW STATUS LIKE 'wsrep_cluster_size';
+--------------------+-------+
| Variable_name
+--------------------+-------+
| wsrep_cluster_size | 3
| Value |
|
+--------------------+-------+
1 row in set (0.01 sec)
#在任意节点查看数据库
mysql> show databases;
+--------------------+
| Database
|
+--------------------+
| information_schema |
| mysql
| performance_schema |
| sys
|
|
+--------------------+
4 rows in set (0.00 sec)
#在任意节点创建数据库
mysql> create database testdb1;
Query OK, 1 row affected (0.00 sec)
mysql> show databases;
+--------------------+
| Database
|
+--------------------+
| information_schema |
| mysql
|
| performance_schema |
| sys
|
|
| testdb1
+--------------------+
5 rows in set (0.00 sec)
mysql>
#在任意其它节点验证数据是否同步
[root@pxc2 ~]#mysql -uroot -pmagedu
mysql> show databases;
+--------------------+
| Database
|
+--------------------+
| information_schema |
| mysql
|
| performance_schema |
| sys
|
|
| testdb1
+--------------------+
5 rows in set (0.01 sec)
#利用Xshell软件,同时在三个节点数据库,在其中一个节点成功
mysql> create database testdb2;
Query OK, 1 row affected (0.01 sec)
#在其它节点都提示失败
mysql> create database testdb2;
ERROR 1007 (HY000): Can't create database 'testdb2'; database exists
7 在PXC集群中加入节点
一个节点加入到Galera集群有两种情况:新节点加入集群、暂时离组的成员再次加入集群
1)新节点加入Galera集群
新节点加入集群时,需要从当前集群中选择一个Donor节点来同步数据,也就是所谓的
state_snapshot_tranfer(SST)过程。SST同步数据的方式由选项wsrep_sst_method决定,一般选择的是
xtrabackup。
必须注意,新节点加入Galera时,会删除新节点上所有已有数据,再通过xtrabackup(假设使用的是该方
式)从Donor处完整备份所有数据进行恢复。所以,如果数据量很大,新节点加入过程会很慢。而且,在
一个新节点成为Synced状态之前,不要同时加入其它新节点,否则很容易将集群压垮。
如果是这种情况,可以考虑使用wsrep_sst_method=rsync来做增量同步,既然是增量同步,最好保证
新节点上已经有一部分数据基础,否则和全量同步没什么区别,且这样会对Donor节点加上全局read
only锁。
2)旧节点加入Galera集群
如果旧节点加入Galera集群,说明这个节点在之前已经在Galera集群中呆过,有一部分数据基础,缺少
的只是它离开集群时的数据。这时加入集群时,会采用IST(incremental snapshot transfer)传输机制,
即使用增量传输。
但注意,这部分增量传输的数据源是Donor上缓存在GCache文件中的,这个文件有大小限制,如果缺失
的数据范围超过已缓存的内容,则自动转为SST传输。如果旧节点上的数据和Donor上的数据不匹配(例
如这个节点离组后人为修改了一点数据),则自动转为SST传输。
#在PXC集群中再加一台新的主机PXC4:10.0.0.37
[root@pxc4 ~]#yum install Percona-XtraDB-Cluster-57 -y
[root@pxc4 ~]#vim /etc/percona-xtradb-cluster.conf.d/wsrep.cnf
[root@pxc4 ~]#grep -Ev "#|$" /etc/percona-xtradb-cluster.conf.d/wsrep.cnf
[mysqld]
wsrep_provider=/usr/lib64/galera3/libgalera_smm.so
wsrep_cluster_address=gcomm://10.0.0.7,10.0.0.17,10.0.0.27,10.0.0.37
binlog_format=ROW
default_storage_engine=InnoDB
wsrep_slave_threads= 8
wsrep_log_conflicts
innodb_autoinc_lock_mode=2
wsrep_node_address=10.0.0.37
wsrep_cluster_name=pxc-cluster
wsrep_node_name=pxc-cluster-node-4
pxc_strict_mode=ENFORCING
wsrep_sst_method=xtrabackup-v2
wsrep_sst_auth="sstuser:s3cretPass"
[root@pxc4 ~]#systemctl start mysql
[root@pxc4 ~]#mysql -uroot -pmagedu
Server version: 5.7.27-30-57-log Percona XtraDB Cluster (GPL), Release rel30,
Revision
mysql> SHOW STATUS LIKE 'wsrep_cluster_size';
+--------------------+-------+
| Variable_name
+--------------------+-------+
| wsrep_cluster_size | 4
| Value |
|
+--------------------+-------+
1 row in set (0.00 sec)
mysql> show databases;
+--------------------+
| Database
|
+--------------------+
| information_schema |
| mysql
|
| performance_schema |
| sys
|
|
|
|
| testdb1
| testdb2
| testdb3
+--------------------+
8 rows in set (0.00 sec)
#将其它节点的配置文件加以修改
[root@pxc1 ~]#vim /etc/percona-xtradb-cluster.conf.d/wsrep.cnf
wsrep_cluster_address=gcomm://10.0.0.7,10.0.0.17,10.0.0.27,10.0.0.37
[root@pxc2 ~]#vim /etc/percona-xtradb-cluster.conf.d/wsrep.cnf
[root@pxc3 ~]#vim /etc/percona-xtradb-cluster.conf.d/wsrep.cnf
8 在PXC集群中修复故障节点
#在除第一个启动节点外的任意节点停止服务
[root@pxc4 ~]#systemctl stop mysql
#在其它任意节点查看wsrep_cluster_size变量少了一个节点
[root@pxc1 ~]#mysql -uroot -pmagedu
Server version: 5.7.27-30-57-log Percona XtraDB Cluster (GPL), Release rel30,
Revision
mysql> SHOW STATUS LIKE 'wsrep_cluster_size';
+--------------------+-------+
| Variable_name
+--------------------+-------+
| wsrep_cluster_size | 3
| Value |
|
+--------------------+-------+
1 row in set (0.01 sec)
mysql> create database testdb4;
#在其它任意节点可看到数据已同步
mysql> show databases;
+--------------------+
| Database
|
+--------------------+
| information_schema |
| mysql
|
| performance_schema |
| sys
|
|
|
|
|
| testdb1
| testdb2
| testdb3
| testdb4
+--------------------+
10 rows in set (0.00 sec)
#恢复服务,数据同步
[root@pxc4 ~]#systemctl start mysql
[root@pxc4 ~]#mysql -uroot -pmagedu
mysql> show databases;
+--------------------+
| Database
|
+--------------------+
| information_schema |
| mysql
|
| performance_schema |
| sys
|
|
|
|
|
| testdb1
| testdb2
| testdb3
| testdb4
+--------------------+
10 rows in set (0.00 sec)
mysql> SHOW STATUS LIKE 'wsrep_cluster_size';
+--------------------+-------+
| Variable_name
+--------------------+-------+
| wsrep_cluster_size | 4
| Value |
|
+--------------------+-------+
1 row in set (0.01 sec)
6.3.3.4 实战案例:MariaDB Galera Cluster
范例:在centos8 实现MariaDB Galera Cluster
#在三个节点上都实现
[root@centos8 ~]#dnf install mariadb-server-galera -y
[root@centos8 ~]#vim /etc/my.cnf.d/galera.cnf
#wsrep_cluster_address="dummy://" 在此行下面加一行
wsrep_cluster_address="gcomm://10.0.0.8,10.0.0.18,10.0.0.28"
#启动第一节点
[root@centos8 ~]#galera_new_cluster
[root@centos8 ~]#systemctl enable mariadb
#再启动其它节点
[root@centos8 ~]#systemctl enable --now mariadb
[root@centos8 ~]#ss -ntul
Netid
State
Peer Address:Port
LISTEN
Recv-Q
Send-Q
Local Address:Port
0.0.0.0:22
tcp
0
128
0.0.0.0:*
0.0.0.0:4567
LISTEN
tcp
LISTEN
0.0.0.0:*
0
128
tcp
tcp
0
0
80
0.0.0.0:3306
[::]:22
0.0.0.0:*
LISTEN
128
[::]:*
[root@centos8 ~]#mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 11
Server version: 10.3.11-MariaDB MariaDB Server
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]>
MariaDB [(none)]> show status like "wsrep_ready";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wsrep_ready
| ON
|
+---------------+-------+
1 row in set (0.001 sec)
MariaDB [(none)]> SHOW STATUS LIKE 'wsrep_cluster_size';
+--------------------+-------+
| Variable_name
+--------------------+-------+
| wsrep_cluster_size | 3
| Value |
|
+--------------------+-------+
1 row in set (0.001 sec)
MariaDB [(none)]> SHOW VARIABLES LIKE 'wsrep_%'\G
MariaDB [(none)]> SHOW STATUS LIKE 'wsrep_%';
范例:CentOS 7 实现 MariaDB Galera Cluster 5.5
#参考仓库:https://mirrors.tuna.tsinghua.edu.cn/mariadb/mariadb-5.5.X/yum/centos7-
amd64/
yum install MariaDB-Galera-server
vim /etc/my.cnf.d/server.cnf
[galera]
wsrep_provider = /usr/lib64/galera/libgalera_smm.so
wsrep_cluster_address="gcomm://10.0.0.7,10.0.0.17,10.0.0.27"
binlog_format=row
default_storage_engine=InnoDB
innodb_autoinc_lock_mode=2
bind-address=0.0.0.0
#下面配置可选项
wsrep_cluster_name = 'mycluster' 默认my_wsrep_cluster
wsrep_node_name = 'node1'
wsrep_node_address = '10.0.0.7'
#首次启动时,需要初始化集群,在其中一个节点上执行命令
/etc/init.d/mysql start --wsrep-new-cluster
#而后正常启动其它节点
service mysql start
#查看集群中相关系统变量和状态变量
SHOW VARIABLES LIKE 'wsrep_%';
SHOW STATUS LIKE 'wsrep_%';
SHOW STATUS LIKE 'wsrep_cluster_size';
6.3.4 TiDB 概述
TiDB 是 PingCAP 公司受 Google Spanner / F1 论文启发而设计的开源分布式 HTAP (Hybrid
Transactional and Analytical Processing) 数据库,结合了传统的 RDBMS 和NoSQL 的最佳特性。TiDB
兼容 MySQL,支持无限的水平扩展,具备强一致性和高可用性。TiDB和mysql几乎完全兼容
TiDB 是一个分布式 NewSQL 数据库。它支持水平弹性扩展、ACID 事务、标准 SQL、MySQL 语法和
MySQL 协议,具有数据强一致的高可用特性,是一个不仅适合 OLTP 场景还适合 OLAP 场景的混合数据
库。TiDB年可用性达到99.95%
TiDB 的目标是为 OLTP(Online Transactional Processing) 和 OLAP (Online Analytical Processing) 场
景提供一站式的解决方案。
6.3.4.1 TiDB 核心特点
1. 高度兼容 MySQL 大多数情况下,无需修改代码即可从 MySQL 轻松迁移至 TiDB,分库分表后的
MySQL 集群亦可通过 TiDB 工具进行实时迁移
2. 水平弹性扩展 通过简单地增加新节点即可实现 TiDB 的水平扩展,按需扩展吞吐或存储,轻松应
对高并发、海量数据场景
3. 分布式事务 TiDB 100% 支持标准的 ACID 事务
4. 真正金融级高可用 相比于传统主从 (M-S) 复制方案,基于 Raft 的多数派选举协议可以提供金融
级的 100% 数据强一致性保证,且在不丢失大多数副本的前提下,可实现故障的自动恢复 (auto-
failover),无需人工介入
5. 一站式 HTAP 解决方案 TiDB 作为典型的 OLTP 行存数据库,同时兼具强大的 OLAP 性能,配合
TiSpark,可提供一站式 HTAP解决方案,一份存储同时处理OLTP & OLAP(OLAP、OLTP的介绍和
比较 )无需传统繁琐的 ETL 过程
6. 云原生 SQL 数据库 TiDB 是为云而设计的数据库,同 Kubernetes 深度耦合,支持公有云、私有
云和混合云,使部署、配置和维护变得十分简单。TiDB 的设计目标是 100% 的 OLTP 场景和 80%
的 OLAP 场景,更复杂的 OLAP 分析可以通过 TiSpark 项目来完成。 TiDB 对业务没有任何侵入
性,能优雅的替换传统的数据库中间件、数据库分库分表等 Sharding 方案。同时它也让开发运维
人员不用关注数据库 Scale 的细节问题,专注于业务开发,极大的提升研发的生产力
6.3.4.2 TiDB整体架构
TiDB Server
TiDB Server 负责接收SQL请求,处理SQL相关的逻辑,并通过PD找到存储计算所需数据的TiKV地址,
与TiKV交互获取数据,最终返回结果。TiDB Server 是无状态的,其本身并不存储数据,只负责计算,
可以无限水平扩展,可以通过负载均衡组件(LVS、HAProxy或F5)对外提供统一的接入地址。
PD Server
Placement Driver(简称PD)是整个集群的管理模块,其主要工作有三个:一是存储集群的元信息(某
个Key存储在那个TiKV节点);二是对TiKV集群进行调度和负载均衡(如数据的迁移、Raft group
leader的迁移等);三是分配全局唯一且递增的事务ID
PD 是一个集群,需要部署奇数个节点,一般线上推荐至少部署3个节点。PD在选举的过程中无法对外提
供服务,这个时间大约是3秒
TiKV Server
TiKV Server 负责存储数据,从外部看TiKV是一个分布式的提供事务的Key-Value存储引擎。存储数据的
基本单位是Region,每个Region负责存储一个Key Range(从StartKey到EndKey的左闭右开区间)的数
据,每个TiKV节点会负责多个Region。TiKV使用Raft协议做复制,保持数据的一致性和容灾。副本以
Region为单位进行管理,不同节点上的多个Region构成一个Raft Group,互为副本。数据在多个TiKV之
间的负载均衡由PD调度,这里也就是以Region为单位进行调度
7 MySQL压力测试
7.1 压力测试工具
7.1.1 常见 MySQL 压力测试工具
mysqlslap
Sysbench:功能强大,官网: https://github.com/akopytov/sysbench
tpcc-mysql
MySQL Benchmark Suite
MySQL super-smack
MyBench
7.1.2 mysqlslap
mysqlslap:来自于mysql或mariadb包,测试的过程默认生成一个mysqlslap的schema,生成测试表
t1,查询和插入测试数据,mysqlslap库自动生成,如果已经存在则先删除。用--only-print来打印实际
的测试过程,整个测试完成后不会在数据库中留下痕迹
使用格式:
mysqlslap [options]
常用参数 [options] 说明:
--auto-generate-sql, -a #自动生成测试表和数据,表示用mysqlslap工具自己生成的SQL脚本来测试
并发压力
--auto-generate-sql-load-type=type #测试语句的类型。代表要测试的环境是读操作还是写操作还是
两者混合的。取值包括:read,key,write,update和mixed(默认)
--auto-generate-sql-add-auto-increment #代表对生成的表自动添加auto_increment列,从
5.1.18版本开始支持
--number-char-cols=N, -x N #自动生成的测试表中包含多少个字符类型的列,默认1
--number-int-cols=N, -y N #自动生成的测试表中包含多少个数字类型的列,默认1
--number-of-queries=N #总的测试查询次数(并发客户数×每客户查询次数)
--query=name,-q #使用自定义脚本执行测试,例如可以调用自定义的存储过程或者sql语句来执行测试
--create-schema #代表自定义的测试库名称,测试的schema
--commint=N #多少条DML后提交一次
--compress, -C #如服务器和客户端都支持压缩,则压缩信息
--concurrency=N, -c N #表示并发量,即模拟多少个客户端同时执行select。可指定多个值,以逗号或
者--delimiter参数指定值做为分隔符,如:--concurrency=100,200,500
--engine=engine_name, -e engine_name #代表要测试的引擎,可以有多个,用分隔符隔开。例如:-
-engines=myisam,innodb
--iterations=N, -i N #测试执行的迭代次数,代表要在不同并发环境下,各自运行测试多少次
--only-print #只打印测试语句而不实际执行。
--detach=N #执行N条语句后断开重连
--debug-info, -T #打印内存和CPU的相关信息
mysqlslap示例
#单线程测试
mysqlslap -a -uroot -pmagedu
#多线程测试。使用--concurrency来模拟并发连接
mysqlslap -a -c 100 -uroot -pmagedu
#迭代测试。用于需要多次执行测试得到平均值
mysqlslap -a -i 10 -uroot -pmagedu
mysqlslap ---auto-generate-sql-add-autoincrement -a
mysqlslap -a --auto-generate-sql-load-type=read
mysqlslap -a --auto-generate-secondary-indexes=3
mysqlslap -a --auto-generate-sql-write-number=1000
mysqlslap --create-schema world -q "select count(*) from City"
mysqlslap -a -e innodb -uroot -pmagedu
mysqlslap -a --number-of-queries=10 -uroot -pmagedu
#测试同时不同的存储引擎的性能进行对比
mysqlslap -a --concurrency=50,100 --number-of-queries 1000 --iterations=5 --
engine=myisam,innodb --debug-info -uroot -pmagedu
#执行一次测试,分别50和100个并发,执行1000次总查询
mysqlslap -a --concurrency=50,100 --number-of-queries 1000 --debug-info -uroot -
pmagedu
#50和100个并发分别得到一次测试结果(Benchmark),并发数越多,执行完所有查询的时间越长。为了准确
起见,可以多迭代测试几次
mysqlslap -a --concurrency=50,100 --number-of-queries 1000 --iterations=5 --
debug-info -uroot -pmagedu
7.2 MySQL配置最佳实践
高并发大数据的互联网业务,架构设计思路是"解放数据库CPU,将计算转移到服务层",并发量大的情
况下,这些功能很可能将数据库拖死,业务逻辑放到服务层具备更好的扩展性,能够轻易实现"增机器就
加性能"
参考资料:
阿里巴巴Java开发手册:https://developer.aliyun.com/topic/java2020
58到家数据库30条军规解读:http://zhuanlan.51cto.com/art/201702/531364.htm
以下规范适用场景:并发量大、数据量大的互联网业务
7.2.1 基础规范
(1)必须使用InnoDB存储引擎
解读:支持事务、行级锁、并发性能更好、CPU及内存缓存页优化使得资源利用率更高
(2)使用UTF8MB4字符集
解读:万国码,无需转码,无乱码风险,节省空间,支持表情包及生僻字
(3)数据表、数据字段必须加入中文注释
解读:N年后谁知道这个r1,r2,r3字段是干嘛的
(4)禁止使用存储过程、视图、触发器、Event
解读:高并发大数据的互联网业务,架构设计思路是"解放数据库CPU,将计算转移到服务层",并发量
大的情况下,这些功能很可能将数据库拖死,业务逻辑放到服务层具备更好的扩展性,能够轻易实现"增
机器就加性能"。数据库擅长存储与索引,CPU计算还是上移吧!
(5)禁止存储大文件或者大照片
解读:为何要让数据库做它不擅长的事情?大文件和照片存储在文件系统,数据库里存URI多好。
7.2.2 命名规范
(6)只允许使用内网域名,而不是ip连接数据库
(7)线上环境、开发环境、测试环境数据库内网域名遵循命名规范
业务名称:xxx
线上环境:xxx.db
开发环境:xxx.rdb
测试环境:xxx.tdb
从库在名称后加-s标识,备库在名称后加-ss标识
线上从库:xxx-s.db
线上备库:xxx-sss.db
(8)库名、表名、字段名:小写,下划线风格,不超过32个字符,必须见名知意,禁止拼音英文混用
(9)库名与应用名称尽量一致,表名:t_业务名称_表的作用,主键名:pk_xxx,非唯一索引名:idx_xxx,唯
一键索引名:uk_xxx
7.2.3 表设计规范
(10)单实例表数目必须小于500
单表行数超过500万行或者单表容量超过2GB,才推荐进行分库分表。
说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表
(11)单表列数目必须小于30
(12)表必须有主键,例如自增主键
解读:
a)主键递增,数据行写入可以提高插入性能,可以避免page分裂,减少表碎片提升空间和内存的使用
b)主键要选择较短的数据类型, Innodb引擎普通索引都会保存主键的值,较短的数据类型可以有效的减
少索引的磁盘空间,提高索引的缓存效率
c) 无主键的表删除,在row模式的主从架构,会导致备库夯住
(13)禁止使用外键,如果有外键完整性约束,需要应用程序控制
解读:外键会导致表与表之间耦合,update与delete操作都会涉及相关联的表,十分影响sql 的性能,
甚至会造成死锁。高并发情况下容易造成数据库性能,大数据高并发业务场景数据库使用以性能优先
7.2.4 字段设计规范
(14)必须把字段定义为NOT NULL并且提供默认值
解读:
a)null的列使索引/索引统计/值比较都更加复杂,对MySQL来说更难优化
b)null 这种类型MySQL内部需要进行特殊处理,增加数据库处理记录的复杂性;同等条件下,表中有较多
空字段的时候,数据库的处理性能会降低很多
c)null值需要更多的存储空,无论是表还是索引中每行中的null的列都需要额外的空间来标识
d)对null 的处理时候,只能采用is null或is not null,而不能采用=、in、<、<>、!=、not in这些操作符
号。如:where name!='shenjian',如果存在name为null值的记录,查询结果就不会包含name为null
值的记录
(15)禁止使用TEXT、BLOB类型
解读:会浪费更多的磁盘和内存空间,非必要的大量的大字段查询会淘汰掉热数据,导致内存命中率急
剧降低,影响数据库性能
(16)禁止使用小数存储货币
解读:使用整数吧,小数容易导致钱对不上
(17)必须使用varchar(20)存储手机号
解读:
a)涉及到区号或者国家代号,可能出现+-()
b)手机号会去做数学运算么?
c)varchar可以支持模糊查询,例如:like"138%"
(18)禁止使用ENUM,可使用TINYINT代替
解读:
a)增加新的ENUM值要做DDL操作
b)ENUM的内部实际存储就是整数,你以为自己定义的是字符串?
7.2.5索引设计规范
(19)单表索引建议控制在5个以内
(20)单索引字段数不允许超过5个
解读:字段超过5个时,实际已经起不到有效过滤数据的作用了
(21)禁止在更新十分频繁、区分度不高的属性上建立索引
解读:
a)更新会变更B+树,更新频繁的字段建立索引会大大降低数据库性能
b)"性别"这种区分度不大的属性,建立索引是没有什么意义的,不能有效过滤数据,性能与全表扫描类
似
(22)建立组合索引,必须把区分度高的字段放在前面
解读:能够更加有效的过滤数据
7.2.6 SQL使用规范
(23)禁止使用SELECT *,只获取必要的字段,需要显示说明列属性
解读:
a)读取不需要的列会增加CPU、IO、NET消耗
b)不能有效的利用覆盖索引
c)使用SELECT *容易在增加或者删除字段后出现程序BUG
(24)禁止使用INSERT INTO t_xxx VALUES(xxx),必须显示指定插入的列属性
解读:容易在增加或者删除字段后出现程序BUG
(25)禁止使用属性隐式转换
解读:SELECT uid FROM t_user WHERE phone=13812345678 会导致全表扫描,而不能命中phone索
引,猜猜为什么?(这个线上问题不止出现过一次)
(26)禁止在WHERE条件的属性上使用函数或者表达式
解读:SELECT uid FROM t_user WHERE from_unixtime(day)>='2017-02-15' 会导致全表扫描
正确的写法是:SELECT uid FROM t_user WHERE day>= unix_timestamp('2017-02-15 00:00:00')
(27)禁止负向查询,以及%开头的模糊查询
解读:
a)负向查询条件:NOT、!=、<>、!<、!>、NOT IN、NOT LIKE等,会导致全表扫描
b)%开头的模糊查询,会导致全表扫描
(28)禁止大表使用JOIN查询,禁止大表使用子查询
解读:会产生临时表,消耗较多内存与CPU,极大影响数据库性能
(29)禁止使用OR条件,必须改为IN查询
解读:旧版本Mysql的OR查询是不能命中索引的,即使能命中索引,为何要让数据库耗费更多的CPU帮
助实施查询优化呢?
(30)应用程序必须捕获SQL异常,并有相应处理