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 官方网址

https://www.mysql.com/

http://mariadb.org/

https://www.percona.com

2.2.2.3 官方文档

https://dev.mysql.com/doc/

https://mariadb.com/kb/en/

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/

https://mirrors.tuna.tsinghua.edu.cn/mysql/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=${DIR}/${NAME}

DATA_DIR="/data/mysql"

yum install -y libaio perl-Data-Dumper

if [ -f ${FULL_NAME} ];then

echo "安装文件存在"

else

echo "安装文件不存在"

exit 3

fi

if [ -h /usr/local/mysql ];then

echo "Mysql 已经安装"

exit 3

else

tar xvf ${FULL_NAME}

-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 ${DIR}/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

www.wangxiaochun.com

The test script

#Description:

#Copyright (C):

2021 All rights reserved

#********************************************************************

. /etc/init.d/functions

DIR=`pwd`

MYSQL_VERSION=5.6.51

NAME="mysql-${MYSQL_VERSION}-linux-glibc2.12-x86_64.tar.gz"

FULL_NAME=${DIR}/${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 ${FULL_NAME} ];then

action "安装文件存在"

else

action "安装文件不存在" false

exit 3

fi

if [ -e /usr/local/mysql ];then

action "Mysql 已经安装" false

exit 3

else

tar xf ${FULL_NAME} -C /usr/local/src

ln -sv /usr/local/src/mysql-${MYSQL_VERSION}-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-${MYSQL_VERSION}-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

http://www.wangxiaochun.com

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"缺少${MYSQL}文件"$END

$COLOR"请将相关软件放在${SRC_DIR}目录下"$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

http://www.wangxiaochun.com

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"缺少${MYSQL}文件"$END

$COLOR"请将相关软件放在${SRC_DIR}目录下"$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="${mysql_basedir}/${port}/socket/mysql.sock"

function_start_mysql()

{

if [ ! -e "$mysql_sock" ];then

printf "Starting MySQL...\n"

${cmd_path}/mysqld_safe --defaults-

file=${mysql_basedir}/${port}/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"

${cmd_path}/mysqladmin -u ${mysql_user} -p${mysql_pwd} -S ${mysql_sock}

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: ${mysql_basedir}/${port}/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

  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

>${BACKUP}/fullbak_${BACKUP_TIME}.sql

MyISAM建议备份策略

mysqldump -uroot -p -A -F -E -R -x --master-data=1 --flush-privileges --

triggers --default-character-set=utf8 --hex-blob

>${BACKUP}/fullbak_${BACKUP_TIME}.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

${DIR}/${DB}_${TIME}.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

>

${DIR}/${DB}_${TIME}.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 的问题

跨节点合并排序分页问题

多数据源管理问题

针对数据源管理,目前主要有两种思路:

A. 客户端模式,在每个应用程序模块中配置管理自己需要的一个(或者多个)数据源,直接访问各个数

据库, 在模块内完成数据的整合

B. 通过中间代理层来统一管理所有的数据源,后端数据库集群对前端应用程序透明; 可能 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/ (原网站)

http://www.mycat.org.cn/

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复制的配置(同一时间只有一个节点是可写的)

官网: http://www.mysql-mmm.org

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-manager/releases

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 {

print

"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

:::22

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

::😗

:::3306

:::22

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

:::22

::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

:::22

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异常,并有相应处理

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值