mysql
Mysql
目录
[toc]
本站内容
- 关系型数据库基础
- 安装MySQL
- 管理数据库和表
- 用户和权限管理
- 函数,存储过程和触发器
- MySQL架构
- 存储引擎(Mysql支持插件式存储引擎)
- 服务器选项,系统和状态变量(这里容易产生混淆)
- 优化查询和索引管理
- 锁和事务管理
- 日志管理(日志种类更多:事务日志、二级日志、慢查询日志、错误日志、通用日志……)
- 备份还原(必备技能)
- MySQL集群
1、数据库原理
数据的时代
- 涉及的数据量大
- 数据不随程序的结束而消失
- 数据被多个应用程序共享
- 大数据
数据的分类:
- 结构化的数据:即有固定格式和有限长度的数据。例如填的表格就是结构化的数据,国籍:中华人民共和国,民族:汉,性别:男,这都叫结构化数据 (mysql适合管理)
- 非结构化的数据:非结构化的数据越来越多,就是不定长、无固定格式的数据,例如网页,有时候非常长,有时候几句话就没了;例如语音,视频都是非结构化的数据 (redis适合管理)
- 半结构化数据:比如:XML或者HTML的格式的数据
数据库的发展史
- 萌芽阶段:文件系统 使用磁盘文件来存储数据
- 初级阶段:第一代数据库 出现了网状模型、层次模型的数据库
- 中级阶段:第二代数据库 关系型数据库和结构化查询语言
- 高级阶段:新一代数据库 “关系-对象”型数据库
文件管理系统的缺点:
- 编写应用程序不方便
- 数据冗余不可避免
- 应用程序依赖性
- 不支持对文件的并发访问
- 数据间联系弱
- 难以按用户视图表示数据
- 无安全控制功能
DBMS 数据库管理系统
数据库:database是数据的汇集,它以一定的组织形式存于存储介质上
DBMS:是管理数据库的系统软件,它实现数据库系统的各种功能。是数据库系统的核心
DBA:负责数据库的规划、设计、协调、维护和管理等工作
应用程序:指以数据库为基础的应用程序
数据库管理系统的优点
- 相互关联的数据的集合
- 较少的数据冗余
- 程序与数据相互独立
- 保证数据的安全、可靠
- 最大限度地保证数据的正确性
- 数据可以并发使用并能同时保证一致性
数据库管理系统的基本功能
- 数据定义
- 数据处理
- 数据安全
- 数据备份
数据库系统的架构
- 单机架构
- 大型主机/终端架构
- 主从式架构(C/S)
- 分布式架构
各种数据库管理系统
网状数据库
最早出现的是网状DBMS,1964年通用电气公司的Charles Bachman成功地开发出世界上第一个网状IDS,也是第一个数据库管理系统,IDS 具有数据模式和日志的特征,只能在GE主机运行。
层次数据库
以树型结构表示实体及其之间联系,关系只支持一对多 代表数据库:IBM IMS
数据会产生冗余情况。
RDBMS 关系型数据库
关系统型数据库相关概念
- 关系 :关系就是二维表,其中:表中的行、列次序并不重要
- 行row:表中的每一行,又称为一条记录record
- 列column:表中的每一列,称为属性,字段,域field
- 主键PK ==Primary key==:用于惟一确定一个记录的字段,一张表只有一个主键 (主键避免一张表里出现了完全一样的记录,要在合适的字段设置主键!)
- 域domain:属性的取值范围,如,性别只能是‘男’和‘女’两个值,人类的年龄只能0-150
常用关系数据库
- MySQL: MySQL, MariaDB, Percona Server
- PostgreSQL: 简称为pgsql,EnterpriseDB
- Oracle
- MSSQL
- DB2 (IBM)
目前主流的还是这种关系型数据库。
redis,mongdb---no sql(非关系型数据库)
数据库排名
https://db-engines.com/en/ranking
office,access数据库,单机版。
- oracle源代码,上亿行了
linux内核源代码,2千万行
据说oracle源代码,上亿行了
关系型数据库理论
实体-联系模型E-R
实体Entity:客观存在并可以相互区分的客观事物或抽象事件称为实体,在E-R图中用矩形框表示实体,把实体名写在框内
属性:实体所具有的特征或性质
联系:联系是数据之间的关联集合,是客观存在的应用语义链
实体内部的联系:指组成实体的各属性之间的联系。如职工实体中,职工号和部门经理号之间有一种关联关系
实体之间的联系:指不同实体之间联系。例:学生选课实体和学生基本信息实体之间
实体之间的联系用菱形框表示
联系类型
- 一对一联系(1:1)
- 一对多联系(1:n):外键
- 多对多联系(m:n):增加第三张表😜
一对多:
==foreign key外键==
多对多:
节约表空间; 数据更加复杂,性能受影响;
数据的操作
- 数据提取:在数据集合中提取感兴趣的内容。SELECT
- 数据更新:变更数据库中的数据。INSERT、DELETE、UPDATE
数据库规划流程
- 收集数据,得到字段 收集必要且完整的数据项 转换成数据表的字段
- 把字段分类,归入表,建立表的关联 关联:表和表间的关系 分割数据表并建立关联的优点 节省空间 减少输入错误 方便数据修改
- 规范化数据库
数据库的正规化分析
面试也会被经常问到,一个比较经典的问题。
范式(设计数据库的规范)
数据库规范化,又称数据库或资料库的正规化、标准化,是数据库设计中的一系列原理和技术,以减少数据库中数据冗余,增进数据的一致性。关系模型的发明者埃德加·科德最早提出这一概念,并于1970年代初定义了第一范式、第二范式和第三范式的概念
设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,不同的规范要求被称为不同范式,各种范式呈递次规范,越高的范式数据库冗余越小。
目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴德斯科范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。满足最低要求的范式是第一范式(1NF)。在第一范式的基础上进一步满足更多规范要求的称为第二范式(2NF),其余范式以次类推。一般数据库只需满足第三范式(3NF)即可
通常情况:达到第一、二、三范式在生产里就够用了,第4、5范式基本用不到。(或者有时,我们甚至会考虑性能,会故意违反第2/3范式,直接使用第一范式。)
范式级别越高:数据库越节约空间,但复杂性越高,性能越低。
学习范式,并不是为了遵守范式,而是为了违反范式哈哈。
第一范式:1NF
无重复的列,每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性,确保每一列的原子性。除去同类型的字段,就是无重复的列。
说明:第一范式(1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据库
举例:
不属于第一范式:
(除去同类型的字段)
(同一列中不能有多个值)
属于第一范式:
第二范式:2NF
属性完全依赖于主键,第二范式必须先满足第一范式,要求表中的每个行必须可以被唯一地区分,通常为表加上每行的唯一标识PK,非PK的字段需要与整个PK有直接相关性
举例:
不符合 第二范式:2NF
(非PK的字段需要与整个PK有直接相关性)
改进后:符合第2范式(拆分成2张表后,节约了空间,但同时也带来了复杂性及性能问题)
第三范式:3NF
属性不依赖于其它非主属性,满足第三范式必须先满足第二范式。第三范式要求一个数据表中不包含已在其它表中已包含的非主关键字信息,非PK的字段间不能有从属关系
举例:
次场景不符合第三范式:(因为非PK的字段间有了从属关系)(会带来一些数据重复录入,数据冗余问题)
解决方法:
还是一样,拆分成2张表就好。(带来的后果还是和上面第二范式一样的效果)
SQL 结构化查询语言简介
SQL:结构化查询语言,Structure Query Language
SQL解释器;
数据存储协议:应用层协议,C/S S:server, 监听于套接字,接收并处理客户端的应用请求 C:Client
客户端程序接口 CLI GUI
应用编程接口 ODBC:Open Database Connectivity JDBC:Java Data Base Connectivity
SQL 基本概念
- 约束:constraint,表中的数据要遵守的限制
- 主键:一个或多个字段的组合,填入的数据必须能在本表中唯一标识本行;必须提供数据,即NOT NULL,一个表只能有一个
- 惟一键:一个或多个字段的组合,填入的数据必须能在本表中唯一标识本行;允许为NULL,一个表可以存在多个
- 外键:一个表中的某字段可填入的数据取决于另一个表的主键或唯一键已有的数据
- 检查:字段值在一定范围内
- 索引:将表中的一个或多个字段中的数据复制一份另存,并且按特定次序排序存储
关系运算
- 选择:挑选出符合条件的行
- 投影:挑选出需要的字段 (列)
- 连接:表间字段的关联
数据抽象
- 物理层:数据存储格式,即RDBMS在磁盘上如何组织文件
- 逻辑层:DBA角度,描述存储什么数据,以及数据间存在什么样的关系
- 视图层:用户角度,描述DB中的部分数据
关系模型的分类
- 关系模型
- 基于对象的关系模型
- 半结构化的关系模型:XML数据
2、MySQL安装和基本使用
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 75亿美元收购sun 2009年:Monty成立MariaDB
MySQL系列
MySQL 的三大主要分支
- mysql (用的最多)
- mariadb
- percona Server
官方网址
官方文档
https://www.percona.com/software/mysql-database/percona-server
==版本演变==
MySQL:5.1 --> 5.5 --> 5.6 --> 5.7 -->8.0
MariaDB:5.5 -->10.0--> 10.1 --> 10.2 --> 10.3 --> 10.4 --> 10.5
NOTE
特别注意:各自版本ios默认mysql版本
CentOS 8:安装光盘直接提供
mysql-server:8.0
mariadb-server : 10.3.17
CentOS 7:安装光盘直接提供
mariadb-server:5.5 服务器包
mariadb 客户端工具包
CentOS 6:
mysql-server:5.1 服务器包
mysql 客户端工具包
MYSQL的特性
==插件式存储引擎==:也称为“表类型”,存储管理器有多种实现版本,功能和特性可能均略有差别;用户可根据需要灵活选择,Mysql5.5.5开始,innoDB引擎是MYSQL默认引擎
- MyISAM ==> Aria
- InnoDB ==> XtraDB
这里会有一个经典的面试题:InnoDB和MyISAM存储引擎有什么区别。
单进程,多线程
诸多扩展和新特性
提供了较多测试组件
开源
MySQL 安装方式介绍和快速安装
安装方式介绍
- 源代码:编译安装 (生产环境,可以定制)
- 二进制格式的程序包:展开至特定路径,并经过简单配置后即可使用 (绿色安装)
- 程序包管理器管理的程序包 (测试环境)
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/
初始化脚本提高安全性
运行脚本:mysql_secure_installation
设置数据库管理员root口令
禁止root远程登录
删除anonymous用户帐号
删除test数据库
- mariadb 10.4.33(centos7安装的)
Enter current password for root (enter for none): #默认没密码,这里直接回车
You already have your root account protected, so you can safely answer 'n'.
Switch to unix_socket authentication [Y/n] #输入n(远程可以登录)
#mysql.sock 使用unix socket登录(只能在本地登录,不能远程登录);
/var/lib/mysql/mysql.sock文件
Change the root password? [Y/n] #输入y
New password: #输入密码:xyy520
Re-enter new password:
Remove anonymous users? [Y/n] #输入y
Disallow root login remotely? [Y/n] #输入y,禁用root远程登录
Remove test database and access to it? [Y/n] #输入y
Reload privilege tables now? [Y/n] #输入y(是否加载权限)
测试:
(直接空口令也是可以登录的……)
[root@linux-test ~]#mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 25
Server version: 10.4.33-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.4.33-MariaDB, for Linux (x86_64) using readline 5.1
Connection id: 25
Current database:
Current user: root@localhost #以root身份登录的:
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server: MariaDB
Server version: 10.4.33-MariaDB MariaDB Server
Protocol version: 10
Connection: Localhost via UNIX socket
Server characterset: latin1
Db characterset: latin1
Client characterset: utf8
Conn. characterset: utf8
UNIX socket: /var/lib/mysql/mysql.sock
Uptime: 1 day 3 hours 44 min 16 sec
Threads: 6 Questions: 180 Slow queries: 0 Opens: 37 Flush tables: 1 Open tables: 30 Queries per second avg: 0.001
--------------
MariaDB [(none)]>
#可以看到root是有口令的:(匿名账号也删除了)
MariaDB [mysql]> select user,host,password from user;
+-------------+-----------+-------------------------------------------+
| User | Host | Password |
+-------------+-----------+-------------------------------------------+
| mariadb.sys | localhost | |
| root | localhost | *ABE374A5F247C93961AD4726B39A5A84FA3BC3B1 |
| mysql | localhost | invalid |
+-------------+-----------+-------------------------------------------+
3 rows in set (0.001 sec)
MariaDB [mysql]>
#重启服务后,root还是可以直接免密登录数据库的:
[root@linux-test ~]#systemctl restart mariadb
[root@linux-test ~]#mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 8
Server version: 10.4.33-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)]>
因此,在本地,使用root用户,空口令是可以直接登录数据库的。(正常登录的话,root登录也是需要输入口令的!!!,其他版本是必须要输入口令才能登的)
[root@linux-test ~]#mysql -uroot -pxyy520 ##这里明确地输密码也是可以的。
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 9
Server version: 10.4.33-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)]>
[root@linux-test ~]#mysql -uroot
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 10
Server version: 10.4.33-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)]>
[root@linux-test ~]#mysql -uroot -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 11
Server version: 10.4.33-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)]>
退出shell后重新登陆,还是一样的效果。
当然,仅限于root
用户而言:(普通用户使用root去登录,不输入密码很定是有问题的)
[root@linux-test ~]#su - xyy
Last login: Fri Mar 29 07:43:03 CST 2024 on pts/1
[xyy@linux-test ~]$mysql -uroot -p
Enter password:
ERROR 1698 (28000): Access denied for user 'root'@'localhost'
[xyy@linux-test ~]$
[xyy@linux-test ~]$mysql -uroot -p
Enter password: ##输入正确密码后。
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 14
Server version: 10.4.33-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)]>
因此:
root是操作系统管理员,当然对mysql具有绝对的控制权哦。
另外,需要注意:
目前配置的策略是,只允许在本机登录数据库才行,远程是不允许被登录的。(只能单机使用,不能跨网络使用)
MariaDB [mysql]> select user,host,password from user;
+-------------+-----------+-------------------------------------------+
| User | Host | Password |
+-------------+-----------+-------------------------------------------+
| mariadb.sys | localhost | |
| root | localhost | *ABE374A5F247C93961AD4726B39A5A84FA3BC3B1 |
| mysql | localhost | invalid |
+-------------+-----------+-------------------------------------------+
3 rows in set (0.001 sec)
MariaDB [mysql]>
如果想要远程用户可以登录数据库,那么就要创建基于远程用户的登录:
localhost和127.0.0.1是不同的。
localhost代表的是走套接字方式(Localhost via UNIX socket)/var/lib/mysql/mysql.sock文件 (不存在封装&解封装过程)
127.0.0.1走的是本机127.0.0.1:3306端口(涉及TCP协议,封装&解封装流程)
它是2个渠道。
客户端和服务端进行连接,相当于是2个进程,一个是客户端(mysql),一个是服务端(mysqld),这两个进程之间通信,可以走unix套接字,也可以走3306端口。
如果只有mysql.socket套接字,那就只能支持本地连接,无法支持远程数据库连接了。
测试远程登录数据库:
[root@linux-test-2 ~]#mysql -uroot -pxyy520 -h172.29.9.31
ERROR 1130 (HY000): Host '172.29.9.32' is not allowed to connect to this MariaDB server
[root@linux-test-2 ~]#
[root@linux-test ~]#mysql
……
MariaDB [mysql]> select user,host,password from user;
+-------------+-----------+-------------------------------------------+
| User | Host | Password |
+-------------+-----------+-------------------------------------------+
| mariadb.sys | localhost | |
| root | localhost | *ABE374A5F247C93961AD4726B39A5A84FA3BC3B1 |
| mysql | localhost | invalid |
+-------------+-----------+-------------------------------------------+
3 rows in set (0.001 sec)
符合预期。
通过127.0.0.1和unix sokcet登录数据库:
[root@linux-test ~]#mysql
……
MariaDB [mysql]> select user,host,password from user;
+-------------+-----------+-------------------------------------------+
| User | Host | Password |
+-------------+-----------+-------------------------------------------+
| mariadb.sys | localhost | |
| root | localhost | *ABE374A5F247C93961AD4726B39A5A84FA3BC3B1 |
| mysql | localhost | invalid |
+-------------+-----------+-------------------------------------------+
3 rows in set (0.001 sec)
[root@linux-test ~]#mysql -uroot -pxyy520 -h127.0.0.1
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 10
Server version: 10.4.33-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.4.33-MariaDB, for Linux (x86_64) using readline 5.1
Connection id: 10
Current database:
Current user: root@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server: MariaDB
Server version: 10.4.33-MariaDB MariaDB Server
Protocol version: 10
Connection: 127.0.0.1 via TCP/IP
Server characterset: latin1
Db characterset: latin1
Client characterset: utf8
Conn. characterset: utf8
TCP port: 3306
Uptime: 3 min 49 sec
Threads: 6 Questions: 42 Slow queries: 0 Opens: 37 Flush tables: 1 Open tables: 30 Queries per second avg: 0.183
--------------
MariaDB [(none)]>
[root@linux-test ~]#mysql -uroot -pxyy520 -hlocalhost
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 11
Server version: 10.4.33-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)]> \s
--------------
mysql Ver 15.1 Distrib 10.4.33-MariaDB, for Linux (x86_64) using readline 5.1
Connection id: 11
Current database:
Current user: root@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server: MariaDB
Server version: 10.4.33-MariaDB MariaDB Server
Protocol version: 10
Connection: Localhost via UNIX socket
Server characterset: latin1
Db characterset: latin1
Client characterset: utf8
Conn. characterset: utf8
UNIX socket: /var/lib/mysql/mysql.sock
Uptime: 4 min 42 sec
Threads: 6 Questions: 46 Slow queries: 0 Opens: 37 Flush tables: 1 Open tables: 30 Queries per second avg: 0.163
--------------
MariaDB [(none)]>
MySQL 组成
客户端程序
- mysql: 交互式的CLI工具
- mysqldump:备份工具,基于mysql协议向mysqld发起查询请求,并将查得的所有数据转换成insert等写操作语句保存文本文件中
- mysqladmin:基于mysql协议管理mysqld
- mysqlimport:数据导入工具
- MyISAM存储引擎的管理工具:
- myisamchk:检查MyISAM库
- myisampack:打包MyISAM表,只读
服务器端程序
- mysqld_safe
- mysqld
- mysqld_multi 多实例 ,示例:mysqld_multi --example
用户账号
mysql用户账号由两部分组成: 'USERNAME'@'HOST‘
说明: HOST限制此用户可通过哪些远程主机连接mysql服务器 支持使用通配符:
% 匹配任意长度的任意字符
172.16.0.0/255.255.0.0 或 172.16.%.%
_ 匹配任意单个字符
mysql 客户端命令
mysql 运行命令类型
- 客户端命令:本地执行,每个命令都完整形式和简写格式
mysql> \h, help
mysql> \u,use
mysql> \s,status
mysql> \!,system
MariaDB [mysql]> help
General information about MariaDB can be found at
http://mariadb.org
List of all client commands:
Note that all text commands must be first on line and end with ';'
? (\?) Synonym for `help'.
clear (\c) Clear the current input statement.
connect (\r) Reconnect to the server. Optional arguments are db and host.
delimiter (\d) Set statement delimiter.
edit (\e) Edit command with $EDITOR.
ego (\G) Send command to MariaDB server, display result vertically.
exit (\q) Exit mysql. Same as quit. ##常用
go (\g) Send command to MariaDB server.
help (\h) Display this help. ##常用
nopager (\n) Disable pager, print to stdout.
notee (\t) Don't write into outfile.
pager (\P) Set PAGER [to_pager]. Print the query results via PAGER.
print (\p) Print current command.
prompt (\R) Change your mysql prompt.
quit (\q) Quit mysql.
rehash (\#) Rebuild completion hash.
source (\.) Execute an SQL script file. Takes a file name as an argument.
status (\s) Get status information from the server. ##常用
system (\!) Execute a system shell command.
tee (\T) Set outfile [to_outfile]. Append everything into given outfile.
use (\u) Use another database. Takes database name as argument.
charset (\C) Switch to another charset. Might be needed for processing binlog with multi-byte charsets.
warnings (\W) Show warnings after every statement.
nowarning (\w) Don't show warnings after every statement.
For server side help, type 'help contents'
MariaDB [mysql]>
举例:(和awk里的system()功能类似)
system (\!) Execute a system shell command.
MariaDB [(none)]> system ls
MariaDB [(none)]> system date
Sat Mar 30 12:17:32 CST 2024
MariaDB [(none)]> system pwd
/root
MariaDB [(none)]>
举例:
prompt (\R) Change your mysql prompt. #修改提示符
MariaDB [(none)]> (修改这里的提示符的,类似与PS1)
- 服务端命令:通过mysql协议发往服务器执行并取回结果,命令末尾都必须使用命令结束符号,默认为分号
#示例:
mysql>SELECT VERSION();
MariaDB [(none)]> show databases
-> ; ##必须要加;号才行,不然不给结束;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
+--------------------+
3 rows in set (0.001 sec)
MariaDB [(none)]>
mysql 使用模式
交互模式:
脚本模式:
mysql –uUSERNAME -pPASSWORD < /path/somefile.sql
cat /path/somefile.sql | mysql –uUSERNAME -pPASSWORD
mysql>source /path/from/somefile.sql
举例:
[root@linux-test ~]#mysql -uroot -pxyy520 < /tmp/test.sql
User Host
mariadb.sys localhost
mysql localhost
root localhost
[root@linux-test ~]#
[root@linux-test ~]#cat /tmp/test.sql |mysql -uroot -pxyy520
User Host
mariadb.sys localhost
mysql localhost
root localhost
[root@linux-test ~]#
mysql命令使用格式
mysql [OPTIONS] [database]
mysql客户端常用选项:
-A, --no-auto-rehash 禁止补全
-u, --user= 用户名,默认为root
-h, --host= 服务器主机,默认为localhost
-p, --passowrd= 用户密码,建议使用-p,默认为空密码
-P, --port= 服务器端口
-S, --socket= 指定连接socket文件路径
-D, --database= 指定默认数据库
-C, --compress 启用压缩
-e “SQL“ 执行SQL命令
-V, --version 显示版本
-v --verbose 显示详细信息
--print-defaults 获取程序默认使用的配置
登录系统:
#默认空密码登录
mysql –uroot –p
运行mysql命令:
mysql>use mysql
mysql>select user(); #查看当前用户
mysql>SELECT User,Host,Password FROM user;
范例:配置客户端mysql的自动登录
vim/etc/my.cnf.d/client.conf
[client]
user=wang
password=centos
服务器端配置
服务器端(mysqld):工作特性有多种配置方式
1、命令行选项:
2、配置文件:类ini格式,集中式的配置,能够为mysql的各应用程序提供配置信息
服务器端配置文件:
/etc/my.cnf #Global选项(主流)
/etc/mysql/my.cnf #Global选项
~/.my.cnf #User-specific 选项
配置文件格式:
[mysqld]
[mysqld_safe]
[mysqld_multi]
[mysql]
[mysqldump]
[server]
[client]
格式:parameter = value
说明:_和- 相同 (不区分)
1,ON,TRUE意义相同, 0,OFF,FALSE意义相同
mariadb 10.4.33
[root@linux-test ~]#ls /etc/my.cnf.d/server.cnf /etc/my.cnf.d/server.cnf
mariadb 10.3.17
socket地址
服务器监听的两种socket地址:
- ip socket: 监听在tcp的3306端口,支持远程通信 ,侦听3306/tcp端口可以在绑定有一个或全部接口IP上
- unix sock: 监听在sock文件上,仅支持本机通信, 如:/var/lib/mysql/mysql.sock)
说明:host为localhost 时自动使用unix sock
关闭mysqld网络连接
只侦听本地客户端, 所有客户端和服务器的交互都通过一个socket文件实现,socket的配置存放在/var/lib/mysql/mysql.sock) 可在/etc/my.cnf修改
范例:
#vim /etc/my.cnf
或者
vim /etc/my.cnf.d/server.cnf
[mysqld]
skip-networking=1
记得配置后,要重启maridb服务的:
systemctl restart mariadb
3、SQL语言
关系型数据库的常见组件
- 数据库:database
- 表:table,行:row 列:column
- 索引:index
- 视图:view
- 用户:user
- 权限:privilege
- 存储过程:procedure
- 存储函数:function
- 触发器:trigger
- 事件调度器:event scheduler,任务计划
SQL语言的兴起与语法标准
20世纪70年代,IBM开发出SQL,用于DB2
1981年,IBM推出SQL/DS数据库
业内标准微软和Sybase的T-SQL,Oracle的PL/SQL
SQL作为关系型数据库所使用的标准语言,最初是基于IBM的实现在1986年被批准的。1987年,国际标准化组织(ISO) 把ANSI(美国国家标准化组织) SQL作为国际标准
SQL:ANSI SQL,SQL-1986, SQL-1989, SQL-1992, SQL-1999, SQL-2003,SQL-2008, SQL-2011
SQL语言规范
在数据库系统中,SQL语句不区分大小写,建议用大写;
SQL语句可单行或多行书写,以“;”结尾
关键词不能跨多行或简写
用空格和缩进来提高语句的可读性
子句通常位于独立行,便于编辑,提高可读性
注释:
SQL标准:
-- 注释内容 单行注释,注意有空格
/*注释内容*/ 多行注释
MySQL注释:
# 注释内容
数据库对象和命名
数据库的组件(对象):
数据库、表、索引、视图、用户、存储过程、函数、触发器、事件调度器等
命名规则:
必须以字母开头,可包括数字和三个特殊字符(# _ $)
不要使用MySQL的保留字
同一database(Schema)下的对象不能同名
NOTE
在mysql里,Schema和database在数据库下是同义词。但在别的数据库里,不是同义词。
SQL语句分类
- DDL: Data Defination Language 数据定义语言
CREATE,DROP,ALTER(改表的结构)
- DML: Data Manipulation Language 数据操纵语言
INSERT,DELETE,UPDATE
- DQL:Data Query Language 数据查询语言
SELECT
- DCL:Data Control Language 数据控制语言
GRANT(授权),REVOKE(取消),COMMIT,ROLLBACK(撤销)
软件开发:CRUD (R:recieve)
NOTE
面试会经常问到这块儿。
SQL语句构成
关健字Keyword组成子句clause,多条clause组成语句
示例:
SELECT * #SELECT子句
FROM products #FROM子句
WHERE price>400 #WHERE子句
说明:一组SQL语句,由三个子句构成,SELECT,FROM和WHERE是关键字
数据库操作
管理数据库
创建数据库
CREATE DATABASE|SCHEMA [IF NOT EXISTS] 'DB_NAME'
CHARACTER SET 'character set name'
COLLATE 'collate name';
CREATE DATABASE|SCHEMA [IF NOT EXISTS] 'DB_NAME';
CREATE DATABASE|SCHEMA 'DB_NAME';
🍊 范例:创建数据库
mysql> create database db1;
Query OK, 1 row affected (0.00 sec)
mysql> show create database db1;
+----------+-----------------------------------------------------------------+
| Database | Create Database |
+----------+-----------------------------------------------------------------+
| db1 | CREATE DATABASE `db1` /*!40100 DEFAULT CHARACTER SET utf8mb4 */ |
+----------+-----------------------------------------------------------------+
1 row in set (0.00 sec)
mysql>
[root@linux-test ~]#cat /data/mysql/db1/db.opt
default-character-set=utf8mb4
default-collation=utf8mb4_general_ci
[root@linux-test ~]#
mysql> create database db1;
ERROR 1007 (HY000): Can't create database 'db1'; database exists
mysql> create database IF NOT EXISTS db1;
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> show warnings;
+-------+------+----------------------------------------------+
| Level | Code | Message |
+-------+------+----------------------------------------------+
| Note | 1007 | Can't create database 'db1'; database exists |
+-------+------+----------------------------------------------+
1 row in set (0.00 sec)
mysql>
🍊 范例:指定字符集创建新数据库
mysql> create database IF NOT EXISTS db2 CHARACTER SET 'utf8';
Query OK, 1 row affected (0.01 sec)
mysql> show create database db2;
+----------+--------------------------------------------------------------+
| Database | Create Database |
+----------+--------------------------------------------------------------+
| db2 | CREATE DATABASE `db2` /*!40100 DEFAULT CHARACTER SET utf8 */ |
+----------+--------------------------------------------------------------+
1 row in set (0.00 sec)
mysql>
default-character-set=utf8
default-collation=utf8_general_ci
[root@linux-test ~]#
修改数据库
ALTER DATABASE DB_NAME character set utf8;
NOTE
修改字符集后,此刻数据库里会存在2种类型字符集,刚修改的只会对新数据产生影响,老的数据会保持旧字符集不变,可能会出现乱码问题,因此最好在创建数据库时就规划好字符集。
🍊 范例:修改数据库的字符集
mysql> show create database db1;
+----------+-----------------------------------------------------------------+
| Database | Create Database |
+----------+-----------------------------------------------------------------+
| db1 | CREATE DATABASE `db1` /*!40100 DEFAULT CHARACTER SET utf8mb4 */ |
+----------+-----------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> alter database db1 character set utf8;
Query OK, 1 row affected (0.00 sec)
mysql> show create database db1;
+----------+--------------------------------------------------------------+
| Database | Create Database |
+----------+--------------------------------------------------------------+
| db1 | CREATE DATABASE `db1` /*!40100 DEFAULT CHARACTER SET utf8 */ |
+----------+--------------------------------------------------------------+
1 row in set (0.00 sec)
mysql>
[root@linux-test ~]#cat /data/mysql/db1/db.opt
default-character-set=utf8
default-collation=utf8_general_ci
[root@linux-test ~]#
删除数据库
DROP DATABASE|SCHEMA [IF EXISTS] 'DB_NAME';
🍊 范例:删除数据库
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db1 |
| db2 |
| mysql |
| performance_schema |
+--------------------+
5 rows in set (0.00 sec)
mysql> drop database db1;
Query OK, 0 rows affected (0.02 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db2 |
| mysql |
| performance_schema |
+--------------------+
4 rows in set (0.00 sec)
mysql>
[root@linux-test ~]#ls /data/mysql/db1
ls: cannot access /data/mysql/db1: No such file or directory
[root@linux-test ~]#
🍊 范例:如果在数据库目录里创建一个文件,删除数据库后,还能删除这个数据库目录吗
[root@linux-test ~]#ll /data/mysql/db2
total 4
-rw-rw---- 1 mysql mysql 61 Apr 23 07:04 db.opt
[root@linux-test ~]#touch /data/mysql/db2/xxx.txt
[root@linux-test ~]#ll /data/mysql/db2
total 4
-rw-rw---- 1 mysql mysql 61 Apr 23 07:04 db.opt
-rw-r--r-- 1 root root 0 Apr 23 07:25 xxx.txt
[root@linux-test ~]#
mysql> drop database db2;
ERROR 1010 (HY000): Error dropping database (can't rmdir './db2/', errno: 17)
mysql>
#修改权限
[root@linux-test ~]#ll /data/mysql/db2
total 0
-rw-r--r-- 1 root root 0 Apr 23 07:25 xxx.txt
[root@linux-test ~]#chown -R mysql.mysql /data/mysql/
[root@linux-test ~]#ll /data/mysql/db2
total 0
-rw-r--r-- 1 mysql mysql 0 Apr 23 07:25 xxx.txt
[root@linux-test ~]#
#再次删除还是报错……
mysql> drop database db2;
ERROR 1010 (HY000): Error dropping database (can't rmdir './db2/', errno: 17)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db2 |
| mysql |
| performance_schema |
+--------------------+
4 rows in set (0.00 sec)
mysql>
🍊 范例:删除mysql数据库(自杀)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db2 |
| mysql |
| performance_schema |
+--------------------+
4 rows in set (0.00 sec)
mysql> drop database mysql;
Query OK, 28 rows affected, 2 warnings (0.03 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db2 |
| performance_schema |
+--------------------+
3 rows in set (0.00 sec)
mysql>
##删除mysql数据库后,停止mysql服务再次启动后,会报错的,完了,mysql废了哈哈😂
[root@linux-test ~]#systemctl status mysql
● mysqld.service - LSB: start and stop MySQL
Loaded: loaded (/etc/rc.d/init.d/mysqld; bad; vendor preset: disabled)
Active: active (running) since Tue 2024-04-23 06:40:40 CST; 47min ago
Docs: man:systemd-sysv-generator(8)
Process: 6518 ExecStart=/etc/rc.d/init.d/mysqld start (code=exited, status=0/SUCCESS)
CGroup: /system.slice/mysqld.service
├─6536 /bin/sh /usr/local/mysql/bin/mysqld_safe --datadir=/data/mysql --pid-file=/data/mysql/linux...
└─6788 /usr/local/mysql/bin/mysqld --basedir=/usr/local/mysql --datadir=/data/mysql --plugin-dir=/...
Apr 23 06:40:40 linux-test systemd[1]: Starting LSB: start and stop MySQL...
Apr 23 06:40:40 linux-test mysqld[6518]: Starting MySQL SUCCESS!
Apr 23 06:40:40 linux-test systemd[1]: Started LSB: start and stop MySQL.
[root@linux-test ~]#systemctl stop mysql
[root@linux-test ~]#systemctl start mysql
Job for mysqld.service failed because the control process exited with error code. See "systemctl status mysqld.service" and "journalctl -xe" for details.
[root@linux-test ~]#
[root@linux-test ~]#netstat -ntlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 6514/sshd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 6877/master
tcp6 0 0 :::22 :::* LISTEN 6514/sshd
tcp6 0 0 ::1:25 :::* LISTEN 6877/master
[root@linux-test ~]#
查看数据库列表
SHOW DATABASES;
🍊 范例:查看数据库列表
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db1 |
| db2 |
| mysql |
| performance_schema |
+--------------------+
5 rows in set (0.00 sec)
mysql>
数据类型
数据类型:
数据长什么样
数据需要多少空间来存放
数据类型
系统内置数据类型
用户定义数据类型
MySQL支持多种内置数据类型
数值类型
日期/时间类型
字符串(字符)类型
数据类型参考链接
https://dev.mysql.com/doc/refman/8.0/en/data-types.html
tinyint:2^8-1=255 -127到+128 符号位
unsigned 无符号位;
截断;
选择正确的数据类型对于获得高性能至关重要,三大原则:
- 更小的通常更好,尽量使用可正确存储数据的最小数据类型
- 简单就好,简单数据类型的操作通常需要更少的CPU周期
- 尽量避免NULL,包含为NULL的列,对MySQL更难优化
整数型
tinyint(m) 1个字节 范围(-128~127)
smallint(m) 2个字节 范围(-32768~32767)
mediumint(m) 3个字节 范围(-8388608~8388607)
int(m) 4个字节 范围(-2147483648~2147483647)
bigint(m) 8个字节 范围(+-9.22*10的18次方
)
上述数据类型,如果加修饰符unsigned后,则最大值翻倍
如:tinyint unsigned的取值范围为(0~255)
int(m)里的m是表示SELECT查询结果集中的显示宽度,并不影响实际的取值范围,规定了MySQL的一些交互工具(例如MySQL命令行客户端)用来显示字符的个数。对于存储和计算来说,Int(1)和Int(20)是相同的
BOOL,BOOLEAN:布尔型,是TINYINT(1)的同义词。zero值被视为假,非zero值视为真。
浮点型(float和double),近似值
float(m,d) 单精度浮点型 8位精度(4字节) m总个数,d小数位
double(m,d) 双精度浮点型16位精度(8字节) m总个数,d小数位
设一个字段定义为float(6,3),如果插入一个数123.45678,实际数据库里存的是123.457,但总个数还以实际为准,即6位
定点数
在数据库中存放的是精确值,存为十进制
decimal(m,d) 参数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。
字符串(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
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数据类型。
二进制数据BLOB
BLOB和text存储方式不同,TEXT以文本方式存储,英文存储区分大小写,而Blob以二进制方式存储,不分大小写
BLOB存储的数据只能整体读出
TEXT可以指定字符集,BLOB不用指定字符集
日期时间类型
date 日期 '2008-12-2'
time 时间 '12:25:36'
datetime 日期时间 '2008-12-2 22:06:44'
timestamp 自动存储记录修改时间
YEAR(2), YEAR(4):年份
timestamp字段里的时间数据会随其他字段修改的时候自动刷新,这个数据类型的字段可以存放这条记录最后被修改的时间
修饰符
适用所有类型的修饰符:
NULL 数据列可包含NULL值,默认值
NOT NULL 数据列不允许包含NULL值,为必填选项
DEFAULT 默认值
PRIMARY KEY 主键,所有记录中此字段的值不能重复,且不能为NULL
UNIQUE KEY 唯一键,所有记录中此字段的值不能重复,但可以为NULL
CHARACTER SET name 指定一个字符集
适用数值型的修饰符:
AUTO_INCREMENT 自动递增,适用于整数类型
UNSIGNED 无符号
DDL语句
表:二维关系
设计表:遵循规范
定义:字段,索引
- 字段:字段名,字段数据类型,修饰符
- 约束,索引:应该创建在经常用作查询条件的字段上
创建表
创建表:
CREATE TABLE
获取帮助:
HELP CREATE TABLE
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是指表类型,也即在表创建时指明其使用的存储引擎
- 同一库中不同表可以使用不同的存储引擎
- 同一个库中表建议要使用同一种存储引擎类型
方式1:直接创建(常用)
范例:表的创建和修改
CREATE TABLE student (
id int UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20) NOT NULL,
age tinyint UNSIGNED,
gender ENUM('M','F') default 'M'
)ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
范例:
student | CREATE TABLE `student` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) CHARACTER SET utf8 NOT NULL,
`age` tinyint(3) unsigned DEFAULT NULL,
`gender` enum('M','F') CHARACTER SET utf8 DEFAULT 'M',
PRIMARY KEY (`id`)
) ;
测试过程:
##创建表
mysql> CREATE TABLE student (
-> id int UNSIGNED AUTO_INCREMENT PRIMARY KEY,
-> name VARCHAR(20) NOT NULL,
-> age tinyint UNSIGNED,
-> gender ENUM('M','F') default 'M'
-> )ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.00 sec)
#id字段以10初始值
##查看表结构
mysql> desc student;
+--------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(20) | NO | | NULL | |
| age | tinyint(3) unsigned | YES | | NULL | |
| gender | enum('M','F') | YES | | M | |
+--------+---------------------+------+-----+---------+----------------+
4 rows in set (0.01 sec)
mysql>
#说明:enum 是枚举类型。 括号里的数字不是字节大小,而是代表的对其宽度;
##查看表内容
mysql> select * from student;
Empty set (0.00 sec)
##修改表
mysql> insert student (name,age)values('xiaoming',20);
Query OK, 1 row affected (0.00 sec)
mysql> select * from student;
+----+----------+------+--------+
| id | name | age | gender |
+----+----------+------+--------+
| 10 | xiaoming | 20 | M |
+----+----------+------+--------+
1 row in set (0.00 sec)
mysql> insert student (name,age,gender)values('xiaohong',18,'f'); ##注意:枚举类型,这里小写字母f或者大写字母F都是可以的;
Query OK, 1 row affected (0.00 sec)
mysql> select * from student;
+----+----------+------+--------+
| id | name | age | gender |
+----+----------+------+--------+
| 10 | xiaoming | 20 | M |
| 11 | xiaohong | 18 | F |
+----+----------+------+--------+
2 rows in set (0.00 sec)
mysql>
🍊 范例:创建复合主键
CREATE TABLE employee (id int UNSIGNED NOT NULL ,name VARCHAR(20) NOT NULL,age tinyint UNSIGNED,PRIMARY KEY(id,name));
🍊 范例:auto_increment 属性
demo1:
# auto_increment_offset 定义初始值
# auto_increment_increment 定义步进
mysql> SHOW VARIABLES LIKE 'auto_inc%';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| auto_increment_increment | 1 |
| auto_increment_offset | 1 |
+--------------------------+-------+
2 rows in set (0.00 sec)
##设置auto_increment 属性
mysql> SET @@auto_increment_increment=10;
Query OK, 0 rows affected (0.00 sec)
mysql> SET @@auto_increment_offset=3;
Query OK, 0 rows affected (0.00 sec)
mysql> SHOW VARIABLES LIKE 'auto_inc%';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| auto_increment_increment | 10 |
| auto_increment_offset | 3 |
+--------------------------+-------+
2 rows in set (0.00 sec)
##创建表和修改表
mysql> CREATE TABLE autoinc1 (col INT NOT NULL AUTO_INCREMENT PRIMARY KEY);
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO autoinc1 VALUES (NULL), (NULL), (NULL), (NULL); ##代表插入4条数据
Query OK, 4 rows affected (0.01 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM autoinc1;
+-----+
| col |
+-----+
| 3 |
| 13 |
| 23 |
| 33 |
+-----+
4 rows in set (0.00 sec)
mysql>
demo2:
🍊 范例:表的创建及auto_increment测试
```sql
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);
Query OK, 0 rows affected (0.02 sec)
mysql> desc t1;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
+-------+------------------+------+-----+---------+----------------+
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 |
+----+
| 1 |
+----+
1 row in set (0.00 sec)
#又插入一条
mysql> insert into t1 values(null);
Query OK, 1 row affected (0.01 sec)
mysql> select * from t1;
+----+
| id |
+----+
| 1 |
| 2 |
+----+
2 rows in set (0.00 sec)
##测试auto_increment
mysql> create table t2(id int unsigned auto_increment primary key) auto_increment = 4294967294;
Query OK, 0 rows affected (0.00 sec)
mysql> desc t2;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
+-------+------------------+------+-----+---------+----------------+
1 row in set (0.00 sec)
mysql> insert into t2 values(null);
Query OK, 1 row affected (0.00 sec)
mysql> select * from t2;
+------------+
| id |
+------------+
| 4294967294 |
+------------+
1 row in set (0.00 sec)
mysql> insert into t2 values(null);
Query OK, 1 row affected (0.00 sec)
mysql> select * from t2;
+------------+
| id |
+------------+
| 4294967294 |
| 4294967295 |
+------------+
2 rows in set (0.00 sec)
mysql> insert into t2 values(null);
ERROR 1062 (23000): Duplicate entry '4294967295' for key 'PRIMARY'
mysql>
##说明
int(10) unsigned 4个字节
0~4294967295
[root@linux-test ~]#echo 2^32|bc
4294967296
[root@linux-test ~]#
```
🍊 范例:timestamp修饰符
mysql> create table testdate (id int auto_increment primary key,date timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL);
测试过程:
##创建表
mysql> create table testdate (id int auto_increment primary key,date timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL);
Query OK, 0 rows affected (0.02 sec)
##插入数据
mysql> insert testdate (id)values(1);
Query OK, 1 row affected (0.01 sec)
mysql> insert testdate (id)values(2);
Query OK, 1 row affected (0.00 sec)
mysql> insert testdate (id)values(3);
Query OK, 1 row affected (0.01 sec)
mysql> insert testdate (id)values(4);
Query OK, 1 row affected (0.00 sec)
##查询表
mysql> select * from testdate;
+----+---------------------+
| id | date |
+----+---------------------+
| 1 | 2024-04-27 13:35:20 |
| 2 | 2024-04-27 13:35:22 |
| 3 | 2024-04-27 13:35:24 |
| 4 | 2024-04-27 13:35:27 |
+----+---------------------+
4 rows in set (0.00 sec)
mysql>
方式2: 通过查询现存表创建;新表会被直接插入查询而来的数据
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)]
[table_options]
[partition_options] select_statement
范例:
##当前表:
mysql> desc testdate;
+-------+-----------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| date | timestamp | NO | | CURRENT_TIMESTAMP | |
+-------+-----------+------+-----+-------------------+----------------+
2 rows in set (0.00 sec)
mysql> select * from testdate;
+----+---------------------+
| id | date |
+----+---------------------+
| 1 | 2024-04-27 13:35:20 |
| 2 | 2024-04-27 13:35:22 |
| 3 | 2024-04-27 13:35:24 |
| 4 | 2024-04-27 13:35:27 |
+----+---------------------+
4 rows in set (0.00 sec)
##新创建表
mysql> create table testdate2 select * from testdate;
Query OK, 4 rows affected (0.02 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> desc testdate2;
+-------+-----------+------+-----+-------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------+------+-----+-------------------+-------+
| id | int(11) | NO | | 0 | |
| date | timestamp | NO | | CURRENT_TIMESTAMP | |
+-------+-----------+------+-----+-------------------+-------+
2 rows in set (0.00 sec)
mysql> select * from testdate2;
+----+---------------------+
| id | date |
+----+---------------------+
| 1 | 2024-04-27 13:35:20 |
| 2 | 2024-04-27 13:35:22 |
| 3 | 2024-04-27 13:35:24 |
| 4 | 2024-04-27 13:35:27 |
+----+---------------------+
4 rows in set (0.00 sec)
#注意:新创建的表里的数据和原表一致,只是表结构里可能会缺少一些属性值;
mysql> desc testdate;
+-------+-----------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| date | timestamp | NO | | CURRENT_TIMESTAMP | |
+-------+-----------+------+-----+-------------------+----------------+
2 rows in set (0.00 sec)
mysql> desc testdate2;
+-------+-----------+------+-----+-------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------+------+-----+-------------------+-------+
| id | int(11) | NO | | 0 | |
| date | timestamp | NO | | CURRENT_TIMESTAMP | |
+-------+-----------+------+-----+-------------------+-------+
2 rows in set (0.00 sec)
方式3:通过复制现存的表的表结构创建,但不复制数据
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name { LIKE old_tbl_name | (LIKEold_tbl_name) }
范例:
##老表
mysql> desc testdate;
+-------+-----------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| date | timestamp | NO | | CURRENT_TIMESTAMP | |
+-------+-----------+------+-----+-------------------+----------------+
2 rows in set (0.00 sec)
mysql> select * from testdate;
+----+---------------------+
| id | date |
+----+---------------------+
| 1 | 2024-04-27 13:35:20 |
| 2 | 2024-04-27 13:35:22 |
| 3 | 2024-04-27 13:35:24 |
| 4 | 2024-04-27 13:35:27 |
+----+---------------------+
4 rows in set (0.00 sec)
##新表
mysql> create table testdate3 like testdate;
Query OK, 0 rows affected (0.00 sec)
mysql> desc testdate3;
+-------+-----------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| date | timestamp | NO | | CURRENT_TIMESTAMP | |
+-------+-----------+------+-----+-------------------+----------------+
2 rows in set (0.00 sec)
mysql> select * from testdate3;
Empty set (0.00 sec)
#说明:通过这种方式创建的表,数据为空,但表结构和老表完全一致。
表查看
- 查看支持的engine类型
SHOW ENGINES;
- 查看表:
SHOW TABLES [FROM db_name]
范例:
mysql> SHOW TABLES;
+----------------+
| Tables_in_test |
+----------------+
| autiinc1 |
| autoinc1 |
| student |
| t1 |
| t2 |
| testdate |
| testdate2 |
| testdate3 |
+----------------+
8 rows in set (0.00 sec)
- 查看表结构:
DESC [db_name.]tb_name
SHOW COLUMNS FROM [db_name.]tb_name
范例:
mysql> desc testdate;
+-------+-----------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| date | timestamp | NO | | CURRENT_TIMESTAMP | |
+-------+-----------+------+-----+-------------------+----------------+
2 rows in set (0.00 sec)
mysql> show columns from testdate;
+-------+-----------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| date | timestamp | NO | | CURRENT_TIMESTAMP | |
+-------+-----------+------+-----+-------------------+----------------+
2 rows in set (0.00 sec)
- 查看表创建命令:
SHOW CREATE TABLE tbl_name
范例:
mysql> 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=12 DEFAULT CHARSET=utf8 |
+---------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> select * from stu
+----+----------+------+
| id | name | age |
+----+----------+------+
| 10 | xiaoming | 20 |
| 11 | xiaohong | 18 |
+----+----------+------+
2 rows in set (0.00 sec)
- 查看表状态:
SHOW TABLE STATUS LIKE 'student'\G
范例:
mysql> SHOW TABLE STATUS LIKE 'student'\G
*************************** 1. row ***************************
Name: student
Engine: InnoDB
Version: 10
Row_format: Compact
Rows: 2
Avg_row_length: 8192
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: 12
Create_time: 2024-04-27 09:10:06
Update_time: NULL
Check_time: NULL
Collation: utf8_general_ci
Checksum: NULL
Create_options:
Comment:
1 row in set (0.00 sec)
mysql>
- 查看库中所有表状态
SHOW TABLE STATUS FROM db_name;
范例:
mysql> show table status from test\G;
*************************** 1. row ***************************
Name: autiinc1
Engine: InnoDB
Version: 10
Row_format: Compact
Rows: 0
Avg_row_length: 0
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: 1
Create_time: 2024-04-27 09:29:38
Update_time: NULL
Check_time: NULL
Collation: latin1_swedish_ci
Checksum: NULL
Create_options:
Comment:
*************************** 2. row ***************************
Name: autoinc1
Engine: InnoDB
Version: 10
Row_format: Compact
Rows: 4
Avg_row_length: 4096
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: 43
Create_time: 2024-04-27 09:32:21
Update_time: NULL
Check_time: NULL
Collation: latin1_swedish_ci
Checksum: NULL
Create_options:
Comment:
*************************** 3. row ***************************
Name: student
Engine: InnoDB
Version: 10
Row_format: Compact
Rows: 2
Avg_row_length: 8192
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: 12
Create_time: 2024-04-27 09:10:06
Update_time: NULL
Check_time: NULL
Collation: utf8_general_ci
Checksum: NULL
Create_options:
Comment:
……
修改和删除表
- 删除表
DROP TABLE [IF EXISTS] 'tbl_name';
范例:
mysql> drop table autoinc1; ##就是删除了mysql目录对应表的2个文件
Query OK, 0 rows affected (0.00 sec)
mysql>
- 修改表
ALTER TABLE 'tbl_name'
#字段:
#添加字段:add
ADD col1 data_type [FIRST|AFTER col_name]
#删除字段:drop
#修改字段:
alter(默认值), change(字段名), modify(字段属性)
范例:添加字段:add
mysql> alter table student add mobile char(11) not null default '13801380000' after name;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> select *from student;
+----+----------+-------------+------+--------+
| id | name | mobile | age | gender |
+----+----------+-------------+------+--------+
| 10 | xiaoming | 13801380000 | 20 | M |
| 11 | xiaohong | 13801380000 | 18 | F |
+----+----------+-------------+------+--------+
2 rows in set (0.00 sec)
mysql>
范例:修改字段属性
mysql> alter table student modify mobile char(12);
Query OK, 2 rows affected (0.02 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> desc student;
+--------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(20) | NO | | NULL | |
| mobile | char(12) | YES | | NULL | |
| age | tinyint(3) unsigned | YES | | NULL | |
| gender | enum('M','F') | YES | | M | |
+--------+---------------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
mysql>
范例:删除表的某一列
mysql> select *from student;
+----+----------+-------------+------+--------+
| id | name | mobile | age | gender |
+----+----------+-------------+------+--------+
| 10 | xiaoming | 13801380000 | 20 | M |
| 11 | xiaohong | 13801380000 | 18 | F |
+----+----------+-------------+------+--------+
2 rows in set (0.00 sec)
mysql> alter table student drop column mobile;
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> select *from student;
+----+----------+------+--------+
| id | name | age | gender |
+----+----------+------+--------+
| 10 | xiaoming | 20 | M |
| 11 | xiaohong | 18 | F |
+----+----------+------+--------+
2 rows in set (0.00 sec)
- 查看修改表帮助
Help ALTER TABLE
- 修改表范例
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');
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 s1 character set utf8;
DML语句
DML: INSERT, DELETE, UPDATE
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,...)
方法1:
🍊 范例:省略col_name,给所有value赋值
mysql> select *from student;
+----+----------+------+--------+
| id | name | age | gender |
+----+----------+------+--------+
| 10 | xiaoming | 20 | M |
| 11 | xiaohong | 18 | F |
+----+----------+------+--------+
2 rows in set (0.00 sec)
mysql> insert student value (1,'xyy',18,'F');
Query OK, 1 row affected (0.02 sec)
mysql> select *from student;
+----+----------+------+--------+
| id | name | age | gender |
+----+----------+------+--------+
| 1 | xyy | 18 | F |
| 10 | xiaoming | 20 | M |
| 11 | xiaohong | 18 | F |
+----+----------+------+--------+
3 rows in set (0.00 sec)
🍊 范例:给部分列属性赋值
mysql> select *from student;
+----+----------+------+--------+
| id | name | age | gender |
+----+----------+------+--------+
| 1 | xyy | 18 | F |
| 10 | xiaoming | 20 | M |
| 11 | xiaohong | 18 | F |
+----+----------+------+--------+
3 rows in set (0.00 sec)
mysql> insert student (name,age,gender) value ('hg',19,'M');
Query OK, 1 row affected (0.02 sec)
mysql> select *from student;
+----+----------+------+--------+
| id | name | age | gender |
+----+----------+------+--------+
| 1 | xyy | 18 | F |
| 10 | xiaoming | 20 | M |
| 11 | xiaohong | 18 | F |
| 12 | hg | 19 | M |
+----+----------+------+--------+
4 rows in set (0.00 sec)
🍊 范例:给部分列属性赋值,并一次性添加多条记录。
mysql> select *from student;
+----+----------+------+--------+
| id | name | age | gender |
+----+----------+------+--------+
| 1 | xyy | 18 | F |
| 10 | xiaoming | 20 | M |
| 11 | xiaohong | 18 | F |
| 12 | hg | 19 | M |
+----+----------+------+--------+
4 rows in set (0.00 sec)
mysql> insert student (name,age,gender) value ('lianlian',18,'F'),('xiaoxiao',18,'F'),('yanyan',19,'F');
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select *from student;
+----+----------+------+--------+
| id | name | age | gender |
+----+----------+------+--------+
| 1 | xyy | 18 | F |
| 10 | xiaoming | 20 | M |
| 11 | xiaohong | 18 | F |
| 12 | hg | 19 | M |
| 13 | lianlian | 18 | F |
| 14 | xiaoxiao | 18 | F |
| 15 | yanyan | 19 | F |
+----+----------+------+--------+
7 rows in set (0.00 sec)
方法2:
🍊 范例:利用旧表的数据批量地导入
mysql> create table student2 like student;
Query OK, 0 rows affected (0.02 sec)
mysql> select *from student2;
Empty set (0.00 sec)
mysql> insert student2 select *from student;
Query OK, 7 rows affected (0.01 sec)
Records: 7 Duplicates: 0 Warnings: 0
mysql> select *from student2;
+----+----------+------+--------+
| id | name | age | gender |
+----+----------+------+--------+
| 1 | xyy | 18 | F |
| 10 | xiaoming | 20 | M |
| 11 | xiaohong | 18 | F |
| 12 | hg | 19 | M |
| 13 | lianlian | 18 | F |
| 14 | xiaoxiao | 18 | F |
| 15 | yanyan | 19 | F |
+----+----------+------+--------+
7 rows in set (0.00 sec)
方法3:set方式
mysql> insert student set name='hao',age=22,gender='M';
范例:
mysql> insert student set name='hao',age=22,gender='M';
Query OK, 1 row affected (0.01 sec)
mysql> select *from student;
+----+----------+------+--------+
| id | name | age | gender |
+----+----------+------+--------+
| 1 | xyy | 18 | F |
| 10 | xiaoming | 20 | M |
| 11 | xiaohong | 18 | F |
| 12 | hg | 19 | M |
| 13 | lianlian | 18 | F |
| 14 | xiaoxiao | 18 | F |
| 15 | yanyan | 19 | F |
| 16 | hao | 22 | M |
+----+----------+------+--------+
8 rows in set (0.00 sec)
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
🍊 范例:更新某个单元格的数据
mysql> select *from student;
+----+----------+------+--------+
| id | name | age | gender |
+----+----------+------+--------+
| 1 | xyy | 18 | F |
| 10 | xiaoming | 20 | M |
| 11 | xiaohong | 18 | F |
| 12 | hg | 19 | M |
| 13 | lianlian | 18 | F |
| 14 | xiaoxiao | 18 | F |
| 15 | yanyan | 19 | F |
| 16 | hao | 22 | M |
+----+----------+------+--------+
8 rows in set (0.00 sec)
#mysql> update student set age=18; ##这个是灾难性的后果,会修改该列的所有值的;
mysql> update student set age=18 where id=15;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select *from student;
+----+----------+------+--------+
| id | name | age | gender |
+----+----------+------+--------+
| 1 | xyy | 18 | F |
| 10 | xiaoming | 20 | M |
| 11 | xiaohong | 18 | F |
| 12 | hg | 19 | M |
| 13 | lianlian | 18 | F |
| 14 | xiaoxiao | 18 | F |
| 15 | yanyan | 18 | F |
| 16 | hao | 22 | M |
+----+----------+------+--------+
8 rows in set (0.00 sec)
🍊 范例:多个字段同时修改
mysql> update student set age=28,gender='F' where id=16;
mysql> select *from student;
+----+----------+------+--------+
| id | name | age | gender |
+----+----------+------+--------+
| 1 | xyy | 18 | F |
| 10 | xiaoming | 20 | M |
| 11 | xiaohong | 18 | F |
| 12 | hg | 19 | M |
| 13 | lianlian | 18 | F |
| 14 | xiaoxiao | 18 | F |
| 15 | yanyan | 18 | F |
| 16 | hao | 22 | M |
+----+----------+------+--------+
8 rows in set (0.00 sec)
mysql> update student set age=28,gender='F' where id=16;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select *from student;
+----+----------+------+--------+
| id | name | age | gender |
+----+----------+------+--------+
| 1 | xyy | 18 | F |
| 10 | xiaoming | 20 | M |
| 11 | xiaohong | 18 | F |
| 12 | hg | 19 | M |
| 13 | lianlian | 18 | F |
| 14 | xiaoxiao | 18 | F |
| 15 | yanyan | 18 | F |
| 16 | hao | 28 | F |
+----+----------+------+--------+
8 rows in set (0.00 sec)
mysql>
🍊 范例:模拟灾难性更新效果
mysql> update student set age=8;
##当前表信息
mysql> select *from student;
+----+----------+------+--------+
| id | name | age | gender |
+----+----------+------+--------+
| 1 | xyy | 18 | F |
| 10 | xiaoming | 20 | M |
| 11 | xiaohong | 18 | F |
| 12 | hg | 19 | M |
| 13 | lianlian | 18 | F |
| 14 | xiaoxiao | 18 | F |
| 15 | yanyan | 18 | F |
| 16 | hao | 28 | F |
+----+----------+------+--------+
8 rows in set (0.00 sec)
##灾难性更新
mysql> update student set age=8;
Query OK, 8 rows affected (0.00 sec)
Rows matched: 8 Changed: 8 Warnings: 0
##查询
mysql> select *from student;
+----+----------+------+--------+
| id | name | age | gender |
+----+----------+------+--------+
| 1 | xyy | 8 | F |
| 10 | xiaoming | 8 | M |
| 11 | xiaohong | 8 | F |
| 12 | hg | 8 | M |
| 13 | lianlian | 8 | F |
| 14 | xiaoxiao | 8 | F |
| 15 | yanyan | 8 | F |
| 16 | hao | 8 | F |
+----+----------+------+--------+
8 rows in set (0.00 sec)
如何避免这个问题呢?
mysql -U | --safe-updates| --i-am-a-dummy
[root@centos8 ~]#vim /etc/my.cnf
[mysql]
safe-updates
方法1:加上-U选项
[root@linux-test ~]#mysql -uroot -pxyy520 -U
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 9
Server version: 5.6.47 MySQL Community Server (GPL)
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> use test
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
mysql> update student set age=18;
ERROR 1175 (HY000): You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column
mysql>
方法2:写到mysql配置文件里
[root@linux-test ~]#vim /etc/my.cnf
[mysql]
safe-updates
然后再次测试:
[root@linux-test ~]#mysql -uroot -pxyy520
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 10
Server version: 5.6.47 MySQL Community Server (GPL)
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> use test
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
mysql> select *from student;
+----+----------+------+--------+
| id | name | age | gender |
+----+----------+------+--------+
| 1 | xyy | 8 | F |
| 10 | xiaoming | 8 | M |
| 11 | xiaohong | 8 | F |
| 12 | hg | 8 | M |
| 13 | lianlian | 8 | F |
| 14 | xiaoxiao | 8 | F |
| 15 | yanyan | 8 | F |
| 16 | hao | 8 | F |
+----+----------+------+--------+
8 rows in set (0.00 sec)
mysql> update student set age=18;
ERROR 1175 (HY000): You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column
mysql>
#符合预期。
DELETE语句
删除表中数据,但不会自动缩减数据文件的大小。
语法:
DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name
[WHERE where_condition]
[ORDER BY ...]
[LIMIT row_count]
可先排序再指定删除的行数
注意:一定要有限制条件,否则将清空表中的所有数据
🍊 范例:删除表里某行数据
mysql> delete from student where id=16;
mysql> select *from student;
+----+----------+------+--------+
| id | name | age | gender |
+----+----------+------+--------+
| 1 | xyy | 8 | F |
| 10 | xiaoming | 8 | M |
| 11 | xiaohong | 8 | F |
| 12 | hg | 8 | M |
| 13 | lianlian | 8 | F |
| 14 | xiaoxiao | 8 | F |
| 15 | yanyan | 8 | F |
| 16 | hao | 8 | F |
+----+----------+------+--------+
8 rows in set (0.00 sec)
mysql> delete from student where id=16;
Query OK, 1 row affected (0.02 sec)
mysql> select *from student;
+----+----------+------+--------+
| id | name | age | gender |
+----+----------+------+--------+
| 1 | xyy | 8 | F |
| 10 | xiaoming | 8 | M |
| 11 | xiaohong | 8 | F |
| 12 | hg | 8 | M |
| 13 | lianlian | 8 | F |
| 14 | xiaoxiao | 8 | F |
| 15 | yanyan | 8 | F |
+----+----------+------+--------+
7 rows in set (0.00 sec)
🍊 范例:删除表里所有数据
mysql> delete from student;
mysql> select *from student;
+----+----------+------+--------+
| id | name | age | gender |
+----+----------+------+--------+
| 1 | xyy | 8 | F |
| 10 | xiaoming | 8 | M |
| 11 | xiaohong | 8 | F |
| 12 | hg | 8 | M |
| 13 | lianlian | 8 | F |
| 14 | xiaoxiao | 8 | F |
| 15 | yanyan | 8 | F |
+----+----------+------+--------+
7 rows in set (0.00 sec)
mysql> delete from student;
Query OK, 7 rows affected (0.02 sec)
mysql> select *from student;
Empty set (0.00 sec)
🍊 范例:TRUNCATE命令来删除表数据
如果想清空表,保留表结构,也可以使用下面语句,此语句会自动缩减数据文件的大小。
TRUNCATE TABLE tbl_name; #当表数据量很大的时候,这个方式删除会比前面 delete from student; 这条命令速度更快些的;
mysql> insert student select *from student2;
Query OK, 7 rows affected (0.00 sec)
Records: 7 Duplicates: 0 Warnings: 0
mysql> select *from student;
+----+----------+------+--------+
| id | name | age | gender |
+----+----------+------+--------+
| 1 | xyy | 18 | F |
| 10 | xiaoming | 20 | M |
| 11 | xiaohong | 18 | F |
| 12 | hg | 19 | M |
| 13 | lianlian | 18 | F |
| 14 | xiaoxiao | 18 | F |
| 15 | yanyan | 19 | F |
+----+----------+------+--------+
7 rows in set (0.00 sec)
mysql> truncate table student;
Query OK, 0 rows affected (0.02 sec)
mysql> select *from student;
Empty set (0.00 sec)
NOTE
注意:mysql -U选项也可以防止delete命令忘记添加where条件导致误删数据的,但对truncate命令无影响。
🍊 范例:缩减表大小
OPTIMIZE TABLE tb_name
如下是一个生成大文件表的sql脚本:
testlog.sql
create table testlog (id int auto_increment primary key,name char(10),age int default 20);
delimiter $$
create procedure pro_testlog()
begin
declare i int;
set i = 1;
while i < 100000
do insert into testlog(name,age) values (concat('wang',i),i);
set i = i +1;
end while;
end$$
delimiter ;
将这个代码拷贝到自己数据库里:
[root@linux-test ~]#mysql -uroot -pxyy520 test
mysql> create table testlog (id int auto_increment primary key,name char(10),age int default 20);
Query OK, 0 rows affected (0.01 sec)
mysql>
mysql> delimiter $$
mysql>
mysql> create procedure pro_testlog()
-> begin
-> declare i int;
-> set i = 1;
-> while i < 100000
-> do insert into testlog(name,age) values (concat('wang',i),i);
-> set i = i +1;
-> end while;
-> end$$
Query OK, 0 rows affected (0.01 sec)
mysql>
mysql> delimiter ;
mysql>
查看当前表信息:
mysql> select *from testlog;
Empty set (0.00 sec)
[root@linux-test ~]#ll -h /data/mysql/test
total 1.1M
……
-rw-rw---- 1 mysql mysql 8.5K Apr 28 07:19 testlog.frm
-rw-rw---- 1 mysql mysql 96K Apr 28 07:19 testlog.ibd #这个文件是96K
触发脚本:
mysql> call pro_testlog;
Query OK, 1 row affected (16.77 sec)
[root@linux-test ~]#ll -h /data/mysql/test/testlog.ibd
-rw-rw---- 1 mysql mysql 11M Apr 28 07:21 /data/mysql/test/testlog.ibd
[root@linux-test ~]#ll -h /data/mysql/test/testlog.ibd
-rw-rw---- 1 mysql mysql 12M Apr 28 07:21 /data/mysql/test/testlog.ibd
#可以看到这个testlog.ibd文件已经增大到12M了。
此时直接使用delete from testlog;
命令删除表后,那么这个/data/mysql/test/testlog.ibd
文件大小是否会变小呢?
mysql> delete from testlog;
Query OK, 99999 rows affected (0.20 sec)
mysql> select *from testlog;
Empty set (0.00 sec)
mysql>
[root@linux-test ~]#ll -h /data/mysql/test/testlog.ibd
-rw-rw---- 1 mysql mysql 12M Apr 28 07:24 /data/mysql/test/testlog.ibd
#可以发现这个文件大小依然没有变化。
那么我们可以利用如下命令来清理这种空洞文件:
mysql> OPTIMIZE TABLE testlog;
+--------------+----------+----------+-------------------------------------------------------------------+
| Table | Op | Msg_type | Msg_text |
+--------------+----------+----------+-------------------------------------------------------------------+
| test.testlog | optimize | note | Table does not support optimize, doing recreate + analyze instead |
| test.testlog | optimize | status | OK |
+--------------+----------+----------+-------------------------------------------------------------------+
2 rows in set (0.01 sec)
##再次验证(符合预期)
[root@linux-test ~]#ll -h /data/mysql/test/testlog.ibd
-rw-rw---- 1 mysql mysql 96K Apr 28 07:25 /data/mysql/test/testlog.ibd
当然,truncate命令直接是可以会自动缩减数据文件的大小的。
| 199997 | wang99998 | 99998 |
| 199998 | wang99999 | 99999 |
+--------+-----------+-------+
99999 rows in set (0.04 sec)
mysql> truncate table testlog;
Query OK, 0 rows affected (0.01 sec)
[root@linux-test ~]#ll -h /data/mysql/test/testlog.ibd
-rw-rw---- 1 mysql mysql 96K Apr 28 07:26 /data/mysql/test/testlog.ibd
DQL语句
行的过滤才是至关重要的!
单表操作
语法:
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:根据指定的条件把查询结果进行“分组”以用于做“聚合”运算
常见聚合函数:avg(), max(), min(), count(), sum()
HAVING: 对分组聚合运算后的结果指定过滤条件
一旦分组group by ,select语句后只跟分组的字段,聚合函数
ORDER BY: 根据指定的字段对查询结果进行排序
升序:ASC
降序:DESC
LIMIT [[offset,]row_count]:对查询的结果进行输出行数数量限制
对查询结果中的数据请求施加“锁”
FOR UPDATE: 写锁,独占或排它锁,只有一个读和写操作
LOCK IN SHARE MODE: 读锁,共享锁,同时多个读操作
范例:整张表的所有内容
06:44:07(root@localhost) [test]> select * from student; #*代表对所有列不过滤,student后面也没where,代表对所有航也不过滤,即显示整张表的所有内容。
+----+-----------+------+--------+
| id | name | age | gender |
+----+-----------+------+--------+
| 1 | xyy | 18 | F |
| 10 | xiaoming | 20 | M |
| 11 | xiaohong | 18 | F |
| 12 | hg | 19 | M |
| 13 | lianlian | 18 | F |
| 14 | xiaoxiao | 18 | F |
| 15 | yanyan | 19 | F |
| 17 | 马哥 | 30 | M |
| 18 | 马云 | 30 | M |
| 19 | 马弟弟 | 30 | M |
| 20 | 小彦彦 | 18 | F |
+----+-----------+------+--------+
11 rows in set (0.00 sec)
范例:过滤列
select name,age from student; #列的字段名是不区分大小写的,但数据库、表名是区分大小写的;
select NAME,AGE from student;
06:44:18(root@localhost) [test]> select name,age from student; #列的字段名是不区分大小写的,但数据库、表名是区分大小写的;
+-----------+------+
| name | age |
+-----------+------+
| xyy | 18 |
| xiaoming | 20 |
| xiaohong | 18 |
| hg | 19 |
| lianlian | 18 |
| xiaoxiao | 18 |
| yanyan | 19 |
| 马哥 | 30 |
| 马云 | 30 |
| 马弟弟 | 30 |
| 小彦彦 | 18 |
+-----------+------+
11 rows in set (0.00 sec)
06:51:25(root@localhost) [test]> select NAME,AGE from student;
+-----------+------+
| NAME | AGE |
+-----------+------+
| xyy | 18 |
| xiaoming | 20 |
| xiaohong | 18 |
| hg | 19 |
| lianlian | 18 |
| xiaoxiao | 18 |
| yanyan | 19 |
| 马哥 | 30 |
| 马云 | 30 |
| 马弟弟 | 30 |
| 小彦彦 | 18 |
+-----------+------+
11 rows in set (0.00 sec)
范例:过滤列(给字段起别名)
06:51:41(root@localhost) [test]> select name as 姓名,age 年龄,gender 性别 from student; #加不加as都行的。
+-----------+--------+--------+
| 姓名 | 年龄 | 性别 |
+-----------+--------+--------+
| xyy | 18 | F |
| xiaoming | 20 | M |
| xiaohong | 18 | F |
| hg | 19 | M |
| lianlian | 18 | F |
| xiaoxiao | 18 | F |
| yanyan | 19 | F |
| 马哥 | 30 | M |
| 马云 | 30 | M |
| 马弟弟 | 30 | M |
| 小彦彦 | 18 | F |
+-----------+--------+--------+
11 rows in set (0.00 sec)
🍊 范例:(多表的情况下,别名还是经常会用的)
NOTE
注意:mysql里,一旦定义了别名就必须要使用别名,再使用原名是不行的。
MariaDB [hellodb]> select stuid,students.name 学生姓名,s.age 学生年龄,tid,t.name 老师姓名,t.age 老师 年龄 from students s cross join teachers t;;
ERROR 1054 (42S22): Unknown column 'students.name' in 'field list'
MariaDB [hellodb]> select stuid,s.name 学生姓名,s.age 学生年龄,tid,t.name 老师姓名,t.age 老师年龄 from students s cross join teachers t;
+-------+---------------+--------------+-----+---------------+--------------+
| stuid | 学生姓名 | 学生年龄 | tid | 老师姓名 | 老师年龄 |
+-------+---------------+--------------+-----+---------------+--------------+
| 1 | Shi Zhongyu | 22 | 1 | Song Jiang | 45 |
| 1 | Shi Zhongyu | 22 | 2 | Zhang Sanfeng | 94 |
| 1 | Shi Zhongyu | 22 | 3 | Miejue Shitai | 77 |
范例:针对特定字段DISTINCT 去除重复行
07:03:09(root@localhost) [test]> SELECT DISTINCT gender FROM student;
+--------+
| gender |
+--------+
| F |
| M |
+--------+
2 rows in set (0.00 sec)
范例:过滤列和行(等于/不等于)
07:03:13(root@localhost) [test]> select * from student where gender='F';
+----+-----------+------+--------+
| id | name | age | gender |
+----+-----------+------+--------+
| 1 | xyy | 18 | F |
| 11 | xiaohong | 18 | F |
| 13 | lianlian | 18 | F |
| 14 | xiaoxiao | 18 | F |
| 15 | yanyan | 19 | F |
| 20 | 小彦彦 | 18 | F |
+----+-----------+------+--------+
6 rows in set (0.01 sec)
07:08:45(root@localhost) [test]> select name,age,gender from student where gender='F';
+-----------+------+--------+
| name | age | gender |
+-----------+------+--------+
| xyy | 18 | F |
| xiaohong | 18 | F |
| lianlian | 18 | F |
| xiaoxiao | 18 | F |
| yanyan | 19 | F |
| 小彦彦 | 18 | F |
+-----------+------+--------+
6 rows in set (0.00 sec)
其它demo:
select name,age,gender from student where gender <> 'F';
select name,age,gender from student where gender != 'F';
select name,age,gender from student where gender = 'F';
select name,age,gender from student where gender <=> 'F';
范例:(>=或者between …… and ……
)
07:09:46(root@localhost) [test]> select name,age,gender from student where age<=18;
+-----------+------+--------+
| name | age | gender |
+-----------+------+--------+
| xyy | 18 | F |
| xiaohong | 18 | F |
| lianlian | 18 | F |
| xiaoxiao | 18 | F |
| 小彦彦 | 18 | F |
+-----------+------+--------+
5 rows in set (0.00 sec)
07:13:07(root@localhost) [test]> select name,age,gender from student where age>=18 and age <=28;
+-----------+------+--------+
| name | age | gender |
+-----------+------+--------+
| xyy | 18 | F |
| xiaoming | 20 | M |
| xiaohong | 18 | F |
| hg | 19 | M |
| lianlian | 18 | F |
| xiaoxiao | 18 | F |
| yanyan | 19 | F |
| 小彦彦 | 18 | F |
+-----------+------+--------+
8 rows in set (0.00 sec)
07:13:29(root@localhost) [test]> select name,age,gender from student where age between 18 and 28;
+-----------+------+--------+
| name | age | gender |
+-----------+------+--------+
| xyy | 18 | F |
| xiaoming | 20 | M |
| xiaohong | 18 | F |
| hg | 19 | M |
| lianlian | 18 | F |
| xiaoxiao | 18 | F |
| yanyan | 19 | F |
| 小彦彦 | 18 | F |
+-----------+------+--------+
8 rows in set (0.00 sec)
范例:参与数字运算
07:14:44(root@localhost) [test]> select name,age+18,gender from student;
+-----------+--------+--------+
| name | age+18 | gender |
+-----------+--------+--------+
| xyy | 36 | F |
| xiaoming | 38 | M |
| xiaohong | 36 | F |
| hg | 37 | M |
| lianlian | 36 | F |
| xiaoxiao | 36 | F |
| yanyan | 37 | F |
| 马哥 | 48 | M |
| 马云 | 48 | M |
| 马弟弟 | 48 | M |
| 小彦彦 | 36 | F |
+-----------+--------+--------+
11 rows in set (0.00 sec)
07:16:40(root@localhost) [test]> select 10*20;
+-------+
| 10*20 |
+-------+
| 200 |
+-------+
1 row in set (0.00 sec)
07:18:17(root@localhost) [test]> select 10*20 as result;
+--------+
| result |
+--------+
| 200 |
+--------+
1 row in set (0.00 sec)
范例:in用法
07:19:22(root@localhost) [test]> select name,age,gender from student where age in (18,19,20);
+-----------+------+--------+
| name | age | gender |
+-----------+------+--------+
| xyy | 18 | F |
| xiaoming | 20 | M |
| xiaohong | 18 | F |
| hg | 19 | M |
| lianlian | 18 | F |
| xiaoxiao | 18 | F |
| yanyan | 19 | F |
| 小彦彦 | 18 | F |
+-----------+------+--------+
8 rows in set (0.00 sec)
范例:判断为空
07:24:26(root@localhost) [hellodb]> select * from students where classid == 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 '== NULL' at line 1
07:24:30(root@localhost) [hellodb]> select * from students where classid == 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 '== null' at line 1
07:24:39(root@localhost) [hellodb]> select * from students where classid is NULL;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 24 | Xu Xian | 27 | M | NULL | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (0.00 sec)
07:24:45(root@localhost) [hellodb]> select * from students where classid is null;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 24 | Xu Xian | 27 | M | NULL | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (0.00 sec)
07:24:49(root@localhost) [hellodb]> select * from students where classid <=> null; #这个写法也是可以的。
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 24 | Xu Xian | 27 | M | NULL | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
+-------+-------------+-----+--------+---------+-----------+
2 rows in set (0.00 sec)
select * from students where classid is not null;
范例:模糊查找
07:27:07(root@localhost) [hellodb]> select * from students where name like 'xu%'; #大小写不敏感的,过滤xu开头的
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 24 | Xu Xian | 27 | M | NULL | NULL |
+-------+-------------+-----+--------+---------+-----------+
3 rows in set (0.00 sec)
范例:SQL 注入攻击
方式1:
select * from user where username='admin' and password='' or '1'='1';
select * from user where username='admin' and password='' or '1=1';
方式2:注释方式
select * from user where username='admin'; -- ' and password='magedu123';
select * from user where username='admin'; # ' and password='magedu123';
##先创建一张表:
07:26:13(root@localhost) [test]> create table user (id int primary key auto_increment, username varchar(30) not null, password varchar(50));
Query OK, 0 rows affected (0.01 sec)
07:27:40(root@localhost) [test]> select *from user;
Empty set (0.00 sec)
##插入一条数据:
07:27:49(root@localhost) [test]> insert user (username,password)values('admin','Magedu20230206');
Query OK, 1 row affected (0.01 sec)
07:29:23(root@localhost) [test]> select *from user;
+----+----------+----------------+
| id | username | password |
+----+----------+----------------+
| 1 | admin | Magedu20230206 |
+----+----------+----------------+
1 row in set (0.00 sec)
##再插入一条数据:
07:32:18(root@localhost) [test]> insert user (username,password)values('hg','Magedu');
Query OK, 1 row affected (0.01 sec)
07:33:17(root@localhost) [test]> select *from user;
+----+----------+----------------+
| id | username | password |
+----+----------+----------------+
| 1 | admin | Magedu20230206 |
| 2 | hg | Magedu |
+----+----------+----------------+
2 rows in set (0.00 sec)
##一般网页登录时会查询后台数据库里用户名和密码是否匹配
07:29:26(root@localhost) [test]> select *from user where username='admin' and password='mage';
Empty set (0.00 sec)
07:32:03(root@localhost) [test]> select *from user where username='admin' and password='Magedu20230206';
+----+----------+----------------+
| id | username | password |
+----+----------+----------------+
| 1 | admin | Magedu20230206 |
+----+----------+----------------+
1 row in set (0.00 sec)
##此时如何利用mysql注入攻击呢?
07:33:36(root@localhost) [test]> select * from user where username='admin' and password='' or '1'='1';
+----+----------+----------------+
| id | username | password |
+----+----------+----------------+
| 1 | admin | Magedu20230206 |
| 2 | hg | Magedu |
+----+----------+----------------+
2 rows in set (0.00 sec)
##呃呃,这个也就绕过来密码,直接查到了user表里的所有信息。
07:34:59(root@localhost) [test]> select * from user where '1'='1'; ##这个同理也是可以查出表的所有信息的!
+----+----------+----------------+
| id | username | password |
+----+----------+----------------+
| 1 | admin | Magedu20230206 |
| 2 | hg | Magedu |
+----+----------+----------------+
2 rows in set (0.00 sec)
另一个方式测试SQL注入攻击:
构建一个特殊的用户名:
#-- 和 #代表注释;
07:49:29(root@localhost) [test]> select * from user where username='admin'; -- ' and password='magedu123';
+----+----------+----------------+
| id | username | password |
+----+----------+----------------+
| 1 | admin | Magedu20230206 |
+----+----------+----------------+
1 row in set (0.00 sec)
07:50:30(root@localhost) [test]> select * from user where username='admin'; # ' and password='magedu123';
+----+----------+----------------+
| id | username | password |
+----+----------+----------------+
| 1 | admin | Magedu20230206 |
+----+----------+----------------+
1 row in set (0.00 sec)
范例:rlike正则表达式
07:56:39(root@localhost) [hellodb]> select *from students where name rlike '^Shi';
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
+-------+-------------+-----+--------+---------+-----------+
3 rows in set (0.01 sec)
07:56:43(root@localhost) [hellodb]> select *from students where name rlike '^shi'; #这里的正则表达式后不区分大小写。
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
+-------+-------------+-----+--------+---------+-----------+
3 rows in set (0.00 sec)
范例:group分组
一个是分组字段本身;
或者是聚合函数;
其它字段毫无意义。
08:10:34(root@localhost) [hellodb]> select gender,avg(age),max(age),min(age) from students group by gender;
+--------+----------+----------+----------+
| gender | avg(age) | max(age) | min(age) |
+--------+----------+----------+----------+
| F | 19.0000 | 22 | 17 |
| M | 33.0000 | 100 | 19 |
+--------+----------+----------+----------+
2 rows in set (0.00 sec)
08:13:35(root@localhost) [hellodb]> select gender,avg(age),sum(age),max(age),min(age) from students group by gender;
+--------+----------+----------+----------+----------+
| gender | avg(age) | sum(age) | max(age) | min(age) |
+--------+----------+----------+----------+----------+
| F | 19.0000 | 190 | 22 | 17 |
| M | 33.0000 | 495 | 100 | 19 |
+--------+----------+----------+----------+----------+
2 rows in set (0.00 sec)
对多字段分别统计:
08:11:41(root@localhost) [hellodb]> select classid,gender,avg(age),max(age),min(age) from students group by classid,gender;
+---------+--------+----------+----------+----------+
| classid | gender | avg(age) | max(age) | min(age) |
+---------+--------+----------+----------+----------+
| NULL | M | 63.5000 | 100 | 27 |
| 1 | F | 19.5000 | 20 | 19 |
| 1 | M | 21.5000 | 22 | 21 |
| 2 | M | 36.0000 | 53 | 22 |
| 3 | F | 18.3333 | 19 | 17 |
| 3 | M | 26.0000 | 26 | 26 |
| 4 | M | 24.7500 | 32 | 19 |
| 5 | M | 46.0000 | 46 | 46 |
| 6 | F | 20.0000 | 22 | 18 |
| 6 | M | 23.0000 | 23 | 23 |
| 7 | F | 18.0000 | 19 | 17 |
| 7 | M | 23.0000 | 23 | 23 |
+---------+--------+----------+----------+----------+
12 rows in set (0.00 sec)
- 范例:统计某个班的平均年龄:
方法1:先分组后过滤
06:10:38(root@localhost) [hellodb]> select classid,avg(age) from students group by classid;
+---------+----------+
| classid | avg(age) |
+---------+----------+
| NULL | 63.5000 |
| 1 | 20.5000 |
| 2 | 36.0000 |
| 3 | 20.2500 |
| 4 | 24.7500 |
| 5 | 46.0000 |
| 6 | 20.7500 |
| 7 | 19.6667 |
+---------+----------+
8 rows in set (0.00 sec)
##如果分组右面有where筛选的话,那么where要替换成having才行!
06:11:28(root@localhost) [hellodb]> select classid,avg(age) from students group by classid where 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 'where classid is not null' at line 1
06:11:42(root@localhost) [hellodb]> select classid,avg(age) from students group by classid having classid is not null;
+---------+----------+
| classid | avg(age) |
+---------+----------+
| 1 | 20.5000 |
| 2 | 36.0000 |
| 3 | 20.2500 |
| 4 | 24.7500 |
| 5 | 46.0000 |
| 6 | 20.7500 |
| 7 | 19.6667 |
+---------+----------+
7 rows in set (0.00 sec)
方法2:先过滤后分组
06:11:52(root@localhost) [hellodb]> select classid,avg(age) from students where classid is not null group by classid;
+---------+----------+
| classid | avg(age) |
+---------+----------+
| 1 | 20.5000 |
| 2 | 36.0000 |
| 3 | 20.2500 |
| 4 | 24.7500 |
| 5 | 46.0000 |
| 6 | 20.7500 |
| 7 | 19.6667 |
+---------+----------+
7 rows in set (0.00 sec)
范例:排序
- 范例:排序
06:20:16(root@localhost) [hellodb]> select *from students order by age;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 21 | Huang Yueying | 22 | F | 6 | NULL |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 23 | Ma Chao | 23 | M | 4 | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
| 24 | Xu Xian | 27 | M | NULL | NULL |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
+-------+---------------+-----+--------+---------+-----------+
25 rows in set (0.00 sec)
- 范例:排序(逆序)
06:20:33(root@localhost) [hellodb]> select *from students order by age desc;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 24 | Xu Xian | 27 | M | NULL | NULL |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
| 17 | Lin Chong | 25 | M | 4 | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL |
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
+-------+---------------+-----+--------+---------+-----------+
25 rows in set (0.00 sec)
- 范例:排序(字段含
null
处理)(小技巧)
##默认null优先级比较高,会排在最前面
06:21:00(root@localhost) [hellodb]> select *from students order by classid;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
| 24 | Xu Xian | 27 | M | NULL | NULL |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
| 23 | Ma Chao | 23 | M | 4 | NULL |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 17 | Lin Chong | 25 | M | 4 | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
+-------+---------------+-----+--------+---------+-----------+
25 rows in set (0.00 sec)
##如果让null排在最后面呢?
06:22:40(root@localhost) [hellodb]> select *from students order by -classid desc;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 24 | Xu Xian | 27 | M | NULL | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
+-------+---------------+-----+--------+---------+-----------+
25 rows in set (0.00 sec)
asc--正序;(默认不写)
desc--排序;
- 范例:多列排序
06:22:49(root@localhost) [hellodb]> select *from students order by classid,age; ##先按classid排序,再按age排序;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 24 | Xu Xian | 27 | M | NULL | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL |
+-------+---------------+-----+--------+---------+-----------+
25 rows in set (0.00 sec)
06:26:55(root@localhost) [hellodb]>
06:26:55(root@localhost) [hellodb]> select *from students order by classid desc,age;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 24 | Xu Xian | 27 | M | NULL | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
+-------+---------------+-----+--------+---------+-----------+
25 rows in set (0.00 sec)
范例:limit
LIMIT [[offset,]row_count]:对查询的结果进行输出行数数量限制。
- 范例:显示过滤的前10行
06:27:31(root@localhost) [hellodb]> select *from students order by age limit 10;
+-------+--------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+--------------+-----+--------+---------+-----------+
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
+-------+--------------+-----+--------+---------+-----------+
10 rows in set (0.00 sec)
#跳过前2行,显示后3行;(但是这里有问题,后续几行都是19,这里把Duan Yu给跳过了)
06:33:17(root@localhost) [hellodb]> select *from students order by age limit 2,3;
+-------+--------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+--------------+-----+--------+---------+-----------+
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
+-------+--------------+-----+--------+---------+-----------+
3 rows in set (0.00 sec)
#
06:33:29(root@localhost) [hellodb]> select distinct age from students;
+-----+
| age |
+-----+
| 22 |
| 53 |
| 32 |
| 26 |
| 46 |
| 19 |
| 17 |
| 20 |
| 23 |
| 33 |
| 21 |
| 25 |
| 18 |
| 27 |
| 100 |
+-----+
15 rows in set (0.00 sec)
06:38:22(root@localhost) [hellodb]> select distinct age from students order by age;
+-----+
| age |
+-----+
| 17 |
| 18 |
| 19 |
| 20 |
| 21 |
| 22 |
| 23 |
| 25 |
| 26 |
| 27 |
| 32 |
| 33 |
| 46 |
| 53 |
| 100 |
+-----+
15 rows in set (0.00 sec)
06:38:30(root@localhost) [hellodb]> select distinct age from students order by age limit 5;
+-----+
| age |
+-----+
| 17 |
| 18 |
| 19 |
| 20 |
| 21 |
+-----+
5 rows in set (0.00 sec)
06:38:44(root@localhost) [hellodb]> select distinct age from students order by age limit 2,3;
+-----+
| age |
+-----+
| 19 |
| 20 |
| 21 |
+-----+
3 rows in set (0.00 sec)
##当然,我们对主键操作是没问题的,主键里的字段是不重复的。
06:38:48(root@localhost) [hellodb]> select *from students order by stuid limit 2,3;
+-------+-----------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-----------+-----+--------+---------+-----------+
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
+-------+-----------+-----+--------+---------+-----------+
3 rows in set (0.00 sec)
范例:时间查询
- 范例
06:44:19(root@localhost) [test]> show create table testdate;
+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| testdate | CREATE TABLE `testdate` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 |
+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
06:44:33(root@localhost) [test]> desc testdate;
+-------+-----------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| date | timestamp | NO | | CURRENT_TIMESTAMP | |
+-------+-----------+------+-----+-------------------+----------------+
2 rows in set (0.00 sec)
06:45:04(root@localhost) [test]> select *from testdate;
+----+---------------------+
| id | date |
+----+---------------------+
| 1 | 2024-04-27 13:35:20 |
| 2 | 2024-04-27 13:35:22 |
| 3 | 2024-04-27 13:35:24 |
| 4 | 2024-04-27 13:35:27 |
+----+---------------------+
4 rows in set (0.00 sec)
##新加几行数据
06:45:49(root@localhost) [test]> insert testdate (id)values(5);
Query OK, 1 row affected (0.01 sec)
06:46:18(root@localhost) [test]> insert testdate (id)values(6);
Query OK, 1 row affected (0.00 sec)
06:46:20(root@localhost) [test]> insert testdate (id)values(7);
Query OK, 1 row affected (0.00 sec)
06:46:23(root@localhost) [test]> select *from testdate;
+----+---------------------+
| id | date |
+----+---------------------+
| 1 | 2024-04-27 13:35:20 |
| 2 | 2024-04-27 13:35:22 |
| 3 | 2024-04-27 13:35:24 |
| 4 | 2024-04-27 13:35:27 |
| 5 | 2024-05-02 06:46:18 |
| 6 | 2024-05-02 06:46:20 |
| 7 | 2024-05-02 06:46:23 |
+----+---------------------+
7 rows in set (0.00 sec)
##时间过滤
06:49:18(root@localhost) [test]> select *from testdate where date between '2024-04-27 13:35:22' and '2024-05-02 06:46:20';
+----+---------------------+
| id | date |
+----+---------------------+
| 2 | 2024-04-27 13:35:22 |
| 3 | 2024-04-27 13:35:24 |
| 4 | 2024-04-27 13:35:27 |
| 5 | 2024-05-02 06:46:18 |
| 6 | 2024-05-02 06:46:20 |
+----+---------------------+
5 rows in set (0.00 sec)
06:49:36(root@localhost) [test]> select *from testdate where date between '2024-05-02 06:46:20' and '2024-04-27 13:35:22'; ##小的数值一定要放在前面才行的;
Empty set (0.00 sec)
- 范例:
>= and <=
也是可以的。
06:50:38(root@localhost) [test]> select *from testdate where date >='2024-04-27 13:35:22' and date <= '2024-05-02 06:46:20';
+----+---------------------+
| id | date |
+----+---------------------+
| 2 | 2024-04-27 13:35:22 |
| 3 | 2024-04-27 13:35:24 |
| 4 | 2024-04-27 13:35:27 |
| 5 | 2024-05-02 06:46:18 |
| 6 | 2024-05-02 06:46:20 |
+----+---------------------+
5 rows in set (0.00 sec)
多表查询(7个图)🍕
最重要的是这2张图,其它都是从这2个图变过来的。(内连接+左外连接-->其它方式(变种))
多表连接--面试常用的题;工作中也是比较常用的;
多表查询,即查询结果来自于多张表
子查询:在SQL语句嵌套着查询语句,性能较差,基于某语句的查询结果再次进行的查询
联合查询:UNION
交叉连接:笛卡尔乘积
内连接:
等值连接:让表之间的字段以“等值”建立连接关系
不等值连接
自然连接:去掉重复列的等值连接
外连接:
左外连接:FROM tb1 LEFT JOIN tb2 ON tb1.col=tb2.col
右外连接:FROM tb1 RIGHT JOIN tb2 ON tb1.col=tb2.col
自连接:本表和本表进行连接查询
子查询
效率比较低。
常用在WHERE子句中的子查询
1、用于比较表达式中的子查询;子查询仅能返回单个值
SELECT Name,Age FROM students WHERE Age>(SELECT avg(Age) FROM teachers);
- 范例:
08:37:04(root@localhost) [hellodb]> select avg(age) from students;
+----------+
| avg(age) |
+----------+
| 27.4000 |
+----------+
1 row in set (0.00 sec)
08:37:13(root@localhost) [hellodb]> select *from students where age > (select avg(age) from students);
+-------+--------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+--------------+-----+--------+---------+-----------+
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
+-------+--------------+-----+--------+---------+-----------+
5 rows in set (0.00 sec)
##当然,也可以从其他表查数据的
08:37:50(root@localhost) [hellodb]> select avg(age) from teachers;
+----------+
| avg(age) |
+----------+
| 77.2500 |
+----------+
1 row in set (0.00 sec)
08:37:59(root@localhost) [hellodb]> select *from students where age > (select avg(age) from teachers);\
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
+-------+-------------+-----+--------+---------+-----------+
1 row in set (0.00 sec)
##错误案例演示:子查询仅能返回单个值
08:38:00(root@localhost) [hellodb]> select *from students where age > (select name,age from teachers order by age desc limit 1);
ERROR 1241 (21000): Operand should contain 1 column(s)
08:39:39(root@localhost) [hellodb]> select name,age from teachers order by age desc limit 1;
+---------------+-----+
| name | age |
+---------------+-----+
| Zhang Sanfeng | 94 |
+---------------+-----+
1 row in set (0.00 sec)
08:39:44(root@localhost) [hellodb]> select *from students where age > (select name,age from teachers order by age desc limit 1);
ERROR 1241 (21000): Operand should contain 1 column(s)
2、 用于IN中的子查询:子查询应该单独查询并返回一个或多个值重新构成列表
SELECT Name,Age FROM students WHERE Age IN (SELECT Age FROM teachers);
范例:
08:47:03(root@localhost) [hellodb]> update students set age=45 where stuid=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
08:47:20(root@localhost) [hellodb]> update students set age=77 where stuid=3;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
08:47:25(root@localhost) [hellodb]> SELECT Name,Age FROM students WHERE Age IN (SELECT Age FROM teachers);
+-------------+-----+
| Name | Age |
+-------------+-----+
| Shi Zhongyu | 45 |
| Xie Yanke | 77 |
+-------------+-----+
2 rows in set (0.00 sec)
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 | 2 | 3 |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 5 | Yu Yutong | 26 | M | 3 | 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 | 22 | M | 1 | 7 |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL |
| 24 | Xu Xian | 27 | M | NULL | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
+-------+---------------+-----+--------+---------+-----------+
22 rows in set (0.001 sec)
4、用于FROM子句中的子查询
使用格式:
SELECT tb_alias.col1,... FROM (SELECT clause) AS tb_alias WHERE Clause;
范例:
09:19:22(root@localhost) [hellodb]> select * from students where age>30;
+-------+--------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+--------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 45 | M | 2 | 3 |
| 3 | Xie Yanke | 77 | M | 2 | 16 |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
+-------+--------------+-----+--------+---------+-----------+
6 rows in set (0.00 sec)
09:19:42(root@localhost) [hellodb]> select name,age from (select * from students where age>30) old_students;
+--------------+-----+
| name | age |
+--------------+-----+
| Shi Zhongyu | 45 |
| Xie Yanke | 77 |
| Ding Dian | 32 |
| Shi Qing | 46 |
| Tian Boguang | 33 |
| Sun Dasheng | 100 |
+--------------+-----+
6 rows in set (0.00 sec)
09:20:32(root@localhost) [hellodb]> SELECT s.aage,s.ClassID FROM (SELECT avg(Age) AS aage,ClassID FROM students
-> WHERE ClassID IS NOT NULL GROUP BY ClassID) AS s WHERE s.aage>30;
+---------+---------+
| aage | ClassID |
+---------+---------+
| 51.6667 | 2 |
| 46.0000 | 5 |
+---------+---------+
2 rows in set (0.00 sec)
- 范例:子查询用于更新表
09:22:55(root@localhost) [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 | 93 | F |
+-----+---------------+-----+--------+
4 rows in set (0.00 sec)
09:28:10(root@localhost) [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
09:28:57(root@localhost) [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 | 29 | F |
+-----+---------------+-----+--------+
4 rows in set (0.00 sec)
联合查询:UNION
SELECT Name,Age FROM students UNION SELECT Name,Age FROM teachers;
- 范例:
一般是要对应好字段数量,及字段类型,否则语法没错,但没啥实际意义。
MariaDB [hellodb]> select *from students;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL |
| 24 | Xu Xian | 27 | M | NULL | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
+-------+---------------+-----+--------+---------+-----------+
25 rows in set (0.00 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 | 93 | F |
+-----+---------------+-----+--------+
4 rows in set (0.00 sec)
MariaDB [hellodb]> select *from teachers union select stuid,name,age,gender from students;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 93 | F |
| 1 | Shi Zhongyu | 22 | M |
| 2 | Shi Potian | 22 | M |
| 3 | Xie Yanke | 53 | M |
| 4 | Ding Dian | 32 | M |
| 5 | Yu Yutong | 26 | M |
| 6 | Shi Qing | 46 | M |
| 7 | Xi Ren | 19 | F |
| 8 | Lin Daiyu | 17 | F |
| 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 | 19 | M |
| 16 | Xu Zhu | 21 | M |
| 17 | Lin Chong | 25 | M |
| 18 | Hua Rong | 23 | M |
| 19 | Xue Baochai | 18 | F |
| 20 | Diao Chan | 19 | F |
| 21 | Huang Yueying | 22 | F |
| 22 | Xiao Qiao | 20 | F |
| 23 | Ma Chao | 23 | M |
| 24 | Xu Xian | 27 | M |
| 25 | Sun Dasheng | 100 | M |
+-----+---------------+-----+--------+
29 rows in set (0.00 sec)
##没啥实际意义……
MariaDB [hellodb]> select *from teachers union select name,stuid,age,gender from students;
+---------------+---------------+-----+--------+
| TID | Name | Age | Gender |
+---------------+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 93 | F |
| Shi Zhongyu | 1 | 22 | M |
| Shi Potian | 2 | 22 | M |
| Xie Yanke | 3 | 53 | M |
| Ding Dian | 4 | 32 | M |
| Yu Yutong | 5 | 26 | M |
| Shi Qing | 6 | 46 | M |
| Xi Ren | 7 | 19 | F |
| Lin Daiyu | 8 | 17 | F |
| Ren Yingying | 9 | 20 | F |
| Yue Lingshan | 10 | 19 | F |
| Yuan Chengzhi | 11 | 23 | M |
| Wen Qingqing | 12 | 19 | F |
| Tian Boguang | 13 | 33 | M |
| Lu Wushuang | 14 | 17 | F |
| Duan Yu | 15 | 19 | M |
| Xu Zhu | 16 | 21 | M |
| Lin Chong | 17 | 25 | M |
| Hua Rong | 18 | 23 | M |
| Xue Baochai | 19 | 18 | F |
| Diao Chan | 20 | 19 | F |
| Huang Yueying | 21 | 22 | F |
| Xiao Qiao | 22 | 20 | F |
| Ma Chao | 23 | 23 | M |
| Xu Xian | 24 | 27 | M |
| Sun Dasheng | 25 | 100 | M |
+---------------+---------------+-----+--------+
29 rows in set (0.00 sec)
MariaDB [hellodb]>
- 范例:2个表union会产生什么问题?(去重)
##创建新表
MariaDB [hellodb]> create table teachers2 select *from teachers;
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0
MariaDB [hellodb]> select *from teachers2;
+-----+---------------+-----+--------+
| 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)
##修改2个字段
MariaDB [hellodb]> update teachers2 set name='mage' where tid=1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MariaDB [hellodb]> update teachers2 set name='wang' where tid=2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
##查询
MariaDB [hellodb]> select *from teachers2;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | mage | 45 | M |
| 2 | wang | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 93 | F |
+-----+---------------+-----+--------+
4 rows in set (0.00 sec)
#union操作
MariaDB [hellodb]> selec
+-----+---------------+-
| TID | Name |
+-----+---------------+-
| 1 | mage |
| 2 | wang |
| 3 | Miejue Shitai |
| 4 | Lin Chaoying |
| 1 | Song Jiang |
| 2 | Zhang Sanfeng |
+-----+---------------+-
6 rows in set (0.01 sec)
##可以看到,用这种小技巧也可以实现简单的去重操作;
##那如何去重呢?
MariaDB [hellodb]> create table teachers3 select *from teachers2 union select *from teachers;
Query OK, 6 rows affected (0.01 sec)
Records: 6 Duplicates: 0 Warnings: 0
MariaDB [hellodb]> select *from teachers3;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | mage | 45 | M |
| 2 | wang | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 93 | F |
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
+-----+---------------+-----+--------+
6 rows in set (0.00 sec)
- 范例:能不能不去重呢?
MariaDB [hellodb]> select *from teachers2 union all select *from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | mage | 45 | M |
| 2 | wang | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 93 | F |
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 93 | F |
+-----+---------------+-----+--------+
8 rows in set (0.00 sec)
- 范例:3个语句的union
MariaDB [hellodb]> select *from teachers2 union all select *from teachers union select stuid,name,age,gender from students;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | mage | 45 | M |
| 2 | wang | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 93 | F |
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 1 | Shi Zhongyu | 22 | M |
| 2 | Shi Potian | 22 | M |
| 3 | Xie Yanke | 53 | M |
| 4 | Ding Dian | 32 | M |
| 5 | Yu Yutong | 26 | M |
| 6 | Shi Qing | 46 | M |
| 7 | Xi Ren | 19 | F |
| 8 | Lin Daiyu | 17 | F |
| 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 | 19 | M |
| 16 | Xu Zhu | 21 | M |
| 17 | Lin Chong | 25 | M |
| 18 | Hua Rong | 23 | M |
| 19 | Xue Baochai | 18 | F |
| 20 | Diao Chan | 19 | F |
| 21 | Huang Yueying | 22 | F |
| 22 | Xiao Qiao | 20 | F |
| 23 | Ma Chao | 23 | M |
| 24 | Xu Xian | 27 | M |
| 25 | Sun Dasheng | 100 | M |
+-----+---------------+-----+--------+
31 rows in set (0.00 sec)
交叉连接
2张表横向连接,交叉组合。
即笛卡尔乘积,"雨露均沾",利用 cross join实现
交叉连接通常结果意义不是很大,用的场景不是很多。它还有一个巨大的缺点,两张表明明是小表,但合并后却成为一个巨大的表。所以,cross join在生产里尽可能不要去执行。
- 范例:交叉连接
select * from students cross join teachers;
MariaDB [hellodb]> select *from students;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL |
| 24 | Xu Xian | 27 | M | NULL | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
+-------+---------------+-----+--------+---------+-----------+
25 rows in set (0.00 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 | 93 | F |
+-----+---------------+-----+--------+
4 rows in set (0.01 sec)
#会产生4+6=10列数据,25*4=100行数据
MariaDB [hellodb]> select *from students cross join teachers;
+-------+---------------+-----+--------+---------+-----------+-----+---------------+-----+--------+
| StuID | Name | Age | Gender | ClassID | TeacherID | TID | Name | Age | Gender |
+-------+---------------+-----+--------+---------+-----------+-----+---------------+-----+--------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 | 1 | Song Jiang | 45 | M |
| 1 | Shi Zhongyu | 22 | M | 2 | 3 | 2 | Zhang Sanfeng | 94 | M |
| 1 | Shi Zhongyu | 22 | M | 2 | 3 | 3 | Miejue Shitai | 77 | F |
| 1 | Shi Zhongyu | 22 | M | 2 | 3 | 4 | Lin Chaoying | 93 | F |
| 2 | Shi Potian | 22 | M | 1 | 7 | 1 | Song Jiang | 45 | M |
| 2 | Shi Potian | 22 | M | 1 | 7 | 2 | Zhang Sanfeng | 94 | M |
| 2 | Shi Potian | 22 | M | 1 | 7 | 3 | Miejue Shitai | 77 | F |
| 2 | Shi Potian | 22 | M | 1 | 7 | 4 | Lin Chaoying | 93 | F |
| 3 | Xie Yanke | 53 | M | 2 | 16 | 1 | Song Jiang | 45 | M |
| 3 | Xie Yanke | 53 | M | 2 | 16 | 2 | Zhang Sanfeng | 94 | M |
| 3 | Xie Yanke | 53 | M | 2 | 16 | 3 | Miejue Shitai | 77 | F |
| 3 | Xie Yanke | 53 | M | 2 | 16 | 4 | Lin Chaoying | 93 | F |
| 4 | Ding Dian | 32 | M | 4 | 4 | 1 | Song Jiang | 45 | M |
| 4 | Ding Dian | 32 | M | 4 | 4 | 2 | Zhang Sanfeng | 94 | M |
| 4 | Ding Dian | 32 | M | 4 | 4 | 3 | Miejue Shitai | 77 | F |
| 4 | Ding Dian | 32 | M | 4 | 4 | 4 | Lin Chaoying | 93 | F |
| 5 | Yu Yutong | 26 | M | 3 | 1 | 1 | Song Jiang | 45 | M |
| 5 | Yu Yutong | 26 | M | 3 | 1 | 2 | Zhang Sanfeng | 94 | M |
| 5 | Yu Yutong | 26 | M | 3 | 1 | 3 | Miejue Shitai | 77 | F |
| 5 | Yu Yutong | 26 | M | 3 | 1 | 4 | Lin Chaoying | 93 | F |
| 6 | Shi Qing | 46 | M | 5 | NULL | 1 | Song Jiang | 45 | M |
| 6 | Shi Qing | 46 | M | 5 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 6 | Shi Qing | 46 | M | 5 | NULL | 3 | Miejue Shitai | 77 | F |
| 6 | Shi Qing | 46 | M | 5 | NULL | 4 | Lin Chaoying | 93 | F |
| 7 | Xi Ren | 19 | F | 3 | NULL | 1 | Song Jiang | 45 | M |
| 7 | Xi Ren | 19 | F | 3 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 7 | Xi Ren | 19 | F | 3 | NULL | 3 | Miejue Shitai | 77 | F |
| 7 | Xi Ren | 19 | F | 3 | NULL | 4 | Lin Chaoying | 93 | F |
| 8 | Lin Daiyu | 17 | F | 7 | NULL | 1 | Song Jiang | 45 | M |
| 8 | Lin Daiyu | 17 | F | 7 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 8 | Lin Daiyu | 17 | F | 7 | NULL | 3 | Miejue Shitai | 77 | F |
| 8 | Lin Daiyu | 17 | F | 7 | NULL | 4 | Lin Chaoying | 93 | F |
| 9 | Ren Yingying | 20 | F | 6 | NULL | 1 | Song Jiang | 45 | M |
| 9 | Ren Yingying | 20 | F | 6 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 9 | Ren Yingying | 20 | F | 6 | NULL | 3 | Miejue Shitai | 77 | F |
| 9 | Ren Yingying | 20 | F | 6 | NULL | 4 | Lin Chaoying | 93 | F |
| 10 | Yue Lingshan | 19 | F | 3 | NULL | 1 | Song Jiang | 45 | M |
| 10 | Yue Lingshan | 19 | F | 3 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 10 | Yue Lingshan | 19 | F | 3 | NULL | 3 | Miejue Shitai | 77 | F |
| 10 | Yue Lingshan | 19 | F | 3 | NULL | 4 | Lin Chaoying | 93 | F |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL | 1 | Song Jiang | 45 | M |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL | 3 | Miejue Shitai | 77 | F |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL | 4 | Lin Chaoying | 93 | F |
| 12 | Wen Qingqing | 19 | F | 1 | NULL | 1 | Song Jiang | 45 | M |
| 12 | Wen Qingqing | 19 | F | 1 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 12 | Wen Qingqing | 19 | F | 1 | NULL | 3 | Miejue Shitai | 77 | F |
| 12 | Wen Qingqing | 19 | F | 1 | NULL | 4 | Lin Chaoying | 93 | F |
| 13 | Tian Boguang | 33 | M | 2 | NULL | 1 | Song Jiang | 45 | M |
| 13 | Tian Boguang | 33 | M | 2 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 13 | Tian Boguang | 33 | M | 2 | NULL | 3 | Miejue Shitai | 77 | F |
| 13 | Tian Boguang | 33 | M | 2 | NULL | 4 | Lin Chaoying | 93 | F |
| 14 | Lu Wushuang | 17 | F | 3 | NULL | 1 | Song Jiang | 45 | M |
| 14 | Lu Wushuang | 17 | F | 3 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 14 | Lu Wushuang | 17 | F | 3 | NULL | 3 | Miejue Shitai | 77 | F |
| 14 | Lu Wushuang | 17 | F | 3 | NULL | 4 | Lin Chaoying | 93 | F |
| 15 | Duan Yu | 19 | M | 4 | NULL | 1 | Song Jiang | 45 | M |
| 15 | Duan Yu | 19 | M | 4 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 15 | Duan Yu | 19 | M | 4 | NULL | 3 | Miejue Shitai | 77 | F |
| 15 | Duan Yu | 19 | M | 4 | NULL | 4 | Lin Chaoying | 93 | F |
| 16 | Xu Zhu | 21 | M | 1 | NULL | 1 | Song Jiang | 45 | M |
| 16 | Xu Zhu | 21 | M | 1 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 16 | Xu Zhu | 21 | M | 1 | NULL | 3 | Miejue Shitai | 77 | F |
| 16 | Xu Zhu | 21 | M | 1 | NULL | 4 | Lin Chaoying | 93 | F |
| 17 | Lin Chong | 25 | M | 4 | NULL | 1 | Song Jiang | 45 | M |
| 17 | Lin Chong | 25 | M | 4 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 17 | Lin Chong | 25 | M | 4 | NULL | 3 | Miejue Shitai | 77 | F |
| 17 | Lin Chong | 25 | M | 4 | NULL | 4 | Lin Chaoying | 93 | F |
| 18 | Hua Rong | 23 | M | 7 | NULL | 1 | Song Jiang | 45 | M |
| 18 | Hua Rong | 23 | M | 7 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 18 | Hua Rong | 23 | M | 7 | NULL | 3 | Miejue Shitai | 77 | F |
| 18 | Hua Rong | 23 | M | 7 | NULL | 4 | Lin Chaoying | 93 | F |
| 19 | Xue Baochai | 18 | F | 6 | NULL | 1 | Song Jiang | 45 | M |
| 19 | Xue Baochai | 18 | F | 6 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 19 | Xue Baochai | 18 | F | 6 | NULL | 3 | Miejue Shitai | 77 | F |
| 19 | Xue Baochai | 18 | F | 6 | NULL | 4 | Lin Chaoying | 93 | F |
| 20 | Diao Chan | 19 | F | 7 | NULL | 1 | Song Jiang | 45 | M |
| 20 | Diao Chan | 19 | F | 7 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 20 | Diao Chan | 19 | F | 7 | NULL | 3 | Miejue Shitai | 77 | F |
| 20 | Diao Chan | 19 | F | 7 | NULL | 4 | Lin Chaoying | 93 | F |
| 21 | Huang Yueying | 22 | F | 6 | NULL | 1 | Song Jiang | 45 | M |
| 21 | Huang Yueying | 22 | F | 6 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 21 | Huang Yueying | 22 | F | 6 | NULL | 3 | Miejue Shitai | 77 | F |
| 21 | Huang Yueying | 22 | F | 6 | NULL | 4 | Lin Chaoying | 93 | F |
| 22 | Xiao Qiao | 20 | F | 1 | NULL | 1 | Song Jiang | 45 | M |
| 22 | Xiao Qiao | 20 | F | 1 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 22 | Xiao Qiao | 20 | F | 1 | NULL | 3 | Miejue Shitai | 77 | F |
| 22 | Xiao Qiao | 20 | F | 1 | NULL | 4 | Lin Chaoying | 93 | F |
| 23 | Ma Chao | 23 | M | 4 | NULL | 1 | Song Jiang | 45 | M |
| 23 | Ma Chao | 23 | M | 4 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 23 | Ma Chao | 23 | M | 4 | NULL | 3 | Miejue Shitai | 77 | F |
| 23 | Ma Chao | 23 | M | 4 | NULL | 4 | Lin Chaoying | 93 | F |
| 24 | Xu Xian | 27 | M | NULL | NULL | 1 | Song Jiang | 45 | M |
| 24 | Xu Xian | 27 | M | NULL | NULL | 2 | Zhang Sanfeng | 94 | M |
| 24 | Xu Xian | 27 | M | NULL | NULL | 3 | Miejue Shitai | 77 | F |
| 24 | Xu Xian | 27 | M | NULL | NULL | 4 | Lin Chaoying | 93 | F |
| 25 | Sun Dasheng | 100 | M | NULL | NULL | 1 | Song Jiang | 45 | M |
| 25 | Sun Dasheng | 100 | M | NULL | NULL | 2 | Zhang Sanfeng | 94 | M |
| 25 | Sun Dasheng | 100 | M | NULL | NULL | 3 | Miejue Shitai | 77 | F |
| 25 | Sun Dasheng | 100 | M | NULL | NULL | 4 | Lin Chaoying | 93 | F |
+-------+---------------+-----+--------+---------+-----------+-----+---------------+-----+--------+
100 rows in set (0.01 sec)
##报错:2张表里都有name字段,所以报错了
MariaDB [hellodb]> select stuid,name,age,tid,name,age from students cross join teachers;
ERROR 1052 (23000): Column 'name' in field list is ambiguous
##
MariaDB [hellodb]> select stuid,students.name,students.age,tid,teachers.name,teachers.age from students cross join teachers;
##这里给表起个别名,更简洁。
MariaDB [hellodb]> select stuid,s.name,s.age,tid,t.name,t.age from students s cross join teachers t;
+-------+---------------+-----+-----+---------------+-----+
| stuid | name | age | tid | 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 | 93 |
| 2 | Shi Potian | 22 | 1 | Song Jiang | 45 |
| 2 | Shi Potian | 22 | 2 | Zhang Sanfeng | 94 |
| 2 | Shi Potian | 22 | 3 | Miejue Shitai | 77 |
| 2 | Shi Potian | 22 | 4 | Lin Chaoying | 93 |
| 3 | Xie Yanke | 53 | 1 | Song Jiang | 45 |
| 3 | Xie Yanke | 53 | 2 | Zhang Sanfeng | 94 |
| 3 | Xie Yanke | 53 | 3 | Miejue Shitai | 77 |
| 3 | Xie Yanke | 53 | 4 | Lin Chaoying | 93 |
| 4 | Ding Dian | 32 | 1 | Song Jiang | 45 |
| 4 | Ding Dian | 32 | 2 | Zhang Sanfeng | 94 |
| 4 | Ding Dian | 32 | 3 | Miejue Shitai | 77 |
| 4 | Ding Dian | 32 | 4 | Lin Chaoying | 93 |
| 5 | Yu Yutong | 26 | 1 | Song Jiang | 45 |
| 5 | Yu Yutong | 26 | 2 | Zhang Sanfeng | 94 |
| 5 | Yu Yutong | 26 | 3 | Miejue Shitai | 77 |
| 5 | Yu Yutong | 26 | 4 | Lin Chaoying | 93 |
| 6 | Shi Qing | 46 | 1 | Song Jiang | 45 |
| 6 | Shi Qing | 46 | 2 | Zhang Sanfeng | 94 |
| 6 | Shi Qing | 46 | 3 | Miejue Shitai | 77 |
| 6 | Shi Qing | 46 | 4 | Lin Chaoying | 93 |
| 7 | Xi Ren | 19 | 1 | Song Jiang | 45 |
| 7 | Xi Ren | 19 | 2 | Zhang Sanfeng | 94 |
| 7 | Xi Ren | 19 | 3 | Miejue Shitai | 77 |
| 7 | Xi Ren | 19 | 4 | Lin Chaoying | 93 |
| 8 | Lin Daiyu | 17 | 1 | Song Jiang | 45 |
| 8 | Lin Daiyu | 17 | 2 | Zhang Sanfeng | 94 |
| 8 | Lin Daiyu | 17 | 3 | Miejue Shitai | 77 |
| 8 | Lin Daiyu | 17 | 4 | Lin Chaoying | 93 |
| 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 | 93 |
| 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 | 93 |
| 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 | 93 |
| 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 | 93 |
| 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 | 93 |
| 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 | 93 |
| 15 | Duan Yu | 19 | 1 | Song Jiang | 45 |
| 15 | Duan Yu | 19 | 2 | Zhang Sanfeng | 94 |
| 15 | Duan Yu | 19 | 3 | Miejue Shitai | 77 |
| 15 | Duan Yu | 19 | 4 | Lin Chaoying | 93 |
| 16 | Xu Zhu | 21 | 1 | Song Jiang | 45 |
| 16 | Xu Zhu | 21 | 2 | Zhang Sanfeng | 94 |
| 16 | Xu Zhu | 21 | 3 | Miejue Shitai | 77 |
| 16 | Xu Zhu | 21 | 4 | Lin Chaoying | 93 |
| 17 | Lin Chong | 25 | 1 | Song Jiang | 45 |
| 17 | Lin Chong | 25 | 2 | Zhang Sanfeng | 94 |
| 17 | Lin Chong | 25 | 3 | Miejue Shitai | 77 |
| 17 | Lin Chong | 25 | 4 | Lin Chaoying | 93 |
| 18 | Hua Rong | 23 | 1 | Song Jiang | 45 |
| 18 | Hua Rong | 23 | 2 | Zhang Sanfeng | 94 |
| 18 | Hua Rong | 23 | 3 | Miejue Shitai | 77 |
| 18 | Hua Rong | 23 | 4 | Lin Chaoying | 93 |
| 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 | 93 |
| 20 | Diao Chan | 19 | 1 | Song Jiang | 45 |
| 20 | Diao Chan | 19 | 2 | Zhang Sanfeng | 94 |
| 20 | Diao Chan | 19 | 3 | Miejue Shitai | 77 |
| 20 | Diao Chan | 19 | 4 | Lin Chaoying | 93 |
| 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 | 93 |
| 22 | Xiao Qiao | 20 | 1 | Song Jiang | 45 |
| 22 | Xiao Qiao | 20 | 2 | Zhang Sanfeng | 94 |
| 22 | Xiao Qiao | 20 | 3 | Miejue Shitai | 77 |
| 22 | Xiao Qiao | 20 | 4 | Lin Chaoying | 93 |
| 23 | Ma Chao | 23 | 1 | Song Jiang | 45 |
| 23 | Ma Chao | 23 | 2 | Zhang Sanfeng | 94 |
| 23 | Ma Chao | 23 | 3 | Miejue Shitai | 77 |
| 23 | Ma Chao | 23 | 4 | Lin Chaoying | 93 |
| 24 | Xu Xian | 27 | 1 | Song Jiang | 45 |
| 24 | Xu Xian | 27 | 2 | Zhang Sanfeng | 94 |
| 24 | Xu Xian | 27 | 3 | Miejue Shitai | 77 |
| 24 | Xu Xian | 27 | 4 | Lin Chaoying | 93 |
| 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 | 93 |
+-------+---------------+-----+-----+---------------+-----+
100 rows in set (0.00 sec)
##再次修改:
MariaDB [hellodb]> select stuid,s.name 学生姓名,s.age 学生年龄,tid,t.name 老师姓名,t.age 老师年龄 from students s cross join teachers t;
+-------+---------------+--------------+-----+---------------+--------------+
| stuid | 学生姓名 | 学生年龄 | tid | 老师姓名 | 老师年龄 |
+-------+---------------+--------------+-----+---------------+--------------+
| 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 | 93 |
| 2 | Shi Potian | 22 | 1 | Song Jiang | 45 |
| 2 | Shi Potian | 22 | 2 | Zhang Sanfeng | 94 |
| 2 | Shi Potian | 22 | 3 | Miejue Shitai | 77 |
| 2 | Shi Potian | 22 | 4 | Lin Chaoying | 93 |
| 3 | Xie Yanke | 53 | 1 | Song Jiang | 45 |
| 3 | Xie Yanke | 53 | 2 | Zhang Sanfeng | 94 |
| 3 | Xie Yanke | 53 | 3 | Miejue Shitai | 77 |
| 3 | Xie Yanke | 53 | 4 | Lin Chaoying | 93 |
| 4 | Ding Dian | 32 | 1 | Song Jiang | 45 |
| 4 | Ding Dian | 32 | 2 | Zhang Sanfeng | 94 |
| 4 | Ding Dian | 32 | 3 | Miejue Shitai | 77 |
| 4 | Ding Dian | 32 | 4 | Lin Chaoying | 93 |
| 5 | Yu Yutong | 26 | 1 | Song Jiang | 45 |
| 5 | Yu Yutong | 26 | 2 | Zhang Sanfeng | 94 |
| 5 | Yu Yutong | 26 | 3 | Miejue Shitai | 77 |
| 5 | Yu Yutong | 26 | 4 | Lin Chaoying | 93 |
| 6 | Shi Qing | 46 | 1 | Song Jiang | 45 |
| 6 | Shi Qing | 46 | 2 | Zhang Sanfeng | 94 |
| 6 | Shi Qing | 46 | 3 | Miejue Shitai | 77 |
| 6 | Shi Qing | 46 | 4 | Lin Chaoying | 93 |
| 7 | Xi Ren | 19 | 1 | Song Jiang | 45 |
| 7 | Xi Ren | 19 | 2 | Zhang Sanfeng | 94 |
| 7 | Xi Ren | 19 | 3 | Miejue Shitai | 77 |
| 7 | Xi Ren | 19 | 4 | Lin Chaoying | 93 |
| 8 | Lin Daiyu | 17 | 1 | Song Jiang | 45 |
| 8 | Lin Daiyu | 17 | 2 | Zhang Sanfeng | 94 |
| 8 | Lin Daiyu | 17 | 3 | Miejue Shitai | 77 |
| 8 | Lin Daiyu | 17 | 4 | Lin Chaoying | 93 |
| 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 | 93 |
| 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 | 93 |
| 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 | 93 |
| 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 | 93 |
| 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 | 93 |
| 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 | 93 |
| 15 | Duan Yu | 19 | 1 | Song Jiang | 45 |
| 15 | Duan Yu | 19 | 2 | Zhang Sanfeng | 94 |
| 15 | Duan Yu | 19 | 3 | Miejue Shitai | 77 |
| 15 | Duan Yu | 19 | 4 | Lin Chaoying | 93 |
| 16 | Xu Zhu | 21 | 1 | Song Jiang | 45 |
| 16 | Xu Zhu | 21 | 2 | Zhang Sanfeng | 94 |
| 16 | Xu Zhu | 21 | 3 | Miejue Shitai | 77 |
| 16 | Xu Zhu | 21 | 4 | Lin Chaoying | 93 |
| 17 | Lin Chong | 25 | 1 | Song Jiang | 45 |
| 17 | Lin Chong | 25 | 2 | Zhang Sanfeng | 94 |
| 17 | Lin Chong | 25 | 3 | Miejue Shitai | 77 |
| 17 | Lin Chong | 25 | 4 | Lin Chaoying | 93 |
| 18 | Hua Rong | 23 | 1 | Song Jiang | 45 |
| 18 | Hua Rong | 23 | 2 | Zhang Sanfeng | 94 |
| 18 | Hua Rong | 23 | 3 | Miejue Shitai | 77 |
| 18 | Hua Rong | 23 | 4 | Lin Chaoying | 93 |
| 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 | 93 |
| 20 | Diao Chan | 19 | 1 | Song Jiang | 45 |
| 20 | Diao Chan | 19 | 2 | Zhang Sanfeng | 94 |
| 20 | Diao Chan | 19 | 3 | Miejue Shitai | 77 |
| 20 | Diao Chan | 19 | 4 | Lin Chaoying | 93 |
| 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 | 93 |
| 22 | Xiao Qiao | 20 | 1 | Song Jiang | 45 |
| 22 | Xiao Qiao | 20 | 2 | Zhang Sanfeng | 94 |
| 22 | Xiao Qiao | 20 | 3 | Miejue Shitai | 77 |
| 22 | Xiao Qiao | 20 | 4 | Lin Chaoying | 93 |
| 23 | Ma Chao | 23 | 1 | Song Jiang | 45 |
| 23 | Ma Chao | 23 | 2 | Zhang Sanfeng | 94 |
| 23 | Ma Chao | 23 | 3 | Miejue Shitai | 77 |
| 23 | Ma Chao | 23 | 4 | Lin Chaoying | 93 |
| 24 | Xu Xian | 27 | 1 | Song Jiang | 45 |
| 24 | Xu Xian | 27 | 2 | Zhang Sanfeng | 94 |
| 24 | Xu Xian | 27 | 3 | Miejue Shitai | 77 |
| 24 | Xu Xian | 27 | 4 | Lin Chaoying | 93 |
| 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 | 93 |
+-------+---------------+--------------+-----+---------------+--------------+
100 rows in set (0.00 sec)
内连接
两张表交叉连接之后,符合条件的信息。
内连接不分谁在前,谁在后。但左、右外连接,得分左右了。
- 范例:内连接
#内连接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 | 26 | M | 3 | 1 | 1 | Song Jiang | 45 | M |
| 1 | Shi Zhongyu | 22 | M | 2 | 3 | 3 | Miejue Shitai | 77 | F |
| 4 | Ding Dian | 32 | M | 4 | 4 | 4 | Lin Chaoying | 93 | F |
+-------+-------------+-----+--------+---------+-----------+-----+---------------+-----+--------+
3 rows in set (0.00 sec)
MariaDB [hellodb]> select *from students s inner join teachers t on s.teacherid=t.tid;
+-------+-------------+-----+--------+---------+-----------+-----+---------------+-----+--------+
| StuID | Name | Age | Gender | ClassID | TeacherID | TID | Name | Age | Gender |
+-------+-------------+-----+--------+---------+-----------+-----+---------------+-----+--------+
| 5 | Yu Yutong | 26 | M | 3 | 1 | 1 | Song Jiang | 45 | M |
| 1 | Shi Zhongyu | 22 | M | 2 | 3 | 3 | Miejue Shitai | 77 | F |
| 4 | Ding Dian | 32 | M | 4 | 4 | 4 | Lin Chaoying | 93 | F |
+-------+-------------+-----+--------+---------+-----------+-----+---------------+-----+--------+
3 rows in set (0.00 sec)
##另一个逻辑:哈哈(男女搭配,干活不累)
MariaDB [hellodb]> select *from students s inner join teachers t on s.gender != t.gender;
MariaDB [hellodb]> select *from students s inner join teachers t on s.gender='m' and t.gender='F' or s.gender='F' and t.gender='M' ;
+-------+---------------+-----+--------+---------+-----------+-----+---------------+-----+--------+
| StuID | Name | Age | Gender | ClassID | TeacherID | TID | Name | Age | Gender |
+-------+---------------+-----+--------+---------+-----------+-----+---------------+-----+--------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 | 3 | Miejue Shitai | 77 | F |
| 1 | Shi Zhongyu | 22 | M | 2 | 3 | 4 | Lin Chaoying | 93 | F |
| 2 | Shi Potian | 22 | M | 1 | 7 | 3 | Miejue Shitai | 77 | F |
| 2 | Shi Potian | 22 | M | 1 | 7 | 4 | Lin Chaoying | 93 | F |
| 3 | Xie Yanke | 53 | M | 2 | 16 | 3 | Miejue Shitai | 77 | F |
| 3 | Xie Yanke | 53 | M | 2 | 16 | 4 | Lin Chaoying | 93 | F |
| 4 | Ding Dian | 32 | M | 4 | 4 | 3 | Miejue Shitai | 77 | F |
| 4 | Ding Dian | 32 | M | 4 | 4 | 4 | Lin Chaoying | 93 | F |
| 5 | Yu Yutong | 26 | M | 3 | 1 | 3 | Miejue Shitai | 77 | F |
| 5 | Yu Yutong | 26 | M | 3 | 1 | 4 | Lin Chaoying | 93 | F |
| 6 | Shi Qing | 46 | M | 5 | NULL | 3 | Miejue Shitai | 77 | F |
| 6 | Shi Qing | 46 | M | 5 | NULL | 4 | Lin Chaoying | 93 | F |
| 7 | Xi Ren | 19 | F | 3 | NULL | 1 | Song Jiang | 45 | M |
| 7 | Xi Ren | 19 | F | 3 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 8 | Lin Daiyu | 17 | F | 7 | NULL | 1 | Song Jiang | 45 | M |
| 8 | Lin Daiyu | 17 | F | 7 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 9 | Ren Yingying | 20 | F | 6 | NULL | 1 | Song Jiang | 45 | M |
| 9 | Ren Yingying | 20 | F | 6 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 10 | Yue Lingshan | 19 | F | 3 | NULL | 1 | Song Jiang | 45 | M |
| 10 | Yue Lingshan | 19 | F | 3 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL | 3 | Miejue Shitai | 77 | F |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL | 4 | Lin Chaoying | 93 | F |
| 12 | Wen Qingqing | 19 | F | 1 | NULL | 1 | Song Jiang | 45 | M |
| 12 | Wen Qingqing | 19 | F | 1 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 13 | Tian Boguang | 33 | M | 2 | NULL | 3 | Miejue Shitai | 77 | F |
| 13 | Tian Boguang | 33 | M | 2 | NULL | 4 | Lin Chaoying | 93 | F |
| 14 | Lu Wushuang | 17 | F | 3 | NULL | 1 | Song Jiang | 45 | M |
| 14 | Lu Wushuang | 17 | F | 3 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 15 | Duan Yu | 19 | M | 4 | NULL | 3 | Miejue Shitai | 77 | F |
| 15 | Duan Yu | 19 | M | 4 | NULL | 4 | Lin Chaoying | 93 | F |
| 16 | Xu Zhu | 21 | M | 1 | NULL | 3 | Miejue Shitai | 77 | F |
| 16 | Xu Zhu | 21 | M | 1 | NULL | 4 | Lin Chaoying | 93 | F |
| 17 | Lin Chong | 25 | M | 4 | NULL | 3 | Miejue Shitai | 77 | F |
| 17 | Lin Chong | 25 | M | 4 | NULL | 4 | Lin Chaoying | 93 | F |
| 18 | Hua Rong | 23 | M | 7 | NULL | 3 | Miejue Shitai | 77 | F |
| 18 | Hua Rong | 23 | M | 7 | NULL | 4 | Lin Chaoying | 93 | F |
| 19 | Xue Baochai | 18 | F | 6 | NULL | 1 | Song Jiang | 45 | M |
| 19 | Xue Baochai | 18 | F | 6 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 20 | Diao Chan | 19 | F | 7 | NULL | 1 | Song Jiang | 45 | M |
| 20 | Diao Chan | 19 | F | 7 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 21 | Huang Yueying | 22 | F | 6 | NULL | 1 | Song Jiang | 45 | M |
| 21 | Huang Yueying | 22 | F | 6 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 22 | Xiao Qiao | 20 | F | 1 | NULL | 1 | Song Jiang | 45 | M |
| 22 | Xiao Qiao | 20 | F | 1 | NULL | 2 | Zhang Sanfeng | 94 | M |
| 23 | Ma Chao | 23 | M | 4 | NULL | 3 | Miejue Shitai | 77 | F |
| 23 | Ma Chao | 23 | M | 4 | NULL | 4 | Lin Chaoying | 93 | F |
| 24 | Xu Xian | 27 | M | NULL | NULL | 3 | Miejue Shitai | 77 | F |
| 24 | Xu Xian | 27 | M | NULL | NULL | 4 | Lin Chaoying | 93 | F |
| 25 | Sun Dasheng | 100 | M | NULL | NULL | 3 | Miejue Shitai | 77 | F |
| 25 | Sun Dasheng | 100 | M | NULL | NULL | 4 | Lin Chaoying | 93 | F |
+-------+---------------+-----+--------+---------+-----------+-----+---------------+-----+--------+
50 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 | 22 | M | Miejue Shitai | 77 | F |
| Shi Zhongyu | 22 | M | Lin Chaoying | 93 | F |
| Shi Potian | 22 | M | Miejue Shitai | 77 | F |
| Shi Potian | 22 | M | Lin Chaoying | 93 | F |
| Xie Yanke | 53 | M | Miejue Shitai | 77 | F |
| Xie Yanke | 53 | M | Lin Chaoying | 93 | F |
| Ding Dian | 32 | M | Miejue Shitai | 77 | F |
| Ding Dian | 32 | M | Lin Chaoying | 93 | F |
| Yu Yutong | 26 | M | Miejue Shitai | 77 | F |
| Yu Yutong | 26 | M | Lin Chaoying | 93 | F |
| Shi Qing | 46 | M | Miejue Shitai | 77 | F |
| Shi Qing | 46 | M | Lin Chaoying | 93 | F |
| Xi Ren | 19 | F | Song Jiang | 45 | M |
| Xi Ren | 19 | F | Zhang Sanfeng | 94 | M |
| Lin Daiyu | 17 | F | Song Jiang | 45 | M |
| Lin Daiyu | 17 | F | Zhang Sanfeng | 94 | M |
| Ren Yingying | 20 | F | Song Jiang | 45 | M |
| Ren Yingying | 20 | F | Zhang Sanfeng | 94 | M |
| Yue Lingshan | 19 | F | Song Jiang | 45 | M |
| Yue Lingshan | 19 | F | Zhang Sanfeng | 94 | M |
| Yuan Chengzhi | 23 | M | Miejue Shitai | 77 | F |
| Yuan Chengzhi | 23 | M | Lin Chaoying | 93 | F |
| Wen Qingqing | 19 | F | Song Jiang | 45 | M |
| Wen Qingqing | 19 | F | Zhang Sanfeng | 94 | M |
| Tian Boguang | 33 | M | Miejue Shitai | 77 | F |
| Tian Boguang | 33 | M | Lin Chaoying | 93 | F |
| Lu Wushuang | 17 | F | Song Jiang | 45 | M |
| Lu Wushuang | 17 | F | Zhang Sanfeng | 94 | M |
| Duan Yu | 19 | M | Miejue Shitai | 77 | F |
| Duan Yu | 19 | M | Lin Chaoying | 93 | F |
| Xu Zhu | 21 | M | Miejue Shitai | 77 | F |
| Xu Zhu | 21 | M | Lin Chaoying | 93 | F |
| Lin Chong | 25 | M | Miejue Shitai | 77 | F |
| Lin Chong | 25 | M | Lin Chaoying | 93 | F |
| Hua Rong | 23 | M | Miejue Shitai | 77 | F |
| Hua Rong | 23 | M | Lin Chaoying | 93 | F |
| Xue Baochai | 18 | F | Song Jiang | 45 | M |
| Xue Baochai | 18 | F | Zhang Sanfeng | 94 | M |
| Diao Chan | 19 | F | Song Jiang | 45 | M |
| Diao Chan | 19 | F | Zhang Sanfeng | 94 | M |
| Huang Yueying | 22 | F | Song Jiang | 45 | M |
| Huang Yueying | 22 | F | Zhang Sanfeng | 94 | M |
| Xiao Qiao | 20 | F | Song Jiang | 45 | M |
| Xiao Qiao | 20 | F | Zhang Sanfeng | 94 | M |
| Ma Chao | 23 | M | Miejue Shitai | 77 | F |
| Ma Chao | 23 | M | Lin Chaoying | 93 | F |
| Xu Xian | 27 | M | Miejue Shitai | 77 | F |
| Xu Xian | 27 | M | Lin Chaoying | 93 | F |
| Sun Dasheng | 100 | M | Miejue Shitai | 77 | F |
| Sun Dasheng | 100 | M | Lin Chaoying | 93 | F |
+---------------+--------------+--------------+---------------+--------------+--------------+
50 rows in set (0.00 sec)
##范例:另一种古老的写法(这个写法也是可以的)
MariaDB [hellodb]> select s.name 学生姓名,s.age 学生年龄,s.gender 学生性别,t.name 老师姓名,t.age 老师年龄, t.gender 老师性别 from students s, teachers t where s.gender <> t.gender;
##进一步再去过滤
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 where t.age<=50;
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 and t.age<=50;
左和右外连接
- 范例:左,右外连接
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 | 26 | M | 3 | 1 | 1 | Song Jiang | 45 | M |
| 1 | Shi Zhongyu | 22 | M | 2 | 3 | 3 | Miejue Shitai | 77 | F |
| 4 | Ding Dian | 32 | M | 4 | 4 | 4 | Lin Chaoying | 93 | F |
+-------+-------------+-----+--------+---------+-----------+-----+---------------+-----+--------+
3 rows in set (0.00 sec)
MariaDB [hellodb]> select *from students left join teachers on students.teacherid=teachers.tid;
+-------+---------------+-----+--------+---------+-----------+------+---------------+------+--------+
| StuID | Name | Age | Gender | ClassID | TeacherID | TID | Name | Age | Gender |
+-------+---------------+-----+--------+---------+-----------+------+---------------+------+--------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 | 3 | Miejue Shitai | 77 | F |
| 2 | Shi Potian | 22 | M | 1 | 7 | NULL | NULL | NULL | NULL |
| 3 | Xie Yanke | 53 | M | 2 | 16 | NULL | NULL | NULL | NULL |
| 4 | Ding Dian | 32 | M | 4 | 4 | 4 | Lin Chaoying | 93 | F |
| 5 | Yu Yutong | 26 | M | 3 | 1 | 1 | Song Jiang | 45 | M |
| 6 | Shi Qing | 46 | M | 5 | NULL | NULL | NULL | NULL | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL | NULL | NULL | NULL | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL | NULL | NULL | NULL | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL | NULL | NULL | NULL | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL | NULL | NULL | NULL | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL | NULL | NULL | NULL | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL | NULL | NULL | NULL | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL | NULL | NULL | NULL | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL | NULL | NULL | NULL | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL | NULL | NULL | NULL | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL | NULL | NULL | NULL | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL | NULL | NULL | NULL | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL | NULL | NULL | NULL | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL | NULL | NULL | NULL | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL | NULL | NULL | NULL | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL | NULL | NULL | NULL | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL | NULL | NULL | NULL | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL | NULL | NULL | NULL | NULL |
| 24 | Xu Xian | 27 | M | NULL | NULL | NULL | NULL | NULL | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL | NULL | NULL | NULL | NULL |
+-------+---------------+-----+--------+---------+-----------+------+---------------+------+--------+
25 rows in set (0.00 sec)
#谁左谁右很关键。
MariaDB [hellodb]> select *from teachers left join students on students.teacherid=teachers.tid;
+-----+---------------+-----+--------+-------+-------------+------+--------+---------+-----------+
| TID | Name | Age | Gender | StuID | Name | Age | Gender | ClassID | TeacherID |
+-----+---------------+-----+--------+-------+-------------+------+--------+---------+-----------+
| 3 | Miejue Shitai | 77 | F | 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 4 | Lin Chaoying | 93 | F | 4 | Ding Dian | 32 | M | 4 | 4 |
| 1 | Song Jiang | 45 | M | 5 | Yu Yutong | 26 | M | 3 | 1 |
| 2 | Zhang Sanfeng | 94 | M | NULL | NULL | NULL | NULL | NULL | NULL |
+-----+---------------+-----+--------+-------+-------------+------+--------+---------+-----------+
4 rows in set (0.00 sec)
##右外连接
MariaDB [hellodb]> select *from teachers right join students on students.teacherid=teachers.tid;
+------+---------------+------+--------+-------+---------------+-----+--------+---------+-----------+
| TID | Name | Age | Gender | StuID | Name | Age | Gender | ClassID | TeacherID |
+------+---------------+------+--------+-------+---------------+-----+--------+---------+-----------+
| 3 | Miejue Shitai | 77 | F | 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| NULL | NULL | NULL | NULL | 2 | Shi Potian | 22 | M | 1 | 7 |
| NULL | NULL | NULL | NULL | 3 | Xie Yanke | 53 | M | 2 | 16 |
| 4 | Lin Chaoying | 93 | F | 4 | Ding Dian | 32 | M | 4 | 4 |
| 1 | Song Jiang | 45 | M | 5 | Yu Yutong | 26 | M | 3 | 1 |
| NULL | NULL | NULL | NULL | 6 | Shi Qing | 46 | M | 5 | NULL |
| NULL | NULL | NULL | NULL | 7 | Xi Ren | 19 | F | 3 | NULL |
| NULL | NULL | NULL | NULL | 8 | Lin Daiyu | 17 | F | 7 | NULL |
| NULL | NULL | NULL | NULL | 9 | Ren Yingying | 20 | F | 6 | NULL |
| NULL | NULL | NULL | NULL | 10 | Yue Lingshan | 19 | F | 3 | NULL |
| NULL | NULL | NULL | NULL | 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| NULL | NULL | NULL | NULL | 12 | Wen Qingqing | 19 | F | 1 | NULL |
| NULL | NULL | NULL | NULL | 13 | Tian Boguang | 33 | M | 2 | NULL |
| NULL | NULL | NULL | NULL | 14 | Lu Wushuang | 17 | F | 3 | NULL |
| NULL | NULL | NULL | NULL | 15 | Duan Yu | 19 | M | 4 | NULL |
| NULL | NULL | NULL | NULL | 16 | Xu Zhu | 21 | M | 1 | NULL |
| NULL | NULL | NULL | NULL | 17 | Lin Chong | 25 | M | 4 | NULL |
| NULL | NULL | NULL | NULL | 18 | Hua Rong | 23 | M | 7 | NULL |
| NULL | NULL | NULL | NULL | 19 | Xue Baochai | 18 | F | 6 | NULL |
| NULL | NULL | NULL | NULL | 20 | Diao Chan | 19 | F | 7 | NULL |
| NULL | NULL | NULL | NULL | 21 | Huang Yueying | 22 | F | 6 | NULL |
| NULL | NULL | NULL | NULL | 22 | Xiao Qiao | 20 | F | 1 | NULL |
| NULL | NULL | NULL | NULL | 23 | Ma Chao | 23 | M | 4 | NULL |
| NULL | NULL | NULL | NULL | 24 | Xu Xian | 27 | M | NULL | NULL |
| NULL | NULL | NULL | NULL | 25 | Sun Dasheng | 100 | M | NULL | NULL |
+------+---------------+------+--------+-------+---------------+-----+--------+---------+-----------+
25 rows in set (0.00 sec)
- 范例:左外连接的扩展用法
MariaDB [hellodb]> select *from students left join teachers on students.teacherid=teachers.tid where tid is null;
+-------+---------------+-----+--------+---------+-----------+------+------+------+--------+
| StuID | Name | Age | Gender | ClassID | TeacherID | TID | Name | Age | Gender |
+-------+---------------+-----+--------+---------+-----------+------+------+------+--------+
| 2 | Shi Potian | 22 | M | 1 | 7 | NULL | NULL | NULL | NULL |
| 3 | Xie Yanke | 53 | M | 2 | 16 | NULL | NULL | NULL | NULL |
| 6 | Shi Qing | 46 | M | 5 | NULL | NULL | NULL | NULL | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL | NULL | NULL | NULL | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL | NULL | NULL | NULL | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL | NULL | NULL | NULL | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL | NULL | NULL | NULL | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL | NULL | NULL | NULL | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL | NULL | NULL | NULL | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL | NULL | NULL | NULL | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL | NULL | NULL | NULL | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL | NULL | NULL | NULL | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL | NULL | NULL | NULL | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL | NULL | NULL | NULL | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL | NULL | NULL | NULL | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL | NULL | NULL | NULL | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL | NULL | NULL | NULL | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL | NULL | NULL | NULL | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL | NULL | NULL | NULL | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL | NULL | NULL | NULL | NULL |
| 24 | Xu Xian | 27 | M | NULL | NULL | NULL | NULL | NULL | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL | NULL | NULL | NULL | NULL |
+-------+---------------+-----+--------+---------+-----------+------+------+------+--------+
22 rows in set (0.00 sec)
完全外连接
可惜,mysql里不支持完全外连接这种语法!
- 范例:完全外连接
#可惜,mysql里不支持完全外连接这种语法!
MariaDB [hellodb]> select *from students full outer join teachers on students.teacherid=teachers.tid;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'outer join teachers on students.teacherid=teachers.tid' at line 1
MariaDB [hellodb]> select *from students full join teachers on students.teacherid=teachers.tid;
ERROR 1054 (42S22): Unknown column 'students.teacherid' in 'on clause'
- 范例:我们可以通过其它方式来实现:
对这2种表union,且union可以去重。
注意:这个不是交叉连接哦。
MariaDB [hellodb]> select *from students left join teachers on students.teacherid=teachers.tid;
+-------+---------------+-----+--------+---------+-----------+------+---------------+------+--------+
| StuID | Name | Age | Gender | ClassID | TeacherID | TID | Name | Age | Gender |
+-------+---------------+-----+--------+---------+-----------+------+---------------+------+--------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 | 3 | Miejue Shitai | 77 | F |
| 2 | Shi Potian | 22 | M | 1 | 7 | NULL | NULL | NULL | NULL |
| 3 | Xie Yanke | 53 | M | 2 | 16 | NULL | NULL | NULL | NULL |
| 4 | Ding Dian | 32 | M | 4 | 4 | 4 | Lin Chaoying | 93 | F |
| 5 | Yu Yutong | 26 | M | 3 | 1 | 1 | Song Jiang | 45 | M |
| 6 | Shi Qing | 46 | M | 5 | NULL | NULL | NULL | NULL | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL | NULL | NULL | NULL | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL | NULL | NULL | NULL | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL | NULL | NULL | NULL | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL | NULL | NULL | NULL | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL | NULL | NULL | NULL | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL | NULL | NULL | NULL | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL | NULL | NULL | NULL | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL | NULL | NULL | NULL | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL | NULL | NULL | NULL | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL | NULL | NULL | NULL | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL | NULL | NULL | NULL | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL | NULL | NULL | NULL | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL | NULL | NULL | NULL | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL | NULL | NULL | NULL | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL | NULL | NULL | NULL | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL | NULL | NULL | NULL | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL | NULL | NULL | NULL | NULL |
| 24 | Xu Xian | 27 | M | NULL | NULL | NULL | NULL | NULL | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL | NULL | NULL | NULL | NULL |
+-------+---------------+-----+--------+---------+-----------+------+---------------+------+--------+
25 rows in set (0.00 sec)
MariaDB [hellodb]> select *from students right join teachers on students.teacherid=teachers.tid;
+-------+-------------+------+--------+---------+-----------+-----+---------------+-----+--------+
| StuID | Name | Age | Gender | ClassID | TeacherID | TID | Name | Age | Gender |
+-------+-------------+------+--------+---------+-----------+-----+---------------+-----+--------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 | 3 | Miejue Shitai | 77 | F |
| 4 | Ding Dian | 32 | M | 4 | 4 | 4 | Lin Chaoying | 93 | F |
| 5 | Yu Yutong | 26 | M | 3 | 1 | 1 | Song Jiang | 45 | M |
| NULL | NULL | NULL | NULL | NULL | NULL | 2 | Zhang Sanfeng | 94 | M |
+-------+-------------+------+--------+---------+-----------+-----+---------------+-----+--------+
4 rows in set (0.00 sec)
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;
+-------+---------------+------+--------+---------+-----------+------+---------------+------+--------+
| StuID | Name | Age | Gender | ClassID | TeacherID | TID | Name | Age | Gender |
+-------+---------------+------+--------+---------+-----------+------+---------------+------+--------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 | 3 | Miejue Shitai | 77 | F |
| 2 | Shi Potian | 22 | M | 1 | 7 | NULL | NULL | NULL | NULL |
| 3 | Xie Yanke | 53 | M | 2 | 16 | NULL | NULL | NULL | NULL |
| 4 | Ding Dian | 32 | M | 4 | 4 | 4 | Lin Chaoying | 93 | F |
| 5 | Yu Yutong | 26 | M | 3 | 1 | 1 | Song Jiang | 45 | M |
| 6 | Shi Qing | 46 | M | 5 | NULL | NULL | NULL | NULL | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL | NULL | NULL | NULL | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL | NULL | NULL | NULL | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL | NULL | NULL | NULL | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL | NULL | NULL | NULL | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL | NULL | NULL | NULL | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL | NULL | NULL | NULL | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL | NULL | NULL | NULL | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL | NULL | NULL | NULL | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL | NULL | NULL | NULL | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL | NULL | NULL | NULL | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL | NULL | NULL | NULL | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL | NULL | NULL | NULL | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL | NULL | NULL | NULL | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL | NULL | NULL | NULL | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL | NULL | NULL | NULL | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL | NULL | NULL | NULL | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL | NULL | NULL | NULL | NULL |
| 24 | Xu Xian | 27 | M | NULL | NULL | NULL | NULL | NULL | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL | NULL | NULL | NULL | NULL |
| NULL | NULL | NULL | NULL | NULL | NULL | 2 | Zhang Sanfeng | 94 | M |
+-------+---------------+------+--------+---------+-----------+------+---------------+------+--------+
26 rows in set (0.00 sec)
MariaDB [hellodb]>
通过这个方式就实现了
完全外连接
这个功能了。先
左外连接,再右外连接,然后中间union
。
- 范例:这个如何实现呢?
2个变种+union
MariaDB [hellodb]> select *from students left join teachers on students.teacherid=teachers.tid where tid is null;
+-------+---------------+-----+--------+---------+-----------+------+------+------+--------+
| StuID | Name | Age | Gender | ClassID | TeacherID | TID | Name | Age | Gender |
+-------+---------------+-----+--------+---------+-----------+------+------+------+--------+
| 2 | Shi Potian | 22 | M | 1 | 7 | NULL | NULL | NULL | NULL |
| 3 | Xie Yanke | 53 | M | 2 | 16 | NULL | NULL | NULL | NULL |
| 6 | Shi Qing | 46 | M | 5 | NULL | NULL | NULL | NULL | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL | NULL | NULL | NULL | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL | NULL | NULL | NULL | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL | NULL | NULL | NULL | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL | NULL | NULL | NULL | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL | NULL | NULL | NULL | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL | NULL | NULL | NULL | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL | NULL | NULL | NULL | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL | NULL | NULL | NULL | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL | NULL | NULL | NULL | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL | NULL | NULL | NULL | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL | NULL | NULL | NULL | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL | NULL | NULL | NULL | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL | NULL | NULL | NULL | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL | NULL | NULL | NULL | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL | NULL | NULL | NULL | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL | NULL | NULL | NULL | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL | NULL | NULL | NULL | NULL |
| 24 | Xu Xian | 27 | M | NULL | NULL | NULL | NULL | NULL | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL | NULL | NULL | NULL | NULL |
+-------+---------------+-----+--------+---------+-----------+------+------+------+--------+
22 rows in set (0.00 sec)
MariaDB [hellodb]> select *from students right join teachers on students.teacherid=teachers.tid where teacherid is null;
+-------+------+------+--------+---------+-----------+-----+---------------+-----+--------+
| StuID | Name | Age | Gender | ClassID | TeacherID | TID | Name | Age | Gender |
+-------+------+------+--------+---------+-----------+-----+---------------+-----+--------+
| NULL | NULL | NULL | NULL | NULL | NULL | 2 | Zhang Sanfeng | 94 | M |
+-------+------+------+--------+---------+-----------+-----+---------------+-----+--------+
1 row in set (0.00 sec)
MariaDB [hellodb]> select *from students left join teachers on students.teacherid=teachers.tid where tid is null
-> union
-> select *from students right join teachers on students.teacherid=teachers.tid where teacherid is null;
+-------+---------------+------+--------+---------+-----------+------+---------------+------+--------+
| StuID | Name | Age | Gender | ClassID | TeacherID | TID | Name | Age | Gender |
+-------+---------------+------+--------+---------+-----------+------+---------------+------+--------+
| 2 | Shi Potian | 22 | M | 1 | 7 | NULL | NULL | NULL | NULL |
| 3 | Xie Yanke | 53 | M | 2 | 16 | NULL | NULL | NULL | NULL |
| 6 | Shi Qing | 46 | M | 5 | NULL | NULL | NULL | NULL | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL | NULL | NULL | NULL | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL | NULL | NULL | NULL | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL | NULL | NULL | NULL | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL | NULL | NULL | NULL | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL | NULL | NULL | NULL | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL | NULL | NULL | NULL | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL | NULL | NULL | NULL | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL | NULL | NULL | NULL | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL | NULL | NULL | NULL | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL | NULL | NULL | NULL | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL | NULL | NULL | NULL | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL | NULL | NULL | NULL | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL | NULL | NULL | NULL | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL | NULL | NULL | NULL | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL | NULL | NULL | NULL | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL | NULL | NULL | NULL | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL | NULL | NULL | NULL | NULL |
| 24 | Xu Xian | 27 | M | NULL | NULL | NULL | NULL | NULL | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL | NULL | NULL | NULL | NULL |
| NULL | NULL | NULL | NULL | NULL | NULL | 2 | Zhang Sanfeng | 94 | M |
+-------+---------------+------+--------+---------+-----------+------+---------------+------+--------+
23 rows in set (0.00 sec)
自连接
即:表自身连接自身。
把一张表当2张表来用。
- 范例:自连接测试
案例背景:想要查询公司里所有员工的姓名,及对应直属领导姓名。
创建表:
MariaDB [hellodb]> create table emp (id int auto_increment primary key,name varchar(20),leader_id int);
Query OK, 0 rows affected (0.01 sec)
MariaDB [hellodb]> desc emp;
+-----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(20) | YES | | NULL | |
| leader_id | int(11) | YES | | NULL | |
+-----------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
##插入数据
MariaDB [hellodb]> insert emp (name,leader_id)value('mage',null),('zhangsir',1),('wang',2),('zhang',3);
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0
MariaDB [hellodb]> select *from emp;
+----+----------+-----------+
| id | name | leader_id |
+----+----------+-----------+
| 1 | mage | NULL |
| 2 | zhangsir | 1 |
| 3 | wang | 2 |
| 4 | zhang | 3 |
+----+----------+-----------+
4 rows in set (0.00 sec)
如果使用内连接+表别名呢?
MariaDB [hellodb]> select e.name,l.name from emp e inner join emp l on e.leader_id=l.id;
+----------+----------+
| name | name |
+----------+----------+
| zhangsir | mage |
| wang | zhangsir |
| zhang | wang |
+----------+----------+
3 rows in set (0.00 sec)
##存在的问题
把mage给丢了……
最后,选择使用左外连接+表别名
MariaDB [hellodb]> select e.name,l.name from emp e left join emp l on e.leader_id=l.id;
+----------+----------+
| name | name |
+----------+----------+
| mage | NULL |
| zhangsir | mage |
| wang | zhangsir |
| zhang | wang |
+----------+----------+
4 rows in set (0.00 sec)
再次更新:
MariaDB [hellodb]> select e.name,IFNULL(l.name,'无上级') from emp e left join emp l on e.leader_id=l.id;
+----------+----------------------------+
| name | IFNULL(l.name,'无上级') |
+----------+----------------------------+
| mage | 无上级 |
| zhangsir | mage |
| wang | zhangsir |
| zhang | wang |
+----------+----------------------------+
4 rows in set (0.00 sec)
测试结束。
三表连接😊
- 范例:
2张表在什么情况下需要构建出第三张表?
MariaDB [hellodb]> show tables;
+-------------------+
| Tables_in_hellodb |
+-------------------+
| classes |
| coc |
| courses |
| emp |
| scores |
| students |
| teachers |
| teachers2 |
| teachers3 |
| toc |
+-------------------+
10 rows in set (0.00 sec)
MariaDB [hellodb]> select *from students;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL |
| 24 | Xu Xian | 27 | M | NULL | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
+-------+---------------+-----+--------+---------+-----------+
25 rows in set (0.00 sec)
MariaDB [hellodb]> select *from courses;
+----------+----------------+
| CourseID | Course |
+----------+----------------+
| 1 | Hamo Gong |
| 2 | Kuihua Baodian |
| 3 | Jinshe Jianfa |
| 4 | Taiji Quan |
| 5 | Daiyu Zanghua |
| 6 | Weituo Zhang |
| 7 | Dagou Bangfa |
+----------+----------------+
7 rows in set (0.00 sec)
MariaDB [hellodb]> select *from scores;
+----+-------+----------+-------+
| ID | StuID | CourseID | Score |
+----+-------+----------+-------+
| 1 | 1 | 2 | 77 |
| 2 | 1 | 6 | 93 |
| 3 | 2 | 2 | 47 |
| 4 | 2 | 5 | 97 |
| 5 | 3 | 2 | 88 |
| 6 | 3 | 6 | 75 |
| 7 | 4 | 5 | 71 |
| 8 | 4 | 2 | 89 |
| 9 | 5 | 1 | 39 |
| 10 | 5 | 7 | 63 |
| 11 | 6 | 1 | 96 |
| 12 | 7 | 1 | 86 |
| 13 | 7 | 7 | 83 |
| 14 | 8 | 4 | 57 |
| 15 | 8 | 3 | 93 |
+----+-------+----------+-------+
15 rows in set (0.00 sec)
需求:如何查询学生的姓名-报的课程姓名-考试成绩?
学生成绩表-学生姓名
MariaDB [hellodb]> select st.name 学生姓名,sc.CourseID,sc.Score 考试成绩 from students st inner join scores sc on st.StuID=sc.StuID;
+--------------+----------+--------------+
| 学生姓名 | CourseID | 考试成绩 |
+--------------+----------+--------------+
| Shi Zhongyu | 2 | 77 |
| Shi Zhongyu | 6 | 93 |
| Shi Potian | 2 | 47 |
| Shi Potian | 5 | 97 |
| Xie Yanke | 2 | 88 |
| Xie Yanke | 6 | 75 |
| Ding Dian | 5 | 71 |
| Ding Dian | 2 | 89 |
| Yu Yutong | 1 | 39 |
| Yu Yutong | 7 | 63 |
| Shi Qing | 1 | 96 |
| Xi Ren | 1 | 86 |
| Xi Ren | 7 | 83 |
| Lin Daiyu | 4 | 57 |
| Lin Daiyu | 3 | 93 |
+--------------+----------+--------------+
15 rows in set (0.00 sec)
再与课程表进行内连接:
MariaDB [hellodb]> select st.name 学生姓名,co.Course 课程名称,sc.Score 考试成绩 from students st inner join scores sc on st.StuID=sc.StuID
-> inner join
-> courses co where sc.CourseID=co. CourseID;
select st.name 学生姓名,co.Course 课程名称,sc.Score 考试成绩 from students st inner join scores sc on st.StuID=sc.StuID inner join courses co where sc.CourseID=co. CourseID;
+--------------+----------------+--------------+
| 学生姓名 | 课程名称 | 考试成绩 |
+--------------+----------------+--------------+
| Shi Zhongyu | Kuihua Baodian | 77 |
| Shi Zhongyu | Weituo Zhang | 93 |
| Shi Potian | Kuihua Baodian | 47 |
| Shi Potian | Daiyu Zanghua | 97 |
| Xie Yanke | Kuihua Baodian | 88 |
| Xie Yanke | Weituo Zhang | 75 |
| Ding Dian | Daiyu Zanghua | 71 |
| Ding Dian | Kuihua Baodian | 89 |
| Yu Yutong | Hamo Gong | 39 |
| Yu Yutong | Dagou Bangfa | 63 |
| Shi Qing | Hamo Gong | 96 |
| Xi Ren | Hamo Gong | 86 |
| Xi Ren | Dagou Bangfa | 83 |
| Lin Daiyu | Taiji Quan | 57 |
| Lin Daiyu | Jinshe Jianfa | 93 |
+--------------+----------------+--------------+
15 rows in set (0.00 sec)
测试结束。😍
SELECT语句处理的顺序
查询执行路径中的组件:查询缓存、解析器、预处理器、优化器、查询执行引擎、存储引擎
SELECT语句的执行流程:
FROM Clause --> WHERE Clause --> GROUP BY --> HAVING Clause -->SELECT --> ORDER BY --> LIMIT
练习
导入hellodb.sql生成数据库
- 在students表中,查询年龄大于25岁,且为男性的同学的名字和年龄
- 以ClassID为分组依据,显示每组的平均年龄
- 显示第2题中平均年龄大于30的分组及平均年龄
- 显示以L开头的名字的同学的信息
- 显示TeacherID非空的同学的相关信息
- 以年龄排序后,显示年龄最大的前10位同学的信息
- 查询年龄大于等于20岁,小于等于25岁的同学的信息
- 以ClassID分组,显示每班的同学的人数
- 以Gender分组,显示其年龄之和
- 以ClassID分组,显示其平均年龄大于25的班级
- 以Gender分组,显示各组中年龄大于25的学员的年龄之和
- 显示前5位同学的姓名、课程及成绩
- 显示其成绩高于80的同学的名称及课程
- 取每位同学各门课的平均成绩,显示成绩前三名的同学的姓名和平均成绩
- 显示每门课程课程名称及学习了这门课的同学的个数
- 显示其年龄大于平均年龄的同学的名字
- 显示其学习的课程为第1、2,4或第7门课的同学的名字
- 显示其成员数最少为3个的班级的同学中年龄大于同班同学平均年龄的同学
- 统计各班级中年龄大于全校同学平均年龄的同学
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]> select st.name 学生姓名,co.Course 课程名称,sc.Score 考试成绩 from students st inner join scores sc on st.StuID=sc.StuID inner join courses co where sc.CourseID=co. CourseID;
+--------------+----------------+--------------+
| 学生姓名 | 课程名称 | 考试成绩 |
+--------------+----------------+--------------+
| Shi Zhongyu | Kuihua Baodian | 77 |
| Shi Zhongyu | Weituo Zhang | 93 |
| Shi Potian | Kuihua Baodian | 47 |
| Shi Potian | Daiyu Zanghua | 97 |
| Xie Yanke | Kuihua Baodian | 88 |
| Xie Yanke | Weituo Zhang | 75 |
| Ding Dian | Daiyu Zanghua | 71 |
| Ding Dian | Kuihua Baodian | 89 |
| Yu Yutong | Hamo Gong | 39 |
| Yu Yutong | Dagou Bangfa | 63 |
| Shi Qing | Hamo Gong | 96 |
| Xi Ren | Hamo Gong | 86 |
| Xi Ren | Dagou Bangfa | 83 |
| Lin Daiyu | Taiji Quan | 57 |
| Lin Daiyu | Jinshe Jianfa | 93 |
+--------------+----------------+--------------+
15 rows in set (0.01 sec)
##创建视图:(其实,就是相当于给一大串select语句起了一个别名)
MariaDB [hellodb]> create view v_score as select st.name 学生姓名,co.Course 课程名称,sc.Score 考试成绩 from students st inner join scores sc on st.StuID=sc.StuID inner join courses co where sc.CourseID=co. CourseID;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> show tables;
+-------------------+
| Tables_in_hellodb |
+-------------------+
| classes |
| coc |
| courses |
| emp |
| scores |
| students |
| teachers |
| teachers2 |
| teachers3 |
| toc |
| v_score |##可以看到,这里出现了一个v_score表;
+-------------------+
11 rows in set (0.01 sec)
##问题:如果我更改了原来某张表信息,那么刚才创建的视图里的表信息会变化吗?(会的)
MariaDB [hellodb]> select *from scores;
+----+-------+----------+-------+
| ID | StuID | CourseID | Score |
+----+-------+----------+-------+
| 1 | 1 | 2 | 77 |
| 2 | 1 | 6 | 93 |
| 3 | 2 | 2 | 47 |
| 4 | 2 | 5 | 97 |
| 5 | 3 | 2 | 88 |
| 6 | 3 | 6 | 75 |
| 7 | 4 | 5 | 71 |
| 8 | 4 | 2 | 89 |
| 9 | 5 | 1 | 39 |
| 10 | 5 | 7 | 63 |
| 11 | 6 | 1 | 96 |
| 12 | 7 | 1 | 86 |
| 13 | 7 | 7 | 83 |
| 14 | 8 | 4 | 57 |
| 15 | 8 | 3 | 93 |
+----+-------+----------+-------+
15 rows in set (0.00 sec)
MariaDB [hellodb]> update scores set score=88 where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MariaDB [hellodb]> select *from scores;
+----+-------+----------+-------+
| ID | StuID | CourseID | Score |
+----+-------+----------+-------+
| 1 | 1 | 2 | 88 |
| 2 | 1 | 6 | 93 |
| 3 | 2 | 2 | 47 |
| 4 | 2 | 5 | 97 |
| 5 | 3 | 2 | 88 |
| 6 | 3 | 6 | 75 |
| 7 | 4 | 5 | 71 |
| 8 | 4 | 2 | 89 |
| 9 | 5 | 1 | 39 |
| 10 | 5 | 7 | 63 |
| 11 | 6 | 1 | 96 |
| 12 | 7 | 1 | 86 |
| 13 | 7 | 7 | 83 |
| 14 | 8 | 4 | 57 |
| 15 | 8 | 3 | 93 |
+----+-------+----------+-------+
15 rows in set (0.00 sec)
MariaDB [hellodb]> select *from v_score;
+--------------+----------------+--------------+
| 学生姓名 | 课程名称 | 考试成绩 |
+--------------+----------------+--------------+
| Shi Zhongyu | Kuihua Baodian | 88 |
| Shi Zhongyu | Weituo Zhang | 93 |
| Shi Potian | Kuihua Baodian | 47 |
| Shi Potian | Daiyu Zanghua | 97 |
| Xie Yanke | Kuihua Baodian | 88 |
| Xie Yanke | Weituo Zhang | 75 |
| Ding Dian | Daiyu Zanghua | 71 |
| Ding Dian | Kuihua Baodian | 89 |
| Yu Yutong | Hamo Gong | 39 |
| Yu Yutong | Dagou Bangfa | 63 |
| Shi Qing | Hamo Gong | 96 |
| Xi Ren | Hamo Gong | 86 |
| Xi Ren | Dagou Bangfa | 83 |
| Lin Daiyu | Taiji Quan | 57 |
| Lin Daiyu | Jinshe Jianfa | 93 |
+--------------+----------------+--------------+
15 rows in set (0.00 sec)
##问题:如果我更改了视图里某条信息,那么原来表里的信息会变化吗?(会的)
MariaDB [hellodb]> select *from v_score;
+--------------+----------------+--------------+
| 学生姓名 | 课程名称 | 考试成绩 |
+--------------+----------------+--------------+
| Shi Zhongyu | Kuihua Baodian | 88 |
| Shi Zhongyu | Weituo Zhang | 93 |
| Shi Potian | Kuihua Baodian | 47 |
| Shi Potian | Daiyu Zanghua | 97 |
| Xie Yanke | Kuihua Baodian | 88 |
| Xie Yanke | Weituo Zhang | 75 |
| Ding Dian | Daiyu Zanghua | 71 |
| Ding Dian | Kuihua Baodian | 89 |
| Yu Yutong | Hamo Gong | 39 |
| Yu Yutong | Dagou Bangfa | 63 |
| Shi Qing | Hamo Gong | 96 |
| Xi Ren | Hamo Gong | 86 |
| Xi Ren | Dagou Bangfa | 83 |
| Lin Daiyu | Taiji Quan | 57 |
| Lin Daiyu | Jinshe Jianfa | 93 |
+--------------+----------------+--------------+
15 rows in set (0.00 sec)
MariaDB [hellodb]> update v_score set 考试成绩=99 where 考试成绩=88;
Query OK, 2 rows affected (0.01 sec)
Rows matched: 2 Changed: 2 Warnings: 0
MariaDB [hellodb]> select *from v_score;
+--------------+----------------+--------------+
| 学生姓名 | 课程名称 | 考试成绩 |
+--------------+----------------+--------------+
| Shi Zhongyu | Kuihua Baodian | 99 |
| Shi Zhongyu | Weituo Zhang | 93 |
| Shi Potian | Kuihua Baodian | 47 |
| Shi Potian | Daiyu Zanghua | 97 |
| Xie Yanke | Kuihua Baodian | 99 |
| Xie Yanke | Weituo Zhang | 75 |
| Ding Dian | Daiyu Zanghua | 71 |
| Ding Dian | Kuihua Baodian | 89 |
| Yu Yutong | Hamo Gong | 39 |
| Yu Yutong | Dagou Bangfa | 63 |
| Shi Qing | Hamo Gong | 96 |
| Xi Ren | Hamo Gong | 86 |
| Xi Ren | Dagou Bangfa | 83 |
| Lin Daiyu | Taiji Quan | 57 |
| Lin Daiyu | Jinshe Jianfa | 93 |
+--------------+----------------+--------------+
15 rows in set (0.00 sec)
MariaDB [hellodb]> select *from scores;
+----+-------+----------+-------+
| ID | StuID | CourseID | Score |
+----+-------+----------+-------+
| 1 | 1 | 2 | 99 |
| 2 | 1 | 6 | 93 |
| 3 | 2 | 2 | 47 |
| 4 | 2 | 5 | 97 |
| 5 | 3 | 2 | 99 |
| 6 | 3 | 6 | 75 |
| 7 | 4 | 5 | 71 |
| 8 | 4 | 2 | 89 |
| 9 | 5 | 1 | 39 |
| 10 | 5 | 7 | 63 |
| 11 | 6 | 1 | 96 |
| 12 | 7 | 1 | 86 |
| 13 | 7 | 7 | 83 |
| 14 | 8 | 4 | 57 |
| 15 | 8 | 3 | 93 |
+----+-------+----------+-------+
15 rows in set (0.00 sec)
##注意:创建视图时,原来表的查询结果字段一定要不同,否则会导致创建视图失败的。
MariaDB [hellodb]> select s.name,t.name from students s inner join teachers t on s.teacherid=t.tid;
+-------------+---------------+
| name | name |
+-------------+---------------+
| Yu Yutong | Song Jiang |
| Shi Zhongyu | Miejue Shitai |
| Ding Dian | Lin Chaoying |
+-------------+---------------+
3 rows in set (0.00 sec)
MariaDB [hellodb]> create view v_testview as select s.name,t.name from students s inner join teachers t on s.teacherid=t.tid;
ERROR 1060 (42S21): Duplicate column name 'name' ##报错了
MariaDB [hellodb]>
##因此,这里通过创建别名来实现
MariaDB [hellodb]> select s.name stu_name,t.name tea_name from students s inner join teachers t on s.teacherid=t.tid;
+-------------+---------------+
| stu_name | tea_name |
+-------------+---------------+
| Yu Yutong | Song Jiang |
| Shi Zhongyu | Miejue Shitai |
| Ding Dian | Lin Chaoying |
+-------------+---------------+
3 rows in set (0.00 sec)
MariaDB [hellodb]> create view v_stu_tea_view as select s.name stu_name,t.name tea_name from students s inner join teachers t on s.teacherid=t.tid;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> select *from v_stu_tea_view;
+-------------+---------------+
| stu_name | tea_name |
+-------------+---------------+
| Yu Yutong | Song Jiang |
| Shi Zhongyu | Miejue Shitai |
| Ding Dian | Lin Chaoying |
+-------------+---------------+
3 rows in set (0.00 sec)
##视图本身不存放数据;
MariaDB [hellodb]> show tables;
+-------------------+
| Tables_in_hellodb |
+-------------------+
| classes |
| coc |
| courses |
| emp |
| scores |
| students |
| teachers |
| teachers2 |
| teachers3 |
| toc |
| v_score |
| v_stu_tea_view |
+-------------------+
12 rows in set (0.00 sec)
MariaDB [hellodb]> desc v_stu_tea_view;
+----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| stu_name | varchar(50) | NO | | NULL | |
| tea_name | varchar(100) | NO | | NULL | |
+----------+--------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
- 范例:如何查看某张表是否是view呢?
MariaDB [hellodb]> show table status like 'v_stu_tea_view'\G
*************************** 1. row ***************************
Name: v_stu_tea_view
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 ##look here 😜
1 row in set (0.00 sec)
MariaDB [hellodb]> show table status like 'students'\G
*************************** 1. row ***************************
Name: students
Engine: InnoDB
Version: 10
Row_format: Compact
Rows: 25
Avg_row_length: 655
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 9437184
Auto_increment: 26
Create_time: 2024-05-03 07:16:29
Update_time: NULL
Check_time: NULL
Collation: utf8_general_ci
Checksum: NULL
Create_options:
Comment:
1 row in set (0.00 sec)
- 范例:查看数据库下所有表/视图的状态
MariaDB [hellodb]> show table status from hellodb\G
……
*************************** 10. row ***************************
Name: toc
Engine: InnoDB
Version: 10
Row_format: Compact
Rows: 0
Avg_row_length: 0
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 9437184
Auto_increment: 1
Create_time: 2024-05-03 07:16:29
Update_time: NULL
Check_time: NULL
Collation: utf8_general_ci
Checksum: NULL
Create_options:
Comment:
*************************** 11. row ***************************
Name: v_score
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
*************************** 12. row ***************************
Name: v_stu_tea_view
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
12 rows in set (0.00 sec)
FUNCTION 函数
CAUTION
测试环境里可以使用函数,但生产力不推荐使用函数来实现这么长的sql功能。
所以,在淘宝、阿里巴巴手册里,规定禁止使用函数、存储过程、视图等功能。
函数:分为系统内置函数和自定义函数
- 系统内置函数参考:https://dev.mysql.com/doc/refman/5.7/en/func-op-summary-ref.html
- 自定义函数:user-defined function UDF,保存在mysql.proc表中
注意:是mysql数据库里的proc表。
创建UDF语法:
CREATE [AGGREGATE] FUNCTION function_name(parameter_name type,[parameter_name
type,...])
RETURNS {STRING|INTEGER|REAL}
runtime_body
说明:
- 参数可以有多个,也可以没有参数;
- 无论有无参数,小括号()是必须的;
- 必须有且只有一个返回值;
查看函数列表:
SHOW FUNCTION STATUS;
查看函数定义:
SHOW CREATE FUNCTION function_name
删除删除UDF:
DROP FUNCTION function_name
调用自定义函数语法:
SELECT function_name(parameter_value,...)
- 范例:统计一张表有多少条记录,
count()函数
(内置函数)
MariaDB [hellodb]> select *from students;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL |
| 24 | Xu Xian | 27 | M | NULL | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
+-------+---------------+-----+--------+---------+-----------+
25 rows in set (0.00 sec)
##或者加上主键,因为主键不允许为空。
MariaDB [hellodb]> select count(stuid) from students;
+--------------+
| count(stuid) |
+--------------+
| 25 |
+--------------+
1 row in set (0.00 sec)
##查询某张表有多少条记录
MariaDB [hellodb]> select count(*) from students;
+----------+
| count(*) |
+----------+
| 25 |
+----------+
1 row in set (0.00 sec)
##也可以查询表里面的某个字段
MariaDB [hellodb]> select count(stuid) from students;
+--------------+
| count(stuid) |
+--------------+
| 25 |
+--------------+
1 row in set (0.00 sec)
MariaDB [hellodb]> select count(classid) from students; ##注意:count函数这个是返回非空数据,空是不计数的。
+----------------+
| count(classid) |
+----------------+
| 23 |
+----------------+
1 row in set (0.00 sec)
MariaDB [hellodb]> select count(teacherid) from students;
+------------------+
| count(teacherid) |
+------------------+
| 5 |
+------------------+
1 row in set (0.00 sec)
- 范例:无参UDF
MariaDB [hellodb]> SHOW FUNCTION STATUS;
Empty set (0.00 sec)
MariaDB [hellodb]> CREATE FUNCTION simpleFun() RETURNS VARCHAR(20) RETURN "Hello World";
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> SHOW FUNCTION STATUS\G
*************************** 1. row ***************************
Db: hellodb
Name: simpleFun
Type: FUNCTION
Definer: root@localhost
Modified: 2024-05-07 07:33:53
Created: 2024-05-07 07:33:53
Security_type: DEFINER
Comment:
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: utf8_general_ci
1 row in set (0.00 sec)
MariaDB [hellodb]> select simpleFun();
+-------------+
| simpleFun() |
+-------------+
| Hello World |
+-------------+
1 row in set (0.00 sec)
##函数是存放在mysql数据库的proc表里的
[root@test mysql]# pwd
/var/lib/mysql/mysql
[root@test mysql]# ll -t
total 1000
-rw-rw---- 1 mysql mysql 292 May 7 07:27 proc.MYD
-rw-rw---- 1 mysql mysql 4096 May 7 07:27 proc.MYI
MariaDB [mysql]> select *from mysql.proc\G
*************************** 1. row ***************************
db: mysql
name: simpleFun
type: FUNCTION
specific_name: simpleFun
language: SQL
sql_data_access: CONTAINS_SQL
is_deterministic: NO
security_type: DEFINER
param_list:
returns: varchar(20) CHARSET latin1
body: RETURN "Hello World"
definer: root@localhost
created: 2024-05-07 07:27:59
modified: 2024-05-07 07:27:59
sql_mode:
comment:
character_set_client: utf8
collation_connection: utf8_general_ci
db_collation: latin1_swedish_ci
body_utf8: RETURN "Hello World"
1 row in set (0.00 sec)
##注意:函数是有归属区分的
MariaDB [hellodb]> 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
MariaDB [mysql]> select simpleFun();
ERROR 1305 (42000): FUNCTION mysql.simpleFun does not exist
MariaDB [mysql]> select hellodb.simpleFun();
+---------------------+
| hellodb.simpleFun() |
+---------------------+
| Hello World |
+---------------------+
1 row in set (0.00 sec)
##删除函数
MariaDB [hellodb]> d
Query OK, 0 rows aff
MariaDB [hellodb]> s
Empty set (0.00 sec)
- 范例:有参UDF
#有参数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 ;
##说明:DELIMITER // 是用来修改数据库分隔符的;
DELIMITER //
CREATE FUNCTION deleteById(id SMALLINT UNSIGNED) RETURNS VARCHAR(20)
BEGIN
DELETE FROM students WHERE stuid = id;
RETURN (SELECT COUNT(*) FROM students);
END//
DELIMITER ;
MariaDB [hellodb]> show function status\G
*************************** 1. row ***************************
Db: hellodb
Name: deleteById
Type: FUNCTION
Definer: root@localhost
Modified: 2024-05-07 07:50:35
Created: 2024-05-07 07:50:35
Security_type: DEFINER
Comment:
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: utf8_general_ci
1 row in set (0.00 sec)
##删除第25个同学
MariaDB [hellodb]> select deleteById(25);
+----------------+
| deleteById(25) |
+----------------+
| 24 |
+----------------+
1 row in set (0.00 sec)
MariaDB [hellodb]> select *from students;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL |
| 24 | Xu Xian | 27 | M | NULL | NULL |
+-------+---------------+-----+--------+---------+-----------+
24 rows in set (0.00 sec)
##删除第10号同学
MariaDB [hellodb]> select deleteById(10);
+----------------+
| deleteById(10) |
+----------------+
| 23 |
+----------------+
1 row in set (0.01 sec)
MariaDB [hellodb]> select *from students;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL |
| 24 | Xu Xian | 27 | M | NULL | NULL |
+-------+---------------+-----+--------+---------+-----------+
23 rows in set (0.00 sec)
MySQL中的变量
两种变量:系统内置变量和用户自定义变量
系统变量:MySQL数据库中内置的变量,可用@@var_name引用
用户自定义变量分为以下两种
- 普通变量:在当前会话中有效,可用@var_name引用
- 局部变量:在函数或存储过程内才有效,需要用DECLARE 声明,之后直接用 var_name引用
范例:查看所有系统变量
MariaDB [hellodb]> show variables\G
……
*************************** 431. row ***************************
Variable_name: version_compile_os
Value: Linux
*************************** 432. row ***************************
Variable_name: wait_timeout
Value: 28800
*************************** 433. row ***************************
Variable_name: warning_count
Value: 0
433 rows in set (0.01 sec)
- 范例:查询系统变量值
MariaDB [hellodb]> select @@port;
+--------+
| @@port |
+--------+
| 3306 |
+--------+
1 row in set (0.00 sec)
MariaDB [hellodb]> select @@hostname;
+-------------------------+
| @@hostname |
+-------------------------+
| iZbp1in7y9nitzcajdv0ufZ |
+-------------------------+
1 row in set (0.00 sec)
- 范例:concat函数(用于连接2个字符串)
MariaDB [hellodb]> select concat('wang',100);
+--------------------+
| concat('wang',100) |
+--------------------+
| wang100 |
+--------------------+
1 row in set (0.00 sec)
MariaDB [hellodb]> select concat('wang',100,'xyy');
+--------------------------+
| concat('wang',100,'xyy') |
+--------------------------+
| wang100xyy |
+--------------------------+
1 row in set (0.00 sec)
自定义函数中定义局部变量语法
DECLARE 变量1[,变量2,... ]变量类型 [DEFAULT 默认值]
NOTE
说明:局部变量的作用范围是在BEGIN...END程序中,而且定义局部变量语句必须在BEGIN...END的第一行定义。
- 范例:自定义函数中定义局部变量语法
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 ;
#测试过程
MariaDB [hellodb]> DELIMITER //
MariaDB [hellodb]> 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//
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> DELIMITER ;
MariaDB [hellodb]>
MariaDB [hellodb]> select addTwoNumber(10,20);
+---------------------+
| addTwoNumber(10,20) |
+---------------------+
| 30 |
+---------------------+
1 row in set (0.00 sec)
MariaDB [hellodb]> select @@a;
ERROR 1193 (HY000): Unknown system variable 'a'
MariaDB [hellodb]> select @a;
+------+
| @a |
+------+
| NULL |
+------+
1 row in set (0.00 sec)
MariaDB [hellodb]>
为变量赋值语法
SET parameter_name = value[,parameter_name = value...]
SELECT INTO parameter_name
范例:
.....
DECLARE x int;
SELECT COUNT(*) FROM tdb_name INTO x;
RETURN x;
END//
- 范例:自定义的普通变量
MariaDB [hellodb]> select @a;
+------+
| @a |
+------+
| NULL |
+------+
1 row in set (0.00 sec)
MariaDB [hellodb]> set @var1='hello';
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> select @var1;
+-------+
| @var1 |
+-------+
| hello |
+-------+
1 row in set (0.00 sec)
##另开一个终端:
MariaDB [hellodb]> select @var1;
+-------+
| @var1 |
+-------+
| NULL |
+-------+
1 row in set (0.00 sec)
MariaDB [hellodb]> select max(age) from students into @age;
Query OK, 1 row affected (0.00 sec)
MariaDB [hellodb]> select @age;
+------+
| @age |
+------+
| 53 |
+------+
1 row in set (0.00 sec)
MariaDB [hellodb]> set @age=100;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> select @age;
+------+
| @age |
+------+
| 100 |
+------+
1 row in set (0.00 sec)
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
- 范例:PROCEDURE 存储过程(创建无参存储过程)
# 创建无参存储过程
delimiter //
CREATE PROCEDURE showTime()
BEGIN
SELECT now();
END//
delimiter ;
CALL showTime;
##测试过程
MariaDB [hellodb]> delimiter //
MariaDB [hellodb]> CREATE PROCEDURE showTime()
-> BEGIN
-> SELECT now();
-> END//
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> delimiter ;
MariaDB [hellodb]> call showtime;
+---------------------+
| now() |
+---------------------+
| 2024-05-10 05:35:20 |
+---------------------+
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
- 范例:PROCEDURE 存储过程(创建含参存储过程:只有一个IN参数)
#创建含参存储过程:只有一个IN参数
delimiter //
CREATE PROCEDURE selectById(IN id SMALLINT UNSIGNED)
BEGIN
SELECT * FROM students WHERE stuid = id;
END//
delimiter ;
call selectById(2);
##测试过程
MariaDB [hellodb]> delimiter //
MariaDB [hellodb]> CREATE PROCEDURE selectById(IN id SMALLINT UNSIGNED)
-> BEGIN
-> SELECT * FROM students WHERE stuid = id;
-> END//
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> delimiter ;
MariaDB [hellodb]>
MariaDB [hellodb]> call selectById(3);
+-------+-----------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-----------+-----+--------+---------+-----------+
| 3 | Xie Yanke | 53 | M | 2 | 16 |
+-------+-----------+-----+--------+---------+-----------+
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
- 范例:
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;
##测试过程
MariaDB [hellodb]> delimiter //
MariaDB [hellodb]> 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//
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> delimiter ;
MariaDB [hellodb]> CALL dorepeat(100);
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]>
MariaDB [hellodb]> select @sum;
+------+
| @sum |
+------+
| 5050 |
+------+
1 row in set (0.00 sec)
MariaDB [hellodb]> set @sum=200;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> select @sum;
+------+
| @sum |
+------+
| 200 |
+------+
1 row in set (0.00 sec)
- 范例
#创建含参存储过程:包含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(2,@Line);
SELECT @Line;
#说明:创建存储过程deleteById,包含一个IN参数和一个OUT参数.调用时,传入删除的ID和保存被修改的行
数值的用户变量@Line,select @Line;输出被影响行数
#row_count() 系统内置函数,用于存放前一条SQL修改过的表的记录数
测试过程:
MariaDB [hellodb]> delimiter //
MariaDB [hellodb]> CREATE PROCEDURE deleteById(IN id SMALLINT UNSIGNED, OUT num SMALLINT UNSIGNED)
-> BEGIN
-> DELETE FROM students WHERE stuid >= id;
-> SELECT row_count() into num;
-> END//
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> delimiter ;
MariaDB [hellodb]> call deleteById(2,@Line);
Query OK, 1 row affected (0.00 sec)
MariaDB [hellodb]> SELECT @Line;
+-------+
| @Line |
+-------+
| 22 |
+-------+
1 row in set (0.00 sec)
MariaDB [hellodb]>
流程控制
存储过程和函数中可以使用流程控制来控制语句的执行
- IF:用来进行条件判断。根据是否满足条件,执行不同语句
- CASE:用来进行条件判断,可实现比IF语句更复杂的条件判断
- LOOP:重复执行特定的语句,实现一个简单的循环
- LEAVE:用于跳出循环控制,相当于SHELL中break
- ITERATE:跳出本次循环,然后直接进入下一次循环,相当于SHELL中continue
- REPEAT:有条件控制的循环语句。当满足特定条件时,就会跳出循环语句
- WHILE:有条件控制的循环语句
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:该触发器作用在表名
查看触发器
#在当前数据库对应的目录下,可以查看到新生成的相关文件: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;
- 范例
#创建触发器,在向学生表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;
测试过程:
MariaDB [hellodb]> CREATE TABLE student_info (
-> stu_id INT(11) NOT NULL AUTO_INCREMENT ,
-> stu_name VARCHAR(255) DEFAULT NULL,
-> PRIMARY KEY (stu_id)
-> );
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> CREATE TABLE student_count (
-> student_count INT(11) DEFAULT 0
-> );
Query OK, 0 rows affected (0.01 sec)
MariaDB [hellodb]> select *from student_info;
Empty set (0.00 sec)
MariaDB [hellodb]> select *from student_count;
Empty set (0.00 sec)
MariaDB [hellodb]> INSERT INTO student_count VALUES(0);
Query OK, 1 row affected (0.00 sec)
##创建trigger
MariaDB [hellodb]>
MariaDB [hellodb]> CREATE TRIGGER trigger_student_count_insert
-> AFTER INSERT
-> ON student_info FOR EACH ROW
-> UPDATE student_count SET student_count=student_count+1;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]>
MariaDB [hellodb]> CREATE TRIGGER trigger_student_count_delete
-> AFTER DELETE
-> ON student_info FOR EACH ROW
-> UPDATE student_count SET student_count=student_count-1;
Query OK, 0 rows affected (0.00 sec)
##更新表
MariaDB [hellodb]> insert student_info (stu_name)values('hg');
Query OK, 1 row affected (0.00 sec)
MariaDB [hellodb]> select *from student_info;
+--------+----------+
| stu_id | stu_name |
+--------+----------+
| 1 | hg |
+--------+----------+
1 row in set (0.00 sec)
MariaDB [hellodb]> select *from student_count;
+---------------+
| student_count |
+---------------+
| 1 |
+---------------+
1 row in set (0.00 sec)
MariaDB [hellodb]> insert student_info (stu_name)values('hg');
Query OK, 1 row affected (0.00 sec)
MariaDB [hellodb]> select *from student_info;
+--------+----------+
| stu_id | stu_name |
+--------+----------+
| 1 | hg |
+--------+----------+
1 row in set (0.00 sec)
MariaDB [hellodb]> select *from student_count;
+---------------+
| student_count |
+---------------+
| 1 |
+---------------+
1 row in set (0.00 sec)
MariaDB [hellodb]> delete from student_info where stu_id>=3;
Query OK, 3 rows affected (0.00 sec)
MariaDB [hellodb]> select *from student_info;
+--------+----------+
| stu_id | stu_name |
+--------+----------+
| 1 | hg |
| 2 | xyy |
+--------+----------+
2 rows in set (0.00 sec)
MariaDB [hellodb]> select *from student_count;
+---------------+
| student_count |
+---------------+
| 2 |
+---------------+
1 row in set (0.00 sec)
##底层存储位置:
[root@test hellodb]# ll
total 168
-rw-rw---- 1 mysql mysql 8636 May 3 07:16 classes.frm
-rw-rw---- 1 mysql mysql 8630 May 3 07:16 coc.frm
-rw-rw---- 1 mysql mysql 8602 May 3 07:16 courses.frm
-rw-rw---- 1 mysql mysql 61 May 3 07:16 db.opt
-rw-rw---- 1 mysql mysql 8626 May 6 06:55 emp.frm
-rw-rw---- 1 mysql mysql 8658 May 3 07:16 scores.frm
-rw-rw---- 1 mysql mysql 8578 May 10 07:47 student_count.frm
-rw-rw---- 1 mysql mysql 8602 May 10 07:47 student_info.frm
-rw-rw---- 1 mysql mysql 560 May 10 07:47 student_info.TRG ##warning
-rw-rw---- 1 mysql mysql 8736 May 3 07:16 students.frm
-rw-rw---- 1 mysql mysql 8656 May 3 07:24 teachers2.frm
-rw-rw---- 1 mysql mysql 8650 May 3 07:32 teachers3.frm
-rw-rw---- 1 mysql mysql 8656 May 3 07:16 teachers.frm
-rw-rw---- 1 mysql mysql 8622 May 3 07:16 toc.frm
-rw-rw---- 1 mysql mysql 44 May 10 07:47 trigger_student_count_delete.TRN ##warning
-rw-rw---- 1 mysql mysql 44 May 10 07:47 trigger_student_count_insert.TRN ##warning
-rw-rw---- 1 mysql mysql 1016 May 7 06:09 v_score.frm
-rw-rw---- 1 mysql mysql 695 May 7 06:31 v_stu_tea_view.frm
[root@test hellodb]# cat 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=0 0
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'
[root@test hellodb]# cat trigger_student_count_delete.TRN
TYPE=TRIGGERNAME
trigger_table=student_info
[root@test hellodb]# cat trigger_student_count_insert.TRN
TYPE=TRIGGERNAME
trigger_table=student_info
Event 事件
NOTE
类似于shell里的crontab。
Event 事件介绍
事件(event)是MySQL在相应的时刻调用的过程式数据库对象。一个事件可调用一次,也可周期性的启动,它由一个特定的线程来管理的,也就是所谓的“事件调度器”。
事件和触发器类似,都是在某些事情发生的时候启动。当数据库上启动一条语句的时候,触发器就启动了,而事件是根据调度事件来启动的。由于它们彼此相似,所以事件也称为临时性触发器。
事件取代了原先只能由操作系统的计划任务来执行的工作,而且MySQL的事件调度器可以精确到每秒钟执行一个任务,而操作系统的计划任务(如:Linux下的CRON或Windows下的任务计划)只能精确到每分钟执行一次。
事件的优缺点
优点:一些对数据定时性操作不再依赖外部程序,而直接使用数据库本身提供的功能,可以实现每秒钟执行一个任务,这在一些对实时性要求较高的环境下就非常实用
缺点:定时触发,不可以直接调用
Event 管理
相关变量和服务器选项
MySQL事件调度器event_scheduler负责调用事件,它默认是关闭的。这个调度器不断地监视一个事件是否要调用, 要创建事件,必须打开调度器
服务器系统变量和服务器选项:
event_scheduler:默认值为OFF,设置为ON才支持Event,并且系统自动打开专用的线程。
🍊 范例:开启和关闭event_scheduler
#默认事件调度功能是关闭的
MariaDB [hellodb]> select @@event_scheduler;
+-------------------+
| @@event_scheduler |
+-------------------+
| OFF |
+-------------------+
1 row in set (0.00 sec)
#临时开启事件调度功能
MariaDB [hellodb]> set global event_scheduler=1;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> show processlist;
+-----+-----------------+-----------+---------+---------+------+------------------------+------------------+----------+
| Id | User | Host | db | Command | Time | State | Info | Progress |
+-----+-----------------+-----------+---------+---------+------+------------------------+------------------+----------+
| 402 | root | localhost | hellodb | Query | 0 | NULL | show processlist | 0.000 |
| 403 | event_scheduler | localhost | NULL | Daemon | 13 | Waiting on empty queue | NULL | 0.000 |
+-----+-----------------+-----------+---------+---------+------+------------------------+------------------+----------+
2 rows in set (0.00 sec)
#临时关闭事件调度功能
MariaDB [hellodb]> set global event_scheduler=0;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> show processlist;
+-----+------+-----------+---------+---------+------+-------+------------------+----------+
| Id | User | Host | db | Command | Time | State | Info | Progress |
+-----+------+-----------+---------+---------+------+-------+------------------+----------+
| 402 | root | localhost | hellodb | Query | 0 | NULL | show processlist | 0.000 |
+-----+------+-----------+---------+---------+------+-------+------------------+----------+
1 row in set (0.00 sec)
#持久开启事件调度
#持久开启事件调度
[root@centos8 ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
event_scheduler=ON
[root@centos8 ~]#systemctl restart mariadb
管理事件
create event 语句创建一个事件。每个事件由两个主要部分组成,第一部分是事件调度(event schedule),表示事件何时启动以及按什么频率启动,第二部分是事件动作(event action ),这是事件启动时执行的代码,事件的动作包含一条SQL语句,它可能是一个简单地insert或者update语句,也可以使一个存储过程或者 benin...end语句块,这两种情况允许我们执行多条SQL
一个事件可以是活动(打开)的或停止(关闭)的,活动意味着事件调度器检查事件动作是否必须调用,停止意味着事件的声明存储在目录中,但调度器不会检查它是否应该调用。在一个事件创建之后,它立即变为活动的,一个活动的事件可以执行一次或者多次。
范例
🍊 范例:创建立即启动事件
#创建数据库
MariaDB [hellodb]> create database testdb;
Query OK, 1 row affected (0.01 sec)
MariaDB [hellodb]> 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.00 sec)
MariaDB [testdb]> select *from events_list;
Empty set (0.00 sec)
#临时关闭事件调度功能
MariaDB [testdb]> set global event_scheduler=0;
Query OK, 0 rows affected (0.00 sec)
MariaDB [testdb]> show variables like 'event_scheduler';
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| event_scheduler | OFF |
+-----------------+-------+
1 row in set (0.00 sec)
#创建一次性事件
MariaDB [testdb]> create event event_now on schedule at now() do insert into events_list values('event_now', now());
Query OK, 0 rows affected (0.00 sec)
#因为事件调度功能禁用,所有表中无记录
MariaDB [testdb]> select *from events_list;
Empty set (0.00 sec)
#查看事件
MariaDB [testdb]> show events\G
*************************** 1. row ***************************
Db: testdb
Name: event_now
Definer: root@localhost
Time zone: SYSTEM
Type: ONE TIME
Execute at: 2024-05-12 07:38:12
Interval value: NULL
Interval field: NULL
Starts: NULL
Ends: NULL
Status: ENABLED
Originator: 0
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: latin1_swedish_ci
1 row in set (0.00 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: 2024-05-11 23:38:12
interval_value: NULL
interval_field: NULL
created: 2024-05-12 07:38:12
modified: 2024-05-12 07:38:12
last_executed: NULL
starts: NULL
ends: NULL
status: ENABLED
on_completion: DROP
sql_mode:
comment:
originator: 0
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.00 sec)
#查看mysql数据库下对应event文件
[root@test mysql]# ll -t
total 1004
-rw-rw---- 1 mysql mysql 216 May 12 07:38 event.MYD
-rw-rw---- 1 mysql mysql 4096 May 12 07:38 event.MYI
……
#开启事件调度功能
MariaDB [testdb]> set global event_scheduler=1;
Query OK, 0 rows affected (0.00 sec)
#事件立即执行,每秒插入一条记录
MariaDB [testdb]> select *from events_list;
+------------+---------------------+
| event_name | event_started |
+------------+---------------------+
| event_now | 2024-05-12 07:41:42 |
+------------+---------------------+
1 row in set (0.00 sec)
#事件执行完成后自动删除
MariaDB [testdb]> show events;
Empty set (0.00 sec)
🍊 范例:创建每秒启动的事件
#创建事件
MariaDB [testdb]> CREATE EVENT event_every_second ON SCHEDULE EVERY 1 SECOND DO INSERT INTO events_list VALUES('event_now', now());
Query OK, 0 rows affected (0.00 sec)
#查看事件
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: 2024-05-12 07:47:44
Ends: NULL
Status: ENABLED
Originator: 0
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: latin1_swedish_ci
1 row in set (0.01 sec)
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: 2024-05-12 07:47:44
modified: 2024-05-12 07:47:44
last_executed: 2024-05-11 23:48:08
starts: 2024-05-11 23:47:44
ends: NULL
status: ENABLED
on_completion: DROP
sql_mode:
comment:
originator: 0
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.00 sec)
MariaDB [testdb]> select *from events_list;
+------------+---------------------+
| event_name | event_started |
+------------+---------------------+
| event_now | 2024-05-12 07:41:42 |
| event_now | 2024-05-12 07:47:44 |
| event_now | 2024-05-12 07:47:45 |
| event_now | 2024-05-12 07:47:46 |
| event_now | 2024-05-12 07:47:47 |
| event_now | 2024-05-12 07:47:48 |
| event_now | 2024-05-12 07:47:49 |
| event_now | 2024-05-12 07:47:50 |
| event_now | 2024-05-12 07:47:51 |
| event_now | 2024-05-12 07:47:52 |
| event_now | 2024-05-12 07:47:53 |
| event_now | 2024-05-12 07:47:54 |
| event_now | 2024-05-12 07:47:55 |
| event_now | 2024-05-12 07:47:56 |
| event_now | 2024-05-12 07:47:57 |
| event_now | 2024-05-12 07:47:58 |
| event_now | 2024-05-12 07:47:59 |
| event_now | 2024-05-12 07:48:00 |
| event_now | 2024-05-12 07:48:01 |
| event_now | 2024-05-12 07:48:02 |
| event_now | 2024-05-12 07:48:03 |
| event_now | 2024-05-12 07:48:04 |
| event_now | 2024-05-12 07:48:05 |
| event_now | 2024-05-12 07:48:06 |
| event_now | 2024-05-12 07:48:07 |
| event_now | 2024-05-12 07:48:08 |
| event_now | 2024-05-12 07:48:09 |
| event_now | 2024-05-12 07:48:10 |
| event_now | 2024-05-12 07:48:11 |
| event_now | 2024-05-12 07:48:12 |
| event_now | 2024-05-12 07:48:13 |
| event_now | 2024-05-12 07:48:14 |
+------------+---------------------+
32 rows in set (0.00 sec)
#删除事件
MariaDB [testdb]> drop event event_every_second;
Query OK, 0 rows affected (0.00 sec)
#删除后确认事件是否为空
MariaDB [testdb]> SHOW EVENTS\G
Empty set (0.00 sec)
MariaDB [testdb]> select *from mysql.event\G
Empty set (0.00 sec)
🍊 范例:创建每分钟启动的事件
MariaDB [testdb]> show variables like 'event_scheduler';
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| event_scheduler | ON |
+-----------------+-------+
1 row in set (0.001 sec)
MariaDB [testdb]> create event testdb.event_every_minute on schedule every
1 minute do insert into events_list values('event_now', now());
Query OK, 0 rows affected (0.001 sec)
MariaDB [testdb]> select now();
+---------------------+
| now() |
+---------------------+
| 2019-12-02 22:39:12 |
+---------------------+
1 row in set (0.000 sec)
MariaDB [testdb]> select *from events_list;
+------------+---------------------+
| event_name | event_started |
+------------+---------------------+
| event_now | 2019-12-02 22:39:10 |
+------------+---------------------+
MariaDB [testdb]> SHOW EVENTS\G
*************************** 1. row ***************************
Db: testdb
Name: event_every_minute
Definer: root@localhost
Time zone: SYSTEM
Type: RECURRING
Execute at: NULL
Interval value: 1
Interval field: MINUTE
Starts: 2019-12-02 22:35:57
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.001 sec)
MariaDB [testdb]> select *from events_list;
+------------+---------------------+
| event_name | event_started |
+------------+---------------------+
| event_now | 2019-12-02 22:39:10 |
| event_now | 2019-12-02 22:40:10 |
| event_now | 2019-12-02 22:41:10 |
| event_now | 2019-12-02 22:42:10 |
| event_now | 2019-12-02 22:43:10 |
| event_now | 2019-12-02 22:44:10 |
| event_now | 2019-12-02 22:45:10 |
+------------+---------------------+
7 rows in set (0.000 sec)
🍊 范例:创建定时调用存储过程的事件
MariaDB [testdb]> drop event event_every_minute;
Query OK, 0 rows affected (0.000 sec)
MariaDB [testdb]> truncate table events_list;
Query OK, 0 rows affected (0.010 sec)
MariaDB [testdb]> select *from events_list;
Empty set (0.000 sec)
MariaDB [testdb]> delimiter //
MariaDB [testdb]> create procedure sp_insert()
-> begin
-> insert into events_list values('event_now', now());
-> end//
Query OK, 0 rows affected (0.001 sec)
MariaDB [testdb]> delimiter ;
MariaDB [testdb]> CREATE DEFINER=`root`@`localhost` EVENT event_test ON SCHEDULE
EVERY 10 SECOND STARTS '2019-12-02 22:55:00' ON COMPLETION PRESERVE ENABLE DO
call sp_insert();
Query OK, 0 rows affected (0.001 sec)
MariaDB [testdb]> select now();
+---------------------+
| now() |
+---------------------+
| 2019-12-02 22:51:57 |
+---------------------+
1 row in set (0.000 sec)
MariaDB [testdb]> select *from events_list;
+------------+---------------------+
| event_name | event_started |
+------------+---------------------+
| event_now | 2019-12-02 22:55:00 |
| event_now | 2019-12-02 22:55:10 |
| event_now | 2019-12-02 22:55:20 |
| event_now | 2019-12-02 22:55:30 |
+------------+---------------------+
4 rows in set (0.000 sec)
MariaDB [testdb]>
🍊 范例:修改事件
MariaDB [testdb]> ALTER DEFINER=`root`@`localhost EVENT event_test ON SCHEDULE
EVERY 30 SECOND ON COMPLETION PRESERVE ENABLE DO call sp_insert();
MariaDB [testdb]> select *from events_list;
+------------+---------------------+
| event_name | event_started |
+------------+---------------------+
| event_now | 2019-12-02 22:55:00 |
| event_now | 2019-12-02 22:55:10 |
| event_now | 2019-12-02 22:55:20 |
| event_now | 2019-12-02 22:55:30 |
| event_now | 2019-12-02 22:55:40 |
| event_now | 2019-12-02 22:55:50 |
| event_now | 2019-12-02 22:56:00 |
| event_now | 2019-12-02 22:56:10 |
| event_now | 2019-12-02 22:56:20 |
| event_now | 2019-12-02 22:56:30 |
| event_now | 2019-12-02 22:56:40 |
| event_now | 2019-12-02 22:56:50 |
| event_now | 2019-12-02 22:57:00 |
| event_now | 2019-12-02 22:57:10 |
| event_now | 2019-12-02 22:57:20 |
| event_now | 2019-12-02 22:57:30 |
| event_now | 2019-12-02 22:57:40 |
| event_now | 2019-12-02 22:57:50 |
| event_now | 2019-12-02 22:58:00 |
| event_now | 2019-12-02 22:58:10 |
| event_now | 2019-12-02 22:58:20 |
| event_now | 2019-12-02 22:58:30 |
| event_now | 2019-12-02 22:58:40 |
| event_now | 2019-12-02 22:58:50 |
| event_now | 2019-12-02 22:59:00 |
| event_now | 2019-12-02 22:59:10 |
| event_now | 2019-12-02 22:59:18 |
| event_now | 2019-12-02 22:59:48 |
| event_now | 2019-12-02 23:00:18 |
| event_now | 2019-12-02 23:00:48 |
| event_now | 2019-12-02 23:01:18 |
| event_now | 2019-12-02 23:01:48 |
| event_now | 2019-12-02 23:02:18 |
| event_now | 2019-12-02 23:02:48 |
+------------+---------------------+
34 rows in set (0.001 sec)
#禁用事件
MariaDB [testdb]> alter event testdb.event_test disable;
MariaDB [testdb]> show events\G
*************************** 1. row ***************************
Db: testdb
Name: event_test
Definer: root@localhost
Time zone: SYSTEM
Type: RECURRING
Execute at: NULL
Interval value: 30
Interval field: SECOND
Starts: 2019-12-02 22:59:18
Ends: NULL
Status: DISABLED
Originator: 1
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: latin1_swedish_ci
1 row in set (0.001 sec)
MariaDB [testdb]> select now();
+---------------------+
| now() |
+---------------------+
| 2019-12-02 23:09:02 |
+---------------------+
1 row in set (0.001 sec)
MariaDB [testdb]> select *from events_list;
+------------+---------------------+
| event_name | event_started |
+------------+---------------------+
| event_now | 2019-12-02 22:55:00 |
| event_now | 2019-12-02 22:55:10 |
| event_now | 2019-12-02 22:55:20 |
| event_now | 2019-12-02 22:55:30 |
| event_now | 2019-12-02 22:55:40 |
| event_now | 2019-12-02 22:55:50 |
| event_now | 2019-12-02 22:56:00 |
| event_now | 2019-12-02 22:56:10 |
| event_now | 2019-12-02 22:56:20 |
| event_now | 2019-12-02 22:56:30 |
| event_now | 2019-12-02 22:56:40 |
| event_now | 2019-12-02 22:56:50 |
| event_now | 2019-12-02 22:57:00 |
| event_now | 2019-12-02 22:57:10 |
| event_now | 2019-12-02 22:57:20 |
| event_now | 2019-12-02 22:57:30 |
| event_now | 2019-12-02 22:57:40 |
| event_now | 2019-12-02 22:57:50 |
| event_now | 2019-12-02 22:58:00 |
| event_now | 2019-12-02 22:58:10 |
| event_now | 2019-12-02 22:58:20 |
| event_now | 2019-12-02 22:58:30 |
| event_now | 2019-12-02 22:58:40 |
| event_now | 2019-12-02 22:58:50 |
| event_now | 2019-12-02 22:59:00 |
| event_now | 2019-12-02 22:59:10 |
| event_now | 2019-12-02 22:59:18 |
| event_now | 2019-12-02 22:59:48 |
| event_now | 2019-12-02 23:00:18 |
| event_now | 2019-12-02 23:00:48 |
| event_now | 2019-12-02 23:01:18 |
| event_now | 2019-12-02 23:01:48 |
| event_now | 2019-12-02 23:02:18 |
| event_now | 2019-12-02 23:02:48 |
+------------+---------------------+
34 rows in set (0.001 sec)
#启用事件
MariaDB [testdb]> alter event testdb.event_test enable;
Query OK, 0 rows affected (0.000 sec)
MariaDB [testdb]> show events\G
*************************** 1. row ***************************
Db: testdb
Name: event_test
Definer: root@localhost
Time zone: SYSTEM
Type: RECURRING
Execute at: NULL
Interval value: 30
Interval field: SECOND
Starts: 2019-12-02 22:59:18
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.001 sec)
MariaDB [testdb]> select *from events_list;
+------------+---------------------+
| event_name | event_started |
+------------+---------------------+
| event_now | 2019-12-02 22:55:00 |
| event_now | 2019-12-02 22:55:10 |
| event_now | 2019-12-02 22:55:20 |
| event_now | 2019-12-02 22:55:30 |
| event_now | 2019-12-02 22:55:40 |
| event_now | 2019-12-02 22:55:50 |
| event_now | 2019-12-02 22:56:00 |
| event_now | 2019-12-02 22:56:10 |
| event_now | 2019-12-02 22:56:20 |
| event_now | 2019-12-02 22:56:30 |
| event_now | 2019-12-02 22:56:40 |
| event_now | 2019-12-02 22:56:50 |
| event_now | 2019-12-02 22:57:00 |
| event_now | 2019-12-02 22:57:10 |
| event_now | 2019-12-02 22:57:20 |
| event_now | 2019-12-02 22:57:30 |
| event_now | 2019-12-02 22:57:40 |
| event_now | 2019-12-02 22:57:50 |
| event_now | 2019-12-02 22:58:00 |
| event_now | 2019-12-02 22:58:10 |
| event_now | 2019-12-02 22:58:20 |
| event_now | 2019-12-02 22:58:30 |
| event_now | 2019-12-02 22:58:40 |
| event_now | 2019-12-02 22:58:50 |
| event_now | 2019-12-02 22:59:00 |
| event_now | 2019-12-02 22:59:10 |
| event_now | 2019-12-02 22:59:18 |
| event_now | 2019-12-02 22:59:48 |
| event_now | 2019-12-02 23:00:18 |
| event_now | 2019-12-02 23:00:48 |
| event_now | 2019-12-02 23:01:18 |
| event_now | 2019-12-02 23:01:48 |
| event_now | 2019-12-02 23:02:18 |
| event_now | 2019-12-02 23:02:48 |
| event_now | 2019-12-02 23:11:48 |
| event_now | 2019-12-02 23:12:18 |
+------------+---------------------+
36 rows in set (0.000 sec)
#修改事件名称
MariaDB [testdb]> alter event testdb.event_test rename to event_test2;
Query OK, 0 rows affected (0.001 sec)
MariaDB [testdb]> show events\G
*************************** 1. row ***************************
Db: testdb
Name: event_test2
Definer: root@localhost
Time zone: SYSTEM
Type: RECURRING
Execute at: NULL
Interval value: 30
Interval field: SECOND
Starts: 2019-12-02 22:59:18
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.001 sec)
MariaDB [testdb]> drop event event_test2;
Query OK, 0 rows affected (0.000 sec)
MariaDB [testdb]> show events;
Empty set (0.001 sec)
MySQL用户管理
相关数据库和表
元数据数据库:mysql
系统授权表:db, host, user,columns_priv, tables_priv, procs_priv, proxies_priv
用户帐号
'USERNAME'@'HOST'
@'HOST':
主机名: user1@'web1.magedu.org'
IP地址或Network
通配符: % _
示例:172.16.%.% user2@'192.168.1.%'
创建用户
CREATE USER 'USERNAME'@'HOST' [IDENTIFIED BY 'password'];
新建用户的默认权限:USAGE
用户重命名
RENAME USER old_user_name TO new_user_name;
删除用户
DROP USER 'USERNAME'@'HOST‘
🍊 范例:删除默认的空用户
DROP USER ''@'localhost';
修改密码 🍍
NOTE
- 新版mysql中用户密码可以保存在mysql.user表的authentication_string字段中
- 如果mysql.user表的authentication_string和password字段都保存密码,authentication_string优先生效;
🍊 范例:修改用户密码
##方法1:(MySQL 5.7 之前的版本)
#mysql -u root -p #进入到mysql里
SET PASSWORD FOR 'root'@'localhost' = PASSWORD('xyy520'); #推荐: #这个命令会直接生效的,如果更新表的话,需要执行`FLUSH PRIVILEGES;`才会生效;
##方法2:(MySQL 5.7 及以上版本)
#mysql -u root -p #进入到mysql里
ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';
FLUSH PRIVILEGES;
##方法3:
#mysql -u root -p #进入到mysql里
update mysql.user set password=password('xyy520') where user='root';
FLUSH PRIVILEGES;
或者
update mysql.user set authentication_string=password('magedu') where user='root';
FLUSH PRIVILEGES;
##方法4:
mysqladmin -u root -p password '新密码'
备注:
在某些情况下,'localhost' 可能需要被替换为具体的主机名或IP地址,具体取决于 `root` 用户可以从哪里访问数据库。如果 `root` 用户应该能够从任何主机连接,请使用 `'root'@'%'`。
备注:
#mariadb 10.3
update mysql.user set authentication_string=password('ubuntu') where user='mage';
#此方法需要执行下面指令才能生效:
FLUSH PRIVILEGES;
忘记管理员密码的解决办法🍊
启动mysqld进程时,为其使用如下选项:
bash--skip-grant-tables --skip-networking
使用UPDATE命令修改管理员密码
关闭mysqld进程,移除上述两个选项,重启mysqld
🍊 范例:破解root密码
[root@centos8 ~]#vim /etc/my.cnf
[mysqld]
skip-grant-tables
skip-networking
[root@centos8 ~]#systemctl restart mariadb
[root@centos8 ~]#mysql
#mariadb 新版
MariaDB [(none)]> update mysql.user set authentication_string=password('ubuntu') where user='root';
#mariadb 旧版
MariaDB [(none)]> update mysql.user set password=password('ubuntu') where user='root';
[root@centos8 ~]#systemctl restart mariadb
[root@centos8 ~]#vim /etc/my.cnf
[mysqld]
#skip-grant-tables
#skip-networking
[root@centos8 ~]#systemctl restart mariadb
[root@centos8 ~]#mysql -uroot -pubuntu
权限管理和DCL语句
权限类别:
- 管理类
- 程序类
- 数据库级别
- 表级别
- 字段级别
管理类:
- 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
授权: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@'192.168.8.%' IDENTIFIED BY 'magedu';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.8.%' IDENTIFIED BY 'magedu' WITH GRANT OPTION;
GRANT ALL ON hellodb.* TO test@'192.168.8.%';
#生产里推荐,一条命令完成创建用户+赋予用户权限事项。
GRANT ALL PRIVILEGES ON *.* TO 'admin'@'172.29.9.%' IDENTIFIED BY 'magedu' WITH GRANT OPTION;
查看指定用户获得的授权
Help SHOW GRANTS
SHOW GRANTS FOR 'user'@'host';
SHOW GRANTS FOR CURRENT_USER[()];
取消授权: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 testdb.* FROM 'testuser'@‘172.16.0.%’;
NOTE
注意:MariaDB服务进程启动时会读取mysql库中所有授权表至内存
(1) GRANT或REVOKE等执行权限操作会保存于系统表中,MariaDB的服务进程通常会自动重读授权表,使之生效
(2) 对于不能够或不能及时重读授权表的命令,可手动让MariaDB的服务进程重读授权表:mysql> FLUSH PRIVILEGES;
MySQL的图形化的远程管理工具
在MySQL数据库中创建用户并授权后,可以使用相关图形化工具进行远程的管理。
常见的图形化管理工具:
- Navicat
- SQLyog
Navicat 工具
SQLyog 工具
4、MySQL架构和性能优化
thread reuse 线程复用
optimizer 优化器
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运作还提供了管理和服务工具,例如:备份恢复工具,安全工具,复制工具,集群服务,管理、配置、迁移、元数据等工具。
存储引擎
MySQL中的数据用各种不同的技术存储在文件(或者内存)中。这些技术中的每一种技术都使用不同的存储机制、索引技巧、锁定水平并且最终提供广泛的不同的功能和能力,此种技术称为存储擎,MySQL 支持多种存储引擎其中目前应用最广泛的是InnoDB和MyISAM两种。
官方参考资料:https://docs.oracle.com/cd/E17952_01/mysql-5.7-en/storage-engines.html
1.MyISAM存储引擎
面试:总爱问MyISAM和InnoDB 两种存储引擎的区别。
MyISAM引擎特点
- 不支持事务表级锁定
- 读写相互阻塞,写入不能读,读时不能写
- 只缓存索引
- 不支持外键约束
- 不支持聚簇索引
- 读取数据较快,占用资源较少
- 不支持MVCC(多版本并发控制机制)高并发
- 崩溃恢复性较差
- MySQL5.5.5前默认的数据库引擎
MyISAM****存储引擎适用场景
- 只读(或者写较少)
- 表较小(可以接受长时间进行修复操作)
MyISAM引擎文件
- tbl_name.frm 表格式定义
- tbl_name.MYD 数据文件
- tbl_name.MYI 索引文件
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_per_table
07:27:05(root@localhost) [(none)]> show variables like 'innodb_file_per_table';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| innodb_file_per_table | ON |
+-----------------------+-------+
1 row in set (0.001 sec)
其它存储引擎
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”引擎,它什么都不做。可以使用此引擎创建表,但不能将数据存储在其中或从中检索。目的是作为例子来说明如何开始编写新的存储引擎
管理存储引擎
- 查看mysql支持的存储引擎
SHOW ENGINES;
- 查看当前默认的存储引擎
05:15:56(root@localhost) [(none)]> show variables like '%storage_engine%';
+----------------------------+--------+
| Variable_name | Value |
+----------------------------+--------+
| default_storage_engine | InnoDB |
| default_tmp_storage_engine | |
| enforce_storage_engine | |
| storage_engine | InnoDB |
+----------------------------+--------+
4 rows in set (0.001 sec)
- 设置默认的存储引擎
vim /etc/my.cnf
[mysqld]
default_storage_engine= InnoDB
- 查看库中所有表使用的存储引擎
show table status from mysql\G
……
*************************** 30. row ***************************
Name: transaction_registry
Engine: InnoDB
Version: 10
Row_format: Dynamic
Rows: 0
Avg_row_length: 0
Data_length: 16384
Max_data_length: 0
Index_length: 49152
Data_free: 0
Auto_increment: NULL
Create_time: 2024-03-29 06:02:16
Update_time: NULL
Check_time: NULL
Collation: utf8_bin
Checksum: NULL
Create_options: stats_persistent=0
Comment:
Max_index_length: 0
Temporary: N
……
- 查看库中指定表的存储引擎
show table status like 'tb_name';
show create table tb_name;
- 设置表的存储引擎:
CREATE TABLE tb_name(... ) ENGINE=InnoDB;
ALTER TABLE tb_name ENGINE=InnoDB;
MySQL中的系统数据库
mysql数据库
是mysql的核心数据库,类似于Sql Server中的master库,主要负责存储数据库的用户、权限设置、关键字等mysql自己需要使用的控制和管理信息
performance_schema数据库
MySQL 5.5开始新增的数据库,主要用于收集数据库服务器性能参数,库里表的存储引擎均为PERFORMANCE_SCHEMA,用户不能创建存储引擎为PERFORMANCE_SCHEMA的表
information_schema数据库
MySQL 5.0之后产生的,一个虚拟数据库,物理上并不存在information_schema数据库,类似与“数据字典”,提供了访问数据库元数据的方式,即数据的数据。比如数据库名或表名,列类型,访问权限(更加细化的访问方式)
sys数据库
MySQL5.7之后新增加的数据库,库中所有数据源来自performance_schema。目标是把performance_schema的把复杂度降低,让DBA能更好的阅读这个库里的内容。让DBA更快的了解DB的运行情况
服务器配置和状态
可以通过mysqld选项,服务器系统变量和服务器状态变量进行MySQL的配置和查看状态
官方帮助:
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/
mysql:
mariadb:
注意:
- 其中有些参数支持运行时修改,会立即生效
- 有些参数不支持动态修改,且只能通过修改配置文件,并重启服务器程序生效
- 有些参数作用域是全局的,为所有会话设置
- 有些可以为每个用户提供单独(会话)的设置
1.服务器选项
这2行是yes的就是服务器选项:
获取mysqld的可用选项列表:
#查看mysqld可用选项列表和及当前值
mysqld --verbose --help
#获取mysqld当前启动选项
mysqld --print-defaults
- 范例:
[root@test ~]# mysqld --verbose --help|grep datadir
……
datadir /var/lib/mysql/
[root@test ~]# mysqld --verbose --help|grep skip-grant-tables
skip-grant-tables FALSE
设置服务器选项方法:
在命令行中设置
sqlshell> /usr/bin/mysqld_safe --skip-name-resolve=1 shell> /usr/libexec/mysqld --basedir=/usr
在配置文件my.cnf中设置
范例:
sql#vim /etc/my.cnf [mysqld] skip_name_resolve=1 skip-grant-tables
- 范例: skip-grant-tables是服务器选项,但不是系统变量
[root@test ~]# mysqladmin variables |grep skip-grant-tables
[root@test ~]# mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 270
Server version: 10.5.24-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-variables';
Empty set (0.001 sec)
MariaDB [(none)]>
2.服务器系统变量
服务器系统变量:可以分全局和会话两种
获取系统变量:
SHOW GLOBAL VARIABLES; #只查看global变量
SHOW [SESSION] VARIABLES;#查看所有变量(包括global和session)
#查看指定的系统变量
SHOW VARIABLES LIKE 'VAR_NAME';
SELECT @@VAR_NAME;
#查看选项和部分变量
[root@centos8 ~]#mysqladmin variables
[root@test ~]# mysql -e 'show variables'|wc -l
668
[root@test ~]# mysql -e 'show global variables'|wc -l
649
[root@test ~]# mysql -e 'show session variables'|wc -l
668
修改服务器变量的值:
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;
范例:修改变量server_id的值
[root@test ~]# mysql -e 'show global variables'|grep server_id
server_id 1
[root@test ~]# mysql -e 'show session variables'|grep server_id
server_id 1
MariaDB [(none)]> set global server_id=200;
Query OK, 0 rows affected (0.000 sec)
MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
| 200 |
+-------------+
1 row in set (0.000 sec)
MariaDB [(none)]> set session server_id=300;
Query OK, 0 rows affected (0.000 sec)
MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
| 300 |
+-------------+
1 row in set (0.000 sec)
范例:查看系统变量的值
MariaDB [(none)]> show variables like 'datadir'; #这个变量不支持动态修改。
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| datadir | /var/lib/mysql/ |
+---------------+-----------------+
1 row in set (0.001 sec)
MariaDB [(none)]> set global datadir='/data';
ERROR 1238 (HY000): Variable 'datadir' is a read only variable
范例:修改mysql的最大并发连接数
MariaDB [(none)]> show variables like 'max_connections';
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| max_connections | 151 |
+-----------------+-------+
1 row in set (0.001 sec)
MariaDB [(none)]> set max_connections=5000;
ERROR 1229 (HY000): Variable 'max_connections' is a GLOBAL variable and should be set with SET GLOBAL
MariaDB [(none)]> set global max_connections=5000;
Query OK, 0 rows affected (0.000 sec)
MariaDB [(none)]> show variables like 'max_connections';
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| max_connections | 5000 |
+-----------------+-------+
1 row in set (0.001 sec)
这个max_connections
既是服务器选项,又是全局系统变量,因此支持写到系统配置文件的。vim /etc/my.cnf
#vim /etc/my.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 |
+-------------------+
范例: character_set_results是系统变量并非服务器选项
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 | utf8 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows 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%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.001 sec)
#character_set_results不是服务器选项,写入配置文件将导致无法启动
[root@test ~]# vim /etc/my.cnf
[mysqld]
character_set_results=utf8mb4
[root@test ~]# 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.
[root@test ~]# systemctl status mariadb
● mariadb.service - MariaDB 10.5.24 database server
Loaded: loaded (/usr/lib/systemd/system/mariadb.service; enabled; vendor preset: disabled)
Drop-In: /etc/systemd/system/mariadb.service.d
└─migrated-from-my.cnf-settings.conf
Active: failed (Result: exit-code) since Mon 2024-05-20 06:54:43 CST; 5s ago
Docs: man:mariadbd(8)
https://mariadb.com/kb/en/library/systemd/
……
id 1331
May 20 06:54:42 test mariadbd[29643]: 2024-05-20 6:54:42 0 [Note] Plugin 'FEEDBACK' is disabled.
May 20 06:54:42 test mariadbd[29643]: 2024-05-20 6:54:42 0 [ERROR] /usr/sbin/mariadbd: unknown variable 'character_set_results=utf8mb4'
May 20 06:54:42 test mariadbd[29643]: 2024-05-20 6:54:42 0 [ERROR] Aborting
May 20 06:54:43 test systemd[1]: mariadb.service: main process exited, code=exited, status=7/NOTRUNNING
May 20 06:54:43 test systemd[1]: Failed to start MariaDB 10.5.24 database server.
May 20 06:54:43 test systemd[1]: Unit mariadb.service entered failed state.
May 20 06:54:43 test systemd[1]: mariadb.service failed.
Hint: Some lines were ellipsized, use -l to show in full.
范例:修改页大小
参看: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)
3.服务器状态变量
服务器状态变量:分全局和会话两种
状态变量(只读):用于保存mysqld运行中的统计数据的变量,不可更改
SHOW GLOBAL STATUS;
SHOW [SESSION] STATUS;
范例:
注意:这个系统变量只对本地当前终端会话有效果。
[root@test2 ~]#mysql -e 'show variables'|grep -i com_select
[root@test2 ~]#mysql -e 'show status'|grep -i com_select
Com_select 0
07:40:55(root@localhost) [(none)]> show global status like 'com_select';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Com_select | 6 |
+---------------+-------+
1 row in set (0.000 sec)
07:40:58(root@localhost) [(none)]> select user,host from mysql.user;
+-------------+-------------+
| User | Host |
+-------------+-------------+
| admin | 172.29.%.% |
| admin | 172.29.9.% |
| test | 172.29.9.% |
| admin | 192.168.8.% |
| mariadb.sys | localhost |
| mysql | localhost |
| root | localhost |
+-------------+-------------+
7 rows in set (0.018 sec)
07:41:08(root@localhost) [(none)]> show global status like 'com_select';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Com_select | 7 |
+---------------+-------+
1 row in set (0.001 sec)
07:41:11(root@localhost) [(none)]>
服务器变量 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 7 修改SQL_MODE变量实现分组语句控制
06:30:20(root@localhost) [hellodb]> select @@sql_mode;
+-------------------------------------------------------------------------------------------+
| @@sql_mode |
+-------------------------------------------------------------------------------------------+
| STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+-------------------------------------------------------------------------------------------+
1 row in set (0.000 sec)
06:30:42(root@localhost) [hellodb]> select classid,count(*) from students group by classid;
+---------+----------+
| classid | count(*) |
+---------+----------+
| NULL | 2 |
| 1 | 4 |
| 2 | 3 |
| 3 | 4 |
| 4 | 4 |
| 5 | 1 |
| 6 | 4 |
| 7 | 3 |
+---------+----------+
8 rows in set (0.011 sec)
06:30:42(root@localhost) [hellodb]> select classid,count(*) from students group by classid;
+---------+----------+
| classid | count(*) |
+---------+----------+
| NULL | 2 |
| 1 | 4 |
| 2 | 3 |
| 3 | 4 |
| 4 | 4 |
| 5 | 1 |
| 6 | 4 |
| 7 | 3 |
+---------+----------+
8 rows in set (0.011 sec)
#修改SQL_MODE
06:32:54(root@localhost) [hellodb]> set sql_mode="ONLY_FULL_GROUP_BY";
Query OK, 0 rows affected (0.000 sec)
06:33:01(root@localhost) [hellodb]> show variables like 'sql_mode';
+---------------+--------------------+
| Variable_name | Value |
+---------------+--------------------+
| sql_mode | ONLY_FULL_GROUP_BY |
+---------------+--------------------+
1 row in set (0.001 sec)
06:33:10(root@localhost) [hellodb]> select classid,count(*) from students group by classid;^C
06:33:10(root@localhost) [hellodb]> select stuid,classid,count(*) from students group by classid;
ERROR 1055 (42000): 'hellodb.students.StuID' isn't in GROUP BY
06:33:46(root@localhost) [hellodb]> select classid,count(*) from students group by classid;
+---------+----------+
| classid | count(*) |
+---------+----------+
| NULL | 2 |
| 1 | 4 |
| 2 | 3 |
| 3 | 4 |
| 4 | 4 |
| 5 | 1 |
| 6 | 4 |
| 7 | 3 |
+---------+----------+
8 rows in set (0.000 sec)
范例:CentOS 7 修改SQL_MODE变量
06:33:53(root@localhost) [hellodb]> create table test (id int ,name varchar(3));
Query OK, 0 rows affected (0.016 sec)
06:40:59(root@localhost) [hellodb]> insert test values(1,'abcde');
Query OK, 1 row affected, 1 warning (0.001 sec)
06:41:06(root@localhost) [hellodb]> show warnings;
+---------+------+-------------------------------------------+
| Level | Code | Message |
+---------+------+-------------------------------------------+
| Warning | 1265 | Data truncated for column 'name' at row 1 |
+---------+------+-------------------------------------------+
1 row in set (0.000 sec)
06:41:11(root@localhost) [hellodb]> select * from test;
+------+------+
| id | name |
+------+------+
| 1 | abc |
+------+------+
1 row in set (0.000 sec)
06:41:17(root@localhost) [hellodb]> show variables like 'SQL_MODE';
+---------------+--------------------+
| Variable_name | Value |
+---------------+--------------------+
| sql_mode | ONLY_FULL_GROUP_BY |
+---------------+--------------------+
1 row in set (0.001 sec)
06:41:23(root@localhost) [hellodb]> SET SQL_MODE=TRADITIONAL;
Query OK, 0 rows affected (0.000 sec)
06:41:28(root@localhost) [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_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+---------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.001 sec)
06:41:29(root@localhost) [hellodb]> insert test values(2,'magedu');
ERROR 1406 (22001): Data too long for column 'name' at row 1
Query Cache 查询缓存
查询缓存原理
查询执行路径
查询缓存原理 哈希运算
缓存SELECT操作或预处理查询的结果集和SQL语句,当有新的SELECT语句或预处理查询语句请求,先去查询缓存,判断是否存在可用的记录集,判断标准:与缓存的SQL语句,是否完全一样,区分大小写
优缺点
不需要对SQL语句做任何解析和执行,当然语法解析必须通过在先,直接从Query Cache中获得查询结果,提高查询性能;
查询缓存的判断规则,不够智能,也即提高了查询缓存的使用门槛,降低效率;
查询缓存的使用,会增加检查和清理Query Cache中记录集的开销;
哪些查询可能不会被缓存
- 查询语句中加了SQL_NO_CACHE参数
- 查询语句中含有获得值的函数,包含:自定义函数,如:NOW() ,CURDATE()、GET_LOCK()、RAND()、CONVERT_TZ()等
- 对系统数据库的查询:mysql、information_schema 查询语句中使用SESSION级别变量或存储过程中的局部变量
- 查询语句中使用了LOCK IN SHARE MODE、FOR UPDATE的语句,查询语句中类似SELECT …
- INTO 导出数据的语句
- 对临时表的查询操作
- 存在警告信息的查询语句
- 不涉及任何表或视图的查询语句
- 某用户只有列级别权限的查询语句
- 事务隔离级别为Serializable时,所有查询语句都不能缓存
查询缓存相关的服务器变量
- query_cache_min_res_unit:查询缓存中内存块的最小分配单位,默认4k,较小值会减少浪费,但会导致更频繁的内存分配操作,较大值会带来浪费,会导致碎片过多,内存不足;
- query_cache_limit:单个查询结果能缓存的最大值,单位字节,默认为1M,对于查询结果过大而无法缓存的语句,建议使用SQL_NO_CACHE
- query_cache_size:查询缓存总共可用的内存空间;单位字节,必须是1024的整数倍,最小值40KB,低于此值有警报
- query_cache_wlock_invalidate:如果某表被其它的会话锁定,是否仍然可以从查询缓存中返回结果,默认值为OFF,表示可以在表被其它会话锁定的场景中继续从缓存返回数据;ON则表示不允许
- query_cache_type:是否开启缓存功能,取值为ON, OFF, DEMAND(按需开启,看select语句是否加
sql_cache参数
)
范例:配置文件配置服务器选项
06:41:40(root@localhost) [hellodb]> show variables like 'query_cache%';
+------------------------------+---------+
| Variable_name | Value |
+------------------------------+---------+
| query_cache_limit | 1048576 |
| query_cache_min_res_unit | 4096 |
| query_cache_size | 1048576 |
| query_cache_strip_comments | OFF |
| query_cache_type | OFF |
| query_cache_wlock_invalidate | OFF |
+------------------------------+---------+
6 rows in set (0.001 sec)
#vim /etc/my.cnf
[mysqld]
query_cache_type=ON
query_cache_size=200M
systemctl restart mariadb
[root@test2 ~]#mysql hellodb
07:42:09(root@localhost) [hellodb]> show variables like 'query_cache%';
+------------------------------+-----------+
| Variable_name | Value |
+------------------------------+-----------+
| query_cache_limit | 1048576 |
| query_cache_min_res_unit | 4096 |
| query_cache_size | 209715200 |
| query_cache_strip_comments | OFF |
| query_cache_type | ON |
| query_cache_wlock_invalidate | OFF |
+------------------------------+-----------+
6 rows in set (0.001 sec)
SELECT语句的缓存控制
查询缓存相关的状态变量
07:44:25(root@localhost) [hellodb]> show global status like 'Qcache%%';
+-------------------------+-----------+
| Variable_name | Value |
+-------------------------+-----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 209697192 |
| Qcache_hits | 0 |
| Qcache_inserts | 0 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 2 |
| Qcache_queries_in_cache | 0 |
| Qcache_total_blocks | 1 |
+-------------------------+-----------+
8 rows in set (0.001 sec)
- Qcache_free_blocks:处于空闲状态 Query Cache中内存 Block 数
- Qcache_total_blocks:Query Cache 中总Block ,当Qcache_free_blocks相对此值较大时,可能用内存碎片,执行FLUSH QUERY CACHE清理碎片
- Qcache_free_memory:处于空闲状态的 Query Cache 内存总量
- Qcache_hits:Query Cache 命中次数
- Qcache_inserts:向 Query Cache 中插入新的 Query Cache 的次数,即没有命中的次数
- Qcache_lowmem_prunes:记录因为内存不足而被移除出查询缓存的查询数
- Qcache_not_cached:没有被 Cache 的 SQL 数,包括无法被 Cache 的 SQL 以及由于
- query_cache_type 设置的不会被 Cache 的 SQL语句
- Qcache_queries_in_cache:在 Query Cache 中的 SQL 数量
范例:Query Cache测试
07:44:25(root@localhost) [hellodb]> show global status like 'Qcache%%';
+-------------------------+-----------+
| Variable_name | Value |
+-------------------------+-----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 209697192 |
| Qcache_hits | 0 |
| Qcache_inserts | 0 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 2 |
| Qcache_queries_in_cache | 0 |
| Qcache_total_blocks | 1 |
+-------------------------+-----------+
8 rows in set (0.001 sec)
07:44:31(root@localhost) [hellodb]> select *from students where stuid=1;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
+-------+-------------+-----+--------+---------+-----------+
1 row in set (0.001 sec)
07:55:49(root@localhost) [hellodb]> show global status like 'Qcache%%';
+-------------------------+-----------+
| Variable_name | Value |
+-------------------------+-----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 209695656 |
| Qcache_hits | 0 |
| Qcache_inserts | 1 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 2 |
| Qcache_queries_in_cache | 1 |
| Qcache_total_blocks | 4 |
+-------------------------+-----------+
8 rows in set (0.001 sec)
07:55:53(root@localhost) [hellodb]> select *from students where stuid=2;
+-------+------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+------------+-----+--------+---------+-----------+
| 2 | Shi Potian | 22 | M | 1 | 7 |
+-------+------------+-----+--------+---------+-----------+
1 row in set (0.000 sec)
07:56:03(root@localhost) [hellodb]> show global status like 'Qcache%%';
+-------------------------+-----------+
| Variable_name | Value |
+-------------------------+-----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 209694632 |
| Qcache_hits | 0 |
| Qcache_inserts | 2 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 2 |
| Qcache_queries_in_cache | 2 |
| Qcache_total_blocks | 6 |
+-------------------------+-----------+
8 rows in set (0.000 sec)
07:56:04(root@localhost) [hellodb]> select *from students where stuid=1;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
+-------+-------------+-----+--------+---------+-----------+
1 row in set (0.000 sec)
07:56:28(root@localhost) [hellodb]> show global status like 'Qcache%%';
+-------------------------+-----------+
| Variable_name | Value |
+-------------------------+-----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 209694632 |
| Qcache_hits | 1 |
| Qcache_inserts | 2 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 2 |
| Qcache_queries_in_cache | 2 |
| Qcache_total_blocks | 6 |
+-------------------------+-----------+
8 rows in set (0.000 sec)
07:56:30(root@localhost) [hellodb]> select *from students where stuid=1;
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
+-------+-------------+-----+--------+---------+-----------+
1 row in set (0.000 sec)
07:56:38(root@localhost) [hellodb]> show global status like 'Qcache%%';
+-------------------------+-----------+
| Variable_name | Value |
+-------------------------+-----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 209694632 |
| Qcache_hits | 2 |
| Qcache_inserts | 2 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 2 |
| Qcache_queries_in_cache | 2 |
| Qcache_total_blocks | 6 |
+-------------------------+-----------+
8 rows in set (0.001 sec)
大小写有区别;
空格在sql语句中间有区别,但在sql语句前面或者最后面是可以的;
查询的优化
命中率和内存使用率估算
查询缓存中内存块的最小分配单位query_cache_min_res_unit :
sql(query_cache_size - Qcache_free_memory) / Qcache_queries_in_cache
查询缓存命中率 :
sqlQcache_hits / ( Qcache_hits + Qcache_inserts ) * 100%
查询缓存内存使用率:
sql(query_cache_size – qcache_free_memory) / query_cache_size * 100%
MySQL 8.0 变化
MySQL8.0 取消查询缓存的功能
尽管MySQL Query Cache旨在提高性能,但它存在严重的可伸缩性问题,并且很容易成为严重的瓶颈。
自MySQL 5.6(2013)以来,默认情况下已禁用查询缓存,其不能与多核计算机上在高吞吐量工作负载情况下进行扩展。
另外有时因为查询缓存往往弊大于利。比如:查询缓存的失效非常频繁,只要有对一个表的更新,这个表上的所有的查询缓存都会被清空。因此很可能你费劲地把结果存起来,还没使用呢,就被一个更新全清空了。对于更新压力大的数据库来说,查询缓存的命中率会非常低。除非你的业务有一张静态表,很长时间更新一次,比如系统配置表,那么这张表的查询才适合做查询缓存。
目前大多数应用都把缓存做到了应用逻辑层,比如:使用redis或者memcache。
INDEX 索引
很重要。
索引介绍
索引:是排序的快速查找的特殊数据结构,定义作为查找条件的字段上,又称为键key,索引通过存储引擎实现
优点:
- 索引可以降低服务需要扫描的数据量,减少了IO次数
- 索引可以帮助服务器避免排序和使用临时表
- 索引可以帮助将随机I/O转为顺序I/O
缺点:
- 占用额外空间,影响插入速度
索引类型:
- B+ TREE、HASH、R TREE、FULL TEXT
- 聚簇(集)索引、非聚簇索引:数据和索引是否存储在一起
- 主键索引、二级(辅助)索引
- 稠密索引、稀疏索引:是否索引了每一个数据项
- 简单索引、组合索引
- 左前缀索引:取前面的字符做索引
- 覆盖索引:从索引中即可取出要查询的数据,性能高
索引结构
二叉树
红黑树
B Tree 索引
B+Tree索引
B+Tree索引:按顺序存储,每一个叶子节点到根结点的距离是相同的;左前缀索引,适合查询范围类的数据
可以使用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)
重复索引:已经有索引,再次建立索引
索引优化
- 独立地使用列:尽量避免其参与运算,独立的列指索引列不能是表达式的一部分,也不能是函数的参数,在where条件中,始终将索引列单独放在比较符号的一侧,尽量不要在列上进行运算(函数操作和表达式操作)
- 左前缀索引:构建指定索引字段的左侧的字符数,要通过索引选择性(不重复的索引值和数据表的
- 记录总数的比值)来评估,尽量使用短索引,如果可以,应该制定一个前缀长度
- 多列索引:AND操作时更适合使用多列索引,而非为每个列创建单独的索引
- 选择合适的索引列顺序:无排序和分组时,将选择性最高放左侧
- 只要列中含有NULL值,就最好不要在此列设置索引,复合索引如果有NULL值,此列在使用时也不会使用索引
- 对于经常在where子句使用的列,最好设置索引
- 对于有多个列where或者order by子句,应该建立复合索引
- 对于like语句,以 % 或者 _ 开头的不会使用索引,以 % 结尾会使用索引
- 尽量不要使用not in和
<>
操作,虽然可能使用索引,但性能不高 - 不要使用RLIKE正则表达式会导致索引失效
- 查询时,能不要就不用,尽量写全字段名,比如:select id,name,age from students;
- 大部分情况连接效率远大于子查询
- 在有大量记录的表分页时使用limit
- 对于经常使用的查询,可以开启查询缓存
- 多使用explain和profile分析查询语句
- 查看慢查询日志,找出执行时间长的sql语句优化
管理索引
创建索引:
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 INDEXES FROM [db_name.]tbl_name;
优化表空间:
OPTIMIZE TABLE tb_name;
查看索引的使用
SET GLOBAL userstat=1;
SHOW INDEX_STATISTICS;
范例
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.001 sec)
MariaDB [hellodb]> desc students;
#这里的key就是索引,建主键的时候同时就自动建立了索引。
+-----------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+----------------+
| StuID | int(10) unsigned | NO | PRI | NULL | auto_increment |
| Name | varchar(50) | NO | | NULL | |
| Age | tinyint(3) unsigned | NO | | NULL | |
| Gender | enum('F','M') | NO | | NULL | |
| ClassID | tinyint(3) unsigned | YES | | NULL | |
| TeacherID | int(10) unsigned | YES | | NULL | |
+-----------+---------------------+------+-----+---------+----------------+
6 rows in set (0.001 sec)
#手动建立索引
MariaDB [hellodb]> create index idx_name on students(name(10));
Query OK, 0 rows affected (0.007 sec)
Records: 0 Duplicates: 0 Warnings: 0
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:
*************************** 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.001 sec)
MariaDB [hellodb]> desc students;
+-----------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+----------------+
| StuID | int(10) unsigned | NO | PRI | NULL | auto_increment |
| Name | varchar(50) | NO | MUL | NULL | |
| Age | tinyint(3) unsigned | NO | | NULL | |
| Gender | enum('F','M') | NO | | NULL | |
| ClassID | tinyint(3) unsigned | YES | | NULL | |
| TeacherID | int(10) unsigned | YES | | NULL | |
+-----------+---------------------+------+-----+---------+----------------+
6 rows in set (0.001 sec)
#删除索引
MariaDB [hellodb]> drop index idx_name on students;
Query OK, 0 rows affected (0.004 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [hellodb]> desc students;
+-----------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+----------------+
| StuID | int(10) unsigned | NO | PRI | NULL | auto_increment |
| Name | varchar(50) | NO | | NULL | |
| Age | tinyint(3) unsigned | NO | | NULL | |
| Gender | enum('F','M') | NO | | NULL | |
| ClassID | tinyint(3) unsigned | YES | | NULL | |
| TeacherID | int(10) unsigned | YES | | NULL | |
+-----------+---------------------+------+-----+---------+----------------+
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]> select @@userstat;
+------------+
| @@userstat |
+------------+
| 0 |
+------------+
1 row in set (0.000 sec)
MariaDB [hellodb]> show variables like 'userstat';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| userstat | OFF |
+---------------+-------+
1 row in set (0.001 sec)
#开启
MariaDB [hellodb]> set global userstat=1;
Query OK, 0 rows affected (0.000 sec)
MariaDB [hellodb]> show variables like 'userstat';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| userstat | ON |
+---------------+-------+
1 row in set (0.001 sec)
#再次建立下之前的索引
MariaDB [hellodb]> create index idx_name on students(name(10));
Query OK, 0 rows affected (0.004 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [hellodb]> desc students;
+-----------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+----------------+
| StuID | int(10) unsigned | NO | PRI | NULL | auto_increment |
| Name | varchar(50) | NO | MUL | NULL | |
| Age | tinyint(3) unsigned | NO | | NULL | |
| Gender | enum('F','M') | NO | | NULL | |
| ClassID | tinyint(3) unsigned | YES | | NULL | |
| TeacherID | int(10) unsigned | YES | | NULL | |
+-----------+---------------------+------+-----+---------+----------------+
6 rows in set (0.001 sec)
#MariaDB [hellodb]> show index_statistics;
Empty set (0.000 sec)
#直接查,是没有利用索引的
MariaDB [hellodb]> select *from students;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL |
| 24 | Xu Xian | 27 | M | NULL | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
+-------+---------------+-----+--------+---------+-----------+
25 rows in set (0.001 sec)
MariaDB [hellodb]> show index_statistics;
Empty set (0.000 sec)
#模拟使用索引
MariaDB [hellodb]> select *from students where stuid=10;
+-------+--------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+--------------+-----+--------+---------+-----------+
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
+-------+--------------+-----+--------+---------+-----------+
1 row in set (0.001 sec)
MariaDB [hellodb]> show index_statistics;
+--------------+------------+------------+-----------+
| Table_schema | Table_name | Index_name | Rows_read |
+--------------+------------+------------+-----------+
| hellodb | students | PRIMARY | 1 |
+--------------+------------+------------+-----------+
1 row in set (0.000 sec)
MariaDB [hellodb]> select *from students where stuid=10;
+-------+--------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+--------------+-----+--------+---------+-----------+
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
+-------+--------------+-----+--------+---------+-----------+
1 row in set (0.001 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)
MariaDB [hellodb]> select *from students where name='Yue Lingshan';
+-------+--------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+--------------+-----+--------+---------+-----------+
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
+-------+--------------+-----+--------+---------+-----------+
1 row in set (0.001 sec)
MariaDB [hellodb]> show index_statistics;
+--------------+------------+------------+-----------+
| Table_schema | Table_name | Index_name | Rows_read |
+--------------+------------+------------+-----------+
| hellodb | students | idx_name | 1 |
| hellodb | students | PRIMARY | 2 |
+--------------+------------+------------+-----------+
2 rows in set (0.000 sec)
MariaDB [hellodb]> select *from students where name='Yue Lingshan';
+-------+--------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+--------------+-----+--------+---------+-----------+
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
+-------+--------------+-----+--------+---------+-----------+
1 row in set (0.001 sec)
MariaDB [hellodb]> show index_statistics;
+--------------+------------+------------+-----------+
| Table_schema | Table_name | Index_name | Rows_read |
+--------------+------------+------------+-----------+
| hellodb | students | idx_name | 2 |
| hellodb | students | PRIMARY | 2 |
+--------------+------------+------------+-----------+
2 rows in set (0.000 sec)
#可以通过这个简单的方法来统计索引用没用。
#以上命令只能粗略地看到是否使用索引,而不能看到她的细节。
EXPLAIN 工具
可以通过EXPLAIN来分析索引的有效性,获取查询执行计划信息,用来查看查询优化器如何执行查询
参考资料: https://dev.mysql.com/doc/refman/5.7/en/explain-output.html
语法:
EXPLAIN SELECT clause
EXPLAIN输出信息说明:
说明: type显示的是访问类型,是较为重要的一个指标,结果值从好到坏依次是:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL ,一般来说,得保证查询至少达到range级别,最好能达到ref。
一般,达到range基本算是优化可以的了,如果出现index或者all,就说明这个索引还是有优化的空间。
范例:
MariaDB [hellodb]> explain select *from students;
+------+-------------+----------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+----------+------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | students | ALL | NULL | NULL | NULL | NULL | 25 | |
+------+-------------+----------+------+---------------+------+---------+------+------+-------+
1 row in set (0.000 sec)
MariaDB [hellodb]> select *from students where name like 'x%';
+-------+-------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-------------+-----+--------+---------+-----------+
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 24 | Xu Xian | 27 | M | NULL | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
+-------+-------------+-----+--------+---------+-----------+
6 rows in set (0.001 sec)
MariaDB [hellodb]> explain select *from students where name like 's%';
+------+-------------+----------+-------+---------------+----------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+----------+-------+---------------+----------+---------+------+------+-------------+
| 1 | SIMPLE | students | range | idx_name | idx_name | 32 | NULL | 4 | Using where |
+------+-------------+----------+-------+---------------+----------+---------+------+------+-------------+
1 row in set (0.001 sec)
#左模糊、全模糊是无法使用索引的
MariaDB [hellodb]> select *from students where name like '%o';
+-------+-----------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+-----------+-----+--------+---------+-----------+
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL |
+-------+-----------+-----+--------+---------+-----------+
2 rows in set (0.001 sec)
MariaDB [hellodb]> explain select *from students where name like '%o';
+------+-------------+----------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+----------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | students | ALL | NULL | NULL | NULL | NULL | 25 | Using where |
+------+-------------+----------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.000 sec)
#以下是可以利用索引的
MariaDB [hellodb]> explain select *from students where stuid > 20;
+------+-------------+----------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+----------+-------+---------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | students | range | PRIMARY | PRIMARY | 4 | NULL | 5 | Using where |
+------+-------------+----------+-------+---------------+---------+---------+------+------+-------------+
1 row in set (0.000 sec)
MariaDB [hellodb]> explain select *from students where stuid > 10 and stuid < 20;
+------+-------------+----------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+----------+-------+---------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | students | range | PRIMARY | PRIMARY | 4 | NULL | 9 | Using where |
+------+-------------+----------+-------+---------------+---------+---------+------+------+-------------+
1 row in set (0.001 sec)
#正则表达式是不使用索引的,很少简单where后面跟正则表达式的
MariaDB [hellodb]> explain select *from students where name rlike '^w';
+------+-------------+----------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+----------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | students | ALL | NULL | NULL | NULL | NULL | 25 | Using where |
+------+-------------+----------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.001 sec)
MariaDB [hellodb]> explain select *from students where name rlike '^W';
+------+-------------+----------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+----------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | students | ALL | NULL | NULL | NULL | NULL | 25 | Using where |
+------+-------------+----------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.001 sec)
#创建复合索引
MariaDB [hellodb]> create index idx_name_age on students(name,age);
Query OK, 0 rows affected (0.006 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [hellodb]> show index from students;
+----------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+----------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| students | 0 | PRIMARY | 1 | StuID | A | 25 | NULL | NULL | | BTREE | | |
| students | 1 | idx_name | 1 | Name | A | 25 | 10 | NULL | | BTREE | | |
| students | 1 | idx_name_age | 1 | Name | A | 25 | NULL | NULL | | BTREE | | |
| students | 1 | idx_name_age | 2 | Age | A | 25 | NULL | NULL | | BTREE | | |
+----------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
#删除冗余索引
MariaDB [hellodb]> drop index idx_name on students;
Query OK, 0 rows affected (0.004 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [hellodb]> explain select *from students where name = "Xu Zhu";
+------+-------------+----------+------+---------------+--------------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+----------+------+---------------+--------------+---------+-------+------+-----------------------+
| 1 | SIMPLE | students | ref | idx_name_age | idx_name_age | 152 | const | 1 | Using index condition |
+------+-------------+----------+------+---------------+--------------+---------+-------+------+-----------------------+
1 row in set (0.001 sec)
#索引失效
MariaDB [hellodb]> explain select *from students where age = 20;
+------+-------------+----------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+----------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | students | ALL | NULL | NULL | NULL | NULL | 25 | Using where |
+------+-------------+----------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.001 sec)
#索引失效(做模糊)
MariaDB [hellodb]> explain select *from students where name like '%s' and age = 20;
+------+-------------+----------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+----------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | students | ALL | NULL | NULL | NULL | NULL | 25 | Using where |
+------+-------------+----------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.001 sec)
MariaDB [hellodb]> explain select *from students where name = 'Ma Chao' and age = 20;
+------+-------------+----------+------+---------------+--------------+---------+-------------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+----------+------+---------------+--------------+---------+-------------+------+-----------------------+
| 1 | SIMPLE | students | ref | idx_name_age | idx_name_age | 153 | const,const | 1 | Using index condition |
+------+-------------+----------+------+---------------+--------------+---------+-------------+------+-----------------------+
1 row in set (0.001 sec)
并发控制
锁机制
锁:
读锁:共享锁,也称为 S 锁,只读不可写(包括当前事务) ,多个读互不阻塞
写锁:独占锁,排它锁,也称为 X 锁,写锁会阻塞其它事务(不包括当前事务)的读和写
S 锁和 S 锁是兼容的,X 锁和其它锁都不兼容,举个例子,事务 T1 获取了一个行 r1 的 S 锁,另外事务 T2 可以立即获得行 r1 的 S 锁,此时 T1 和 T2 共同获得行 r1 的 S 锁,此种情况称为锁兼容,但是另外一个事务 T2 此时如果想获得行 r1 的 X 锁,则必须等待 T1 对行 r 锁的释放,此种情况也成为锁冲突
锁粒度:
- 表级锁:MyISAM
- 行级锁:InnodB
实现:
存储引擎:自行实现其锁策略和锁粒度
服务器级:实现了锁,表级锁,用户可显式请求
分类:
隐式锁:由存储引擎自动施加锁
显式锁:用户手动请求
锁策略:在锁粒度及数据安全性寻求的平衡机制
显式使用锁
帮助: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]
#范例
FLUSH TABLES 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
范例:如果加锁终端被关闭了,那么锁自然也不存在了。
#终端1
MariaDB [hellodb]> FLUSH TABLES WITH READ LOCK;
#终端2
MariaDB [hellodb]> show processlist;
+----+------+-----------+---------+---------+------+----------+------------------+----------+
| Id | User | Host | db | Command | Time | State | Info | Progress |
+----+------+-----------+---------+---------+------+----------+------------------+----------+
| 68 | root | localhost | hellodb | Sleep | 10 | | NULL | 0.000 |
| 69 | root | localhost | hellodb | Query | 0 | starting | show processlist | 0.000 |
+----+------+-----------+---------+---------+------+----------+------------------+----------+
2 rows in set (0.000 sec)
MariaDB [hellodb]> \s
--------------
mysql Ver 15.1 Distrib 10.5.25-MariaDB, for Linux (x86_64) using readline 5.1
Connection id: 69
Current database: hellodb
Current user: root@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server: MariaDB
Server version: 10.5.25-MariaDB MariaDB Server
Protocol version: 10
Connection: Localhost via UNIX socket
Server characterset: latin1
Db characterset: utf8
Client characterset: utf8
Conn. characterset: utf8
UNIX socket: /var/lib/mysql/mysql.sock
Uptime: 1 day 1 hour 39 min 43 sec
Threads: 2 Questions: 303 Slow queries: 0 Opens: 52 Open tables: 0 Queries per second avg: 0.003
--------------
MariaDB [hellodb]> update students set classid=2 where stuid=24;
Query OK, 1 row affected (3.299 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MariaDB [hellodb]>
事务
事务Transactions:一组原子性的SQL语句,或一个独立工作单元
事务日志:记录事务信息,实现undo,redo等故障恢复功能
事务特性
ACID特性:
- A:atomicity原子性:整个事务中的所有操作要么全部成功执行,要么全部失败后回滚
- C:consistency一致性:数据库总是从一个一致性状态转换为另一个一致性状态
- I:Isolation隔离性:一个事务所做出的操作在提交之前,是不能为其它事务所见;隔离有多种隔离级别,实现并发
- D:durability持久性:一旦事务提交,其所做的修改会永久保存于数据库中
Transaction生命周期
管理事务
显式启动事务:
BEGIN
BEGIN WORK
START TRANSACTION
结束事务:
#提交
COMMIT
#回滚
ROLLBACK
注意:只有事务型存储引擎中的DML语句方能支持此类操作
事务不是万能的!有些指令,并不受事务的约束。 DML语句:insert、update、delete
但注意:truncate、drop等语句本身就是一条提交事务,不走事务机制的,删除就真难得被删除了。
drop table teachers;
truncate table students;
自动提交:
set autocommit={1|0}
默认为1,为0时设为非自动提交
建议:显式请求和提交事务,而不要使用“自动提交”功能。
事务支持保存点:
SAVEPOINT identifier
ROLLBACK [WORK] TO [SAVEPOINT] identifier
RELEASE SAVEPOINT identifier
查看事务:
#查看当前正在进行的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
#查看当前锁定的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
#查看当前等锁的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
范例:测试事务
#查看测试表
MariaDB [hellodb]> select *from students;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL |
| 24 | Xu Xian | 27 | M | 2 | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
+-------+---------------+-----+--------+---------+-----------+
25 rows in set (0.000 sec)
#在一个会话里显示开启一个事务
MariaDB [hellodb]> begin;
Query OK, 0 rows affected (0.000 sec)
#执行2条DML语句
MariaDB [hellodb]> update students set classid=1 where stuid=25;
Query OK, 1 row affected (0.001 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MariaDB [hellodb]> delete from students where stuid=24;
Query OK, 1 row affected (0.001 sec)
#在当前会话里是可以正常看到执行效果的
MariaDB [hellodb]> select *from students;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL |
| 25 | Sun Dasheng | 100 | M | 1 | NULL |
+-------+---------------+-----+--------+---------+-----------+
24 rows in set (0.001 sec)
#但是重新打开一个会话后,发现students表是没任何变化的
MariaDB [hellodb]> select *from students;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL |
| 24 | Xu Xian | 27 | M | 2 | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
+-------+---------------+-----+--------+---------+-----------+
25 rows in set (0.001 sec)
#这是为什么呢?--事务的隔离性
# I:Isolation隔离性:一个事务所做出的操作在提交之前,是不能为其它事务所见;隔离有多种隔离级别,实现并发
#那么我们在原来会话里可以执行rollback
MariaDB [hellodb]> rollback;
Query OK, 0 rows affected (0.001 sec)
#执行之后,本会话看,students里的数据已经恢复到更改前端的状态了。
MariaDB [hellodb]> select *from students;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL |
| 24 | Xu Xian | 27 | M | 2 | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
+-------+---------------+-----+--------+---------+-----------+
25 rows in set (0.001 sec)
#再测试
#开启一个事务,然后执行2条DML语句
MariaDB [hellodb]> begin;
Query OK, 0 rows affected (0.000 sec)
MariaDB [hellodb]> update students set classid=1 where stuid=25;
Query OK, 1 row affected (0.001 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MariaDB [hellodb]> delete from students where stuid=24;
Query OK, 1 row affected (0.001 sec)
#当我吧当前会话关闭后,重新打开一个会话后,那么查看表的现象是什么样的呢?
MariaDB [hellodb]> select *from students;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL |
| 24 | Xu Xian | 27 | M | 2 | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
+-------+---------------+-----+--------+---------+-----------+
25 rows in set (0.001 sec)
#会发现表的状态依然是未发生改变的
#这是由事务的 原子性来决定的。
#A:atomicity原子性:整个事务中的所有操作要么全部成功执行,要么全部失败后回滚
#再测试
#开启一个事务,然后执行2条DML语句
MariaDB [hellodb]> begin;
Query OK, 0 rows affected (0.000 sec)
MariaDB [hellodb]> update students set classid=1 where stuid=25;
Query OK, 1 row affected (0.001 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MariaDB [hellodb]> delete from students where stuid=24;
Query OK, 1 row affected (0.001 sec)
#自己执行下commit
MariaDB [hellodb]> commit;
Query OK, 0 rows affected
MariaDB [hellodb]> select
+-------+---------------+-
| StuID | Name |
+-------+---------------+-
| 1 | Shi Zhongyu |
| 2 | Shi Potian |
| 3 | Xie Yanke |
| 4 | Ding Dian |
| 5 | Yu Yutong |
| 6 | Shi Qing |
| 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 |
| 25 | Sun Dasheng |
+-------+---------------+-
24 rows in set (0.001 sec)
#会发现自己当前会话里数据是发行了改变。关闭当前会话,再重新打开一个会话查看,发现数据已经被改变了的,符合预期。
MariaDB [hellodb]> select *from students;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL |
| 25 | Sun Dasheng | 100 | M | 1 | NULL |
+-------+---------------+-----+--------+---------+-----------+
24 rows in set (0.001 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 | 93 | F |
+-----+---------------+-----+--------+
4 rows in set (0.001 sec)
#开始事务:
MariaDB [hellodb]> begin;insert teachers (name,age,gender)value('a',20,'M');
Query OK, 0 rows affected (0.000 sec)
Query OK, 1 row affected (0.000 sec)
MariaDB [hellodb]> savepoint a;
Query OK, 0 rows affected (0.000 sec)
MariaDB [hellodb]> insert teachers (name,age,gender)value('b',30,'F');
Query OK, 1 row affected (0.000 sec)
MariaDB [hellodb]> savepoint b;
Query OK, 0 rows affected (0.000 sec)
MariaDB [hellodb]> insert teachers (name,age,gender)value('c',40,'F');
Query OK, 1 row affected (0.000 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 | 93 | F |
| 5 | a | 20 | M |
| 6 | b | 30 | F |
| 7 | c | 40 | F |
+-----+---------------+-----+--------+
7 rows in set (0.000 sec)
#撤销
MariaDB [hellodb]> rollback to b;
Query OK, 0 rows affected (0.000 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 | 93 | F |
| 5 | a | 20 | M |
| 6 | b | 30 | F |
+-----+---------------+-----+--------+
6 rows in set (0.001 sec)
MariaDB [hellodb]> rollback to a;
Query OK, 0 rows affected (0.000 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 | 93 | F |
| 5 | a | 20 | M |
+-----+---------------+-----+--------+
5 rows in set (0.001 sec)
MariaDB [hellodb]> rollback;
Query OK, 0 rows affected (0.001 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 | 93 | F |
+-----+---------------+-----+--------+
4 rows in set (0.000 sec)
#不能反撤销:
MariaDB [hellodb]> rollback to c;
ERROR 1305 (42000): SAVEPOINT c does not exist
范例:查看事务
MariaDB [hellodb]> begin;
Query OK, 0 rows affected (0.000 sec)
MariaDB [hellodb]> SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
Empty set (0.000 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 | 93 | F |
+-----+---------------+-----+--------+
4 rows in set (0.000 sec)
MariaDB [hellodb]> SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
+-----------------+-----------+---------------------+-----------------------+------------------+------------+---------------------+---------------------------------------------+---------------------+-------------------+-------------------+------------------+-----------------------+-----------------+-------------------+-------------------------+---------------------+-------------------+------------------------+----------------------------+------------------+----------------------------+
| trx_id | trx_state | trx_started | trx_requested_lock_id | trx_wait_started | trx_weight | trx_mysql_thread_id | trx_query | trx_operation_state | trx_tables_in_use | trx_tables_locked | trx_lock_structs | trx_lock_memory_bytes | trx_rows_locked | trx_rows_modified | trx_concurrency_tickets | trx_isolation_level | trx_unique_checks | trx_foreign_key_checks | trx_last_foreign_key_error | trx_is_read_only | trx_autocommit_non_locking |
+-----------------+-----------+---------------------+-----------------------+------------------+------------+---------------------+---------------------------------------------+---------------------+-------------------+-------------------+------------------+-----------------------+-----------------+-------------------+-------------------------+---------------------+-------------------+------------------------+----------------------------+------------------+----------------------------+
| 421262868086992 | RUNNING | 2024-05-31 06:15:02 | NULL | NULL | 0 | 162 | SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX | | 0 | 0 | 0 | 1128 | 0 | 0 | 0 | REPEATABLE READ | 1 | 1 | NULL | 0 | 0 |
+-----------------+-----------+---------------------+-----------------------+------------------+------------+---------------------+---------------------------------------------+---------------------+-------------------+-------------------+------------------+-----------------------+-----------------+-------------------+-------------------------+---------------------+-------------------+------------------------+----------------------------+------------------+----------------------------+
1 row in set (0.000 sec)
MariaDB [hellodb]> SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX\G
*************************** 1. row ***************************
trx_id: 421262868086992
trx_state: RUNNING
trx_started: 2024-05-31 06:15:02
trx_requested_lock_id: NULL
trx_wait_started: NULL
trx_weight: 0
trx_mysql_thread_id: 162
trx_query: SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX
trx_operation_state:
trx_tables_in_use: 0
trx_tables_locked: 0
trx_lock_structs: 0
trx_lock_memory_bytes: 1128
trx_rows_locked: 0
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
1 row in set (0.000 sec)
MariaDB [hellodb]> update teachers set age=50 where tid=4;
Query OK, 1 row affected (0.001 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MariaDB [hellodb]> SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX\G
*************************** 1. row ***************************
trx_id: 936
trx_state: RUNNING
trx_started: 2024-05-31 06:15:02
trx_requested_lock_id: NULL
trx_wait_started: NULL
trx_weight: 3
trx_mysql_thread_id: 162
trx_query: SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX
trx_operation_state:
trx_tables_in_use: 0
trx_tables_locked: 1
trx_lock_structs: 2
trx_lock_memory_bytes: 1128
trx_rows_locked: 1
trx_rows_modified: 1
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
1 row in set (0.000 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 | 93 | F |
+-----+---------------+-----+--------+
4 rows in set (0.000 sec)
MariaDB [hellodb]> update teachers set gender='M' where tid=4;
……#卡顿,无法更改
#是因为innodb加了行级锁,导致另一个用户就无法修改这行的数据
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 |
+------------+-------------+-----------+-----------+----------------------+------------+------------+-----------+----------+-----------+
| 937:15:3:5 | 937 | X | RECORD | `hellodb`.`teachers` | PRIMARY | 15 | 3 | 5 | 4 |
| 936:15:3:5 | 936 | X | RECORD | `hellodb`.`teachers` | PRIMARY | 15 | 3 | 5 | 4 |
+------------+-------------+-----------+-----------+----------------------+------------+------------+-----------+----------+-----------+
2 rows in set (0.001 sec)
MariaDB [hellodb]> SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX\G
*************************** 1. row ***************************
trx_id: 937
trx_state: LOCK WAIT
trx_started: 2024-05-31 06:22:49
trx_requested_lock_id: 937:15:3:5
trx_wait_started: 2024-05-31 06:25:41
trx_weight: 2
trx_mysql_thread_id: 163 #线程id
trx_query: update teachers set gender='M' where tid=4
trx_operation_state: starting index read
trx_tables_in_use: 1
trx_tables_locked: 1
trx_lock_structs: 2
trx_lock_memory_bytes: 1128
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: 936
trx_state: RUNNING
trx_started: 2024-05-31 06:15:02
trx_requested_lock_id: NULL
trx_wait_started: NULL
trx_weight: 3
trx_mysql_thread_id: 162 #线程id
trx_query: SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX
trx_operation_state:
trx_tables_in_use: 0
trx_tables_locked: 1
trx_lock_structs: 2
trx_lock_memory_bytes: 1128
trx_rows_locked: 1
trx_rows_modified: 1
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.001 sec)
#超时,回滚(50s的超时时长)
MariaDB [hellodb]> update teachers set gender='M' where tid=4;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
#查看当前等锁的事务
MariaDB [hellodb]> SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
+-------------------+-------------------+-----------------+------------------+
| requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id |
+-------------------+-------------------+-----------------+------------------+
| 937 | 937:15:3:5 | 936 | 936:15:3:5 |
+-------------------+-------------------+-----------------+------------------+
1 row in set (0.000 sec)
MariaDB [hellodb]> show processlist;
+-----+------+-----------+---------+---------+------+----------+--------------------------------------------+----------+
| Id | User | Host | db | Command | Time | State | Info | Progress |
+-----+------+-----------+---------+---------+------+----------+--------------------------------------------+----------+
| 162 | root | localhost | hellodb | Sleep | 44 | | NULL | 0.000 |
| 163 | root | localhost | hellodb | Query | 48 | Updating | update teachers set gender='M' where tid=4 | 0.000 |
| 164 | root | localhost | hellodb | Query | 0 | starting | show processlist | 0.000 |
+-----+------+-----------+---------+---------+------+----------+--------------------------------------------+----------+
3 rows in set (0.000 sec)
范例:找到未完成的导致阻塞的事务
#在第一会话中执行
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
...省略...
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 | X | RECORD | `hellodb`.`students` |
PRIMARY | 9 | 3 | 2 | 1 |
| 120:9:3:2 | 120 | X | RECORD | `hellodb`.`students` |
PRIMARY | 9 | 3 | 2 | 1 |
+-----------+-------------+-----------+-----------+----------------------+------
------+------------+-----------+----------+-----------+
2 rows in set (0.001 sec)
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 | Host | db | Command | Time | State
| Info | Progress |
+----+-------------+-----------+---------+---------+------+---------------------
-----+------------------+----------+
| 1 | system user | | NULL | Daemon | NULL | InnoDB purge
coordinator | NULL | 0.000 |
| 3 | system user | | NULL | Daemon | NULL | InnoDB purge worker
| NULL | 0.000 |
| 4 | system user | | NULL | Daemon | NULL | InnoDB purge worker
| NULL | 0.000 |
| 2 | system user | | NULL | Daemon | NULL | InnoDB purge worker
| NULL | 0.000 |
| 5 | system user | | NULL | Daemon | NULL | InnoDB shutdown
handler | NULL | 0.000 |
| 11 | root | localhost | hellodb | Query | 0 | Init
| show processlist | 0.000 |
| 13 | root | localhost | hellodb | Sleep | 38 |
| NULL | 0.000 |
+----+-------------+-----------+---------+---------+------+---------------------
-----+------------------+----------+
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 | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 50 |
+--------------------------+-------+
1 row in set (0.001 sec)
事务隔离级别
面试重点。
MySQL 支持四种隔离级别,事务隔离级别:从上至下更加严格
- READ UNCOMMITTED
可读取到未提交数据,产生脏读
- READ COMMITTED
可读取到提交数据,但未提交数据不可读,产生不可重复读,即可读取到多个提交数据,导致每次读取数据不一致
- REPEATABLE READ
可重复读,多次读取数据都一致,产生幻读,即读取过程中,即使有其它提交的事务修改数据,仍只能读取到未修改前的旧数据。此为MySQL默认设置
- SERIALIZABLE
可串行化,未提交的读事务阻塞修改事务(加读锁,但不阻塞读事务),或者未提交的修改事务阻塞读事务(加写锁,其它事务的读,写都不可以执行)。会导致并发性能差。
MVCC和事务的隔离级别:
MVCC(多版本并发控制机制)只在REPEATABLE READ和READ COMMITTED两个隔离级别下工作。其他两个隔离级别都和MVCC不兼容,因为READ UNCOMMITTED总是读取最新的数据行,而不是符合当前事务版本的数据行。而SERIALIZABLE则会对所有读取的行都加锁。
指定事务隔离级别:
服务器变量tx_isolation指定,默认为REPEATABLE-READ,可在GLOBAL和SESSION级进行设置
sqlSET tx_isolation='READ-UNCOMMITTED|READ-COMMITTED|REPEATABLE-READ|SERIALIZABLE'
服务器选项中指定
bashvim /etc/my.cnf [mysqld] transaction-isolation=SERIALIZABLE
死锁:
两个或多个事务在同一资源相互占用,并请求锁定对方占用的资源的状态。
死锁问题,数据库会自动解决。
日志管理
MySQL 支持丰富的日志类型,如下:
事务日志:transaction log
事务日志的写入类型为“追加”,因此其操作为“顺序IO”;通常也被称为:预写式日志 write ahead logging
事务日志文件: ib_logfile0, ib_logfile1
错误日志 error log
通用日志 general log
慢查询日志 slow query log
二进制日志 binary log
中继日志 reley log,在主从复制架构中,从服务器用于保存从主服务器的二进制日志中读取的事
事务日志
事务日志:transaction log
事务型存储引擎自行管理和使用,建议和数据文件分开存放,redo log和undo log
Innodb事务日志相关配置:
show variables like '%innodb_log%';
MariaDB [hellodb]> show variables like '%innodb_log%';
+-----------------------------+-----------+
| Variable_name | Value |
+-----------------------------+-----------+
| innodb_log_buffer_size | 16777216 |
| innodb_log_checksums | ON |
| innodb_log_compressed_pages | ON |
| innodb_log_file_size | 100663296 |
| innodb_log_files_in_group | 1 |
| innodb_log_group_home_dir | ./ |
| innodb_log_optimize_ddl | OFF |
| innodb_log_write_ahead_size | 8192 |
+-----------------------------+-----------+
8 rows in set (0.001 sec)
说明:
innodb_log_file_size 50331648 #每个日志文件大小 #50M
innodb_log_files_in_group 2 #日志组成员个数
innodb_log_group_home_dir ./ #事务文件路径
innodb_flush_log_at_trx_commit #默认为1(尤其这个值)
配置文件里修改事务日志选项:(修改成功)
[root@test ~]# mkdir -p /data/trans_log
[root@test ~]# chown mysql.mysql /data/trans_log/
# vim /etc/my.cnf.d/server.cnf
[mysqld]
……
innodb_log_group_home_dir=/data/trans_log
innodb_log_files_in_group=3
innodb_log_file_size=200M
[root@test ~]# systemctl restart mariadb
事务日志性能优化:
innodb_flush_log_at_trx_commit=0|1|2
1 此为默认值,日志缓冲区将写入日志文件,并在每次事务后执行刷新到磁盘。 这是完全遵守ACID特性
0 提交时没有写磁盘的操作; 而是每秒执行一次将日志缓冲区的提交的事务写入刷新到磁盘。 这样可提供更好的性能,但服务器崩溃可能丢失最后一秒的事务
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 后废弃)
错误日志
错误日志
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...
范例:
MariaDB [hellodb]> SHOW GLOBAL VARIABLES LIKE 'log_warnings';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_warnings | 2 |
+---------------+-------+
1 row in set (0.001 sec)
通用日志
通用日志:记录对数据库的通用操作,包括:错误的SQL语句
通用日志可以保存在:file(默认值)或 table(mysql.general_log表)
通用日志相关设置
general_log=ON|OFF
general_log_file=HOSTNAME.log
log_output=TABLE|FILE|NONE
范例:
#修改通用日志,记录通用日志至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)
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)
范例:对访问的语句进行排序
[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
慢查询日志
慢查询日志:记录执行查询时长超出指定时长的操作
慢查询相关变量
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 版后已删除
范例:模拟慢查询情况
这个事务得30-40s:
范例:模拟慢查询情况
1s查询1行。
范例:未使用索引,慢查询记录
log_queries_not_using_indexes=ON #不使用索引或使用全索引扫描,不论是否达到慢查询阀值的语句是否记录日志,默认OFF,即不记录
创建索引:
再次查询:
可以看到,本次未触发慢日志功能:
慢查询分析工具
mysqldumpslow -s c -t 10 /data/mysql/slow.log
使用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 | Duration |
+------------------------+----------+
| Starting | 0.000157 |
| Checking permissions | 0.000009 |
| Opening tables | 0.000025 |
| After opening tables | 0.000005 |
| System lock | 0.000004 |
| Table lock | 0.000006 |
| Init | 0.000017 |
| Optimizing | 0.000009 |
| Statistics | 0.000018 |
| Preparing | 0.000028 |
| Executing | 0.000003 |
| Sending data | 0.000070 |
| User sleep | 1.001128 |
| User sleep | 1.000313 |
| User sleep | 1.000834 |
| User sleep | 1.000348 |
| End of update loop | 0.000032 |
| Query end | 0.000003 |
| Commit | 0.000014 |
| Closing tables | 0.000004 |
| Unlocking tables | 0.000003 |
| Closing tables | 0.000012 |
| Starting cleanup | 0.000003 |
| Freeing items | 0.000056 |
| Updating status | 0.000024 |
| Logging slow query | 0.000069 |
| 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 | Duration | CPU_user | CPU_system |
+------------------------+----------+----------+------------+
| 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 |
| System lock | 0.000004 | 0.000002 | 0.000002 |
| Table lock | 0.000006 | 0.000004 | 0.000002 |
| Init | 0.000017 | 0.000010 | 0.000007 |
| Optimizing | 0.000009 | 0.000005 | 0.000004 |
| Statistics | 0.000018 | 0.000010 | 0.000007 |
| Preparing | 0.000028 | 0.000016 | 0.000012 |
| Executing | 0.000003 | 0.000002 | 0.000002 |
| Sending data | 0.000070 | 0.000059 | 0.000000 |
| User sleep | 1.001128 | 0.000665 | 0.000000 |
| User sleep | 1.000313 | 0.000716 | 0.000000 |
| User sleep | 1.000834 | 0.000379 | 0.000100 |
| User sleep | 1.000348 | 0.000319 | 0.000231 |
| End of update loop | 0.000032 | 0.000017 | 0.000012 |
| Query end | 0.000003 | 0.000002 | 0.000002 |
| Commit | 0.000014 | 0.000008 | 0.000005 |
| Closing tables | 0.000004 | 0.000002 | 0.000002 |
| Unlocking tables | 0.000003 | 0.000002 | 0.000001 |
| Closing tables | 0.000012 | 0.000007 | 0.000005 |
| Starting cleanup | 0.000003 | 0.000001 | 0.000001 |
| Freeing items | 0.000056 | 0.000034 | 0.000024 |
| Updating status | 0.000024 | 0.000013 | 0.000010 |
| Logging slow query | 0.000069 | 0.000040 | 0.000029 |
| Reset for next command | 0.000004 | 0.000002 | 0.000001 |
+------------------------+----------+----------+------------+
27 rows in set (0.000 sec)
MariaDB [hellodb]>
二进制日志(备份)(很重要)
**二进制日志默认不启用的;**😉
在工作中肯定是要启用二进制日志的。(增删改操作都会记录到)
- 记录导致数据改变或潜在导致数据改变的SQL语句
- 记录已提交的日志
- 不依赖于存储引擎类型
功能:通过“重放”日志文件中的事件来生成数据副本
注意:建议二进制日志和数据文件分开存放
二进制日志记录三种格式
- 基于“语句”记录:statement,记录语句,默认模式( MariaDB 10.2.3 版本以下 ),日志量较少
- 基于“行”记录:row,记录数据,日志量较大,更加安全,建议使用的格式
- 混合模式: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.文件名后缀,二进制格式,如: mariadb-bin.000001
2.索引文件:mysql|mariadb-bin.index,文本格式
二进制日志相关的服务器变量:
sql_log_bin=ON|OFF:#是否记录二进制日志,默认ON,支持动态修改,系统变量,而非服务器选项(是一个sesson变量)
log_bin=/PATH/BIN_LOG_FILE:#指定文件位置;默认OFF,表示不启用二进制日志功能,上述两项都开启才可以
binlog_format=STATEMENT|ROW|MIXED:#二进制日志记录的格式,默认STATEMENT
max_binlog_size=1073741824:#单个二进制日志文件的最大体积,到达最大值会自动滚动,默认为1G
#说明:文件达到上限时的大小未必为指定的精确值
#事务日志:默认是2个
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
案例:
mysqlbinlog /backup/newlogbin/mysql-bin.000002 ##默认查看所有内容
清除指定二进制日志
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 #
刷新二进制日志文件的方法:
方法1:重启服务,可以生成一个新的二进制日志文件
方法2:切换日志文件:
FLUSH LOGS;
方法3:
mysqladmin flush-logs
5、备份和恢复
5.1 备份恢复概述
5.1.1 为什么要备份
灾难恢复:硬件故障、软件故障、自然灾害、黑客攻击、误操作测试等数据丢失场景。
5.1.2 备份类型
完全备份,部分备份
完全备份:整个数据集
部分备份:只备份数据子集,如部分库或表
- 完全备份、增量备份、差异备份
增量备份:仅备份最近一次完全备份或增量备份(如果存在增量)以来变化的数据,备份较快,还原复杂。
差异备份:仅备份最近一次完全备份以来变化的数据,备份较慢,还原简单
注意:二进制日志文件不应该与数据文件放在同一磁盘。
- 冷、温、热备份
冷备:读、写操作均不可进行,数据库停止服务 (适合传统业务)
温备:读操作可执行;但写操作不可执行
热备:读、写操作均可执行
MyISAM:温备,不支持热备
InnoDB:都支持
事务具有隔离性。(可重复读)
- 物理和逻辑备份
物理备份:直接复制数据文件进行备份,与存储引擎有关,占用较多的空间,速度快
逻辑备份:从数据库中“导出”数据另存而进行的备份,与存储引擎无关,占用空间少,速度慢,可能丢失精度
5.1.3 备份什么
- 数据
- 二进制日志、InnoDB的事务日志
- 用户帐号,权限设置,程序代码(存储过程、函数、触发器、事件调度器)
- 服务器的配置文件
这2个数据库是没必要备份的:(用来描述数据库状态的)
information_schema
performance_schema
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.6 基于 LVM 的快照备份
前提:你的数据库要存放在lvm里。
(1) 请求锁定所有表
mysql> FLUSH TABLES WITH READ LOCK; (这里不要关窗口哦)
(2) 记录二进制日志文件及事件位置
mysql> FLUSH LOGS;
mysql> SHOW MASTER STATUS;
mysql -e 'SHOW MASTER STATUS' > /PATH/TO/SOMEFILE
(3) 创建快照
lvcreate -L # -s -p r -n NAME /DEV/VG_NAME/LV_NAME
(4) 释放锁
mysql> UNLOCK TABLES;
(5) 挂载快照卷,执行数据备份
(6) 备份完成后,删除快照卷
(7) 制定好策略,通过原卷备份二进制日志
5.1.7 实战案例:数据库冷备份和还原😉
老师课件文档:
#在目标服务器(10.0.0.18)安装mariadb-server,不启动服务
[root@centos8 ~]#dnf install mariadb-server
#在源主机(10.0.0.8)执行
[root@centos8 ~]# systemctl stop mariadb
#复制相关文件
[root@centos8 ~]# scp /etc/my.cnf.d/mariadb-server.cnf 10.0.0.18:/etc/my.cnf.d/
[root@centos8 ~]# scp -r /var/lib/mysql/* 10.0.0.18:/var/lib/mysql/
[root@centos8 ~]# scp -r /data/logbin/ 10.0.0.18:/data/ #10.0.0.18事先存在/data/目录
#保留属性:可以用rsync
[root@centos8 ~]#rsync -av /var/lib/mysql/ 10.0.0.18:/var/lib/mysql/
#在目标主机(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
2024年9月21日测试成功
10.3.17-MariaDB MariaDB Server
centos8
自己测试过程:
1.当前mysql机器
10.3.17-MariaDB MariaDB Server
centos8
192.168.1.81
当前自己mysql机器:
安装mysql
dnf install mariadb-server -y
systemctl enable --now mariadb
mysql
导入测试数据
当前是有一些数据的
我们导入一下正在使用的测试sql:
mysql -uroot -p123456 < hellodb_innodb.sql
[root@centos8 ~]# ll /var/lib/mysql/
total 122912
-rw-rw----. 1 mysql mysql 16384 Sep 21 17:14 aria_log.00000001
-rw-rw----. 1 mysql mysql 52 Sep 21 17:14 aria_log_control
drwx------. 2 mysql mysql 272 Sep 21 17:06 hellodb
-rw-rw----. 1 mysql mysql 1318 Sep 21 17:14 ib_buffer_pool
-rw-rw----. 1 mysql mysql 12582912 Sep 21 17:14 ibdata1
-rw-rw----. 1 mysql mysql 50331648 Sep 21 17:21 ib_logfile0
-rw-rw----. 1 mysql mysql 50331648 Sep 21 16:46 ib_logfile1
-rw-rw----. 1 mysql mysql 12582912 Sep 21 17:21 ibtmp1
-rw-rw----. 1 mysql mysql 0 Sep 21 16:46 multi-master.info
drwx------. 2 mysql mysql 4096 Sep 21 16:46 mysql
srwxrwxrwx. 1 mysql mysql 0 Sep 21 17:21 mysql.sock
-rw-rw----. 1 mysql mysql 16 Sep 21 16:46 mysql_upgrade_info
drwx------. 2 mysql mysql 20 Sep 21 16:46 performance_schema
启用下二进制日志
mkdir -p /data/logbin/mysql-bin
chown mysql.mysql /data/logbin/
vim /etc/my.cnf.d/mariadb-server.cnf
log-bin=/data/logbin/mysql-bin
重启mysql服务:
systemctl restart mariadb
- 此时,出现了二进制日志文件了
[root@centos8 ~]# ll /data/logbin/
total 8
-rw-rw----. 1 mysql mysql 328 Sep 21 17:21 mysql-bin.000001
-rw-rw----. 1 mysql mysql 30 Sep 21 17:21 mysql-bin.index
2.准备一台备份机器
安装好mysql软件,但是不启动mysql服务,版本要和生产的机器版本保持一致。
10.3.17-MariaDB MariaDB Server
centos8
192.168.1.82
dnf install mariadb-server -y
刚装好数据库后,其数据库目录是空的:(现在也不需要把他启动起来)
[root@mysql_backup ~]# ll /var/lib/mysql/
total 0
[root@mysql_backup ~]#
- 创建个备份目录
mkdir /backup
3.开始冷备份
- 停止数据库服务:
systemctl stop mariadb
- 先把一些核心文件拷贝到远程机器
rsync -av /var/lib/mysql 192.168.1.82:/backup #复制数据库:
rsync -av /data/logbin 192.168.1.82:/backup #复制二进制文件:
rsync -av /etc/my.cnf.d/mariadb-server.cnf 192.168.1.82:/backup #复制数据库配置文件:
到备份机器验证:
[root@mysql_backup ~]# ll /backup/
total 4
drwxr-xr-x. 2 mysql mysql 76 Sep 21 21:47 logbin
-rw-r--r--. 1 root root 1489 Sep 21 17:12 mariadb-server.cnf
drwxr-xr-x. 5 mysql mysql 235 Sep 21 21:47 mysql
- 启动原生产服务器数据库服务
[root@mysql ~]# systemctl start mariadb
mysql -uroot -p123456 hellodb
- 这里做一些测试数据操作
mysql -uroot -p123456 hellodb
create database db1;
show databases;
#对数据再做一些修改吧
#对teachers表添加2行数据:
insert teachers (name,age,gender)values('mage',30,'M');
insert teachers (name,age,gender)values('wang',33,'M');
exit
- 现在模拟数据库的奔溃
#删库了
[root@mysql ~]# rm -rf /var/lib/mysql/*
[root@mysql ~]# mysql -uroot -p
Enter password:
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)
[root@mysql ~]#
4.模拟还原数据库
还原数据库
拿数据库的备份来还原:
把之前备份好的数据拷贝到它应该在的地方:
[root@mysql_backup ~]# ls /backup/
logbin mariadb-server.cnf mysql
开始拷贝:
[root@mysql_backup ~]# cp -av /backup/mysql/* /var/lib/mysql/
[root@mysql_backup ~]# cp /backup/mariadb-server.cnf /etc/my.cnf.d/
cp: overwrite '/etc/my.cnf.d/mariadb-server.cnf'? y
[root@mysql_backup ~]# cp -av /backup/logbin /data/ #注意,备份机器上必须已经存在/data目录哦
- 目前所有数据都齐全了
- 启动数据库服务
[root@mysql_backup ~]# systemctl start mariadb
[root@mysql_backup ~]# mysql -uroot -p123456
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 9
Server version: 10.3.17-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)]> show databases;
+--------------------+
| Database |
+--------------------+
| hellodb |
| information_schema |
| mysql |
| performance_schema |
+--------------------+
4 rows in set (0.000 sec)
MariaDB [(none)]> select *from hellodb.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.001 sec)
复合预期。
还原到了我们备份的那个状态。
但是我们不甘心:。。。
现在的数据不是最新的。。。
该怎么办??
期望能还原到数据库最新的状态?
回退到删库前的状态。
利用二进制日志。😎
利用二进制日志进行数据库的还原
- 数据库服务一启动,就会生成新的二进制文件:
002文件是自己数据库服务启动后生成的文件:(冷被后--到删库前的一些操作-重要)
备份机器:
002文件是自己数据库服务启动后生成的文件:
现在的情况是:
数据库服务器数据库所在磁盘坏了,但是二进制日志文件所在磁盘是ok的:
那么我们就可以把这个002文件给拷贝出来。
[root@mysql ~]# rsync -av /data/logbin/ 192.168.1.82:/backup/newlogbin
现在的重点就是如何处理二进制日志文件mysql-bin.000002
里面的东西?
利用它里面的数据进行还原的。
查看二进制日志文件mysql-bin.000002
内容:
mysqlbinlog /backup/newlogbin/mysql-bin.000002 #####默认查看所有内容
- 导出文件
mysqlbinlog /backup/newlogbin/mysql-bin.000002 > logbin.sql
- 将导出的这个sql文件导入数据库即可
我们来临时关闭下二进制日志文件的记录:(没必要记录数据库恢复过程的二进制日志)
mysql -uroot -p123456
show variables like 'sql_log_bin';
set sql_log_bin=0;
show variables like 'sql_log_bin';
#####此时一定不要退出来,然后进行导入,否则就白设置了哈哈
system ls /root
source /root/logbin.sql
- 打开二进制日志功能
MariaDB [hellodb]> set sql_log_bin=1;
Query OK, 0 rows affected (0.000 sec)
5.验证
- 验证下
show databases;
select * from teachers;
完美。😉(大功告成)
注意
- 备份的重要性
- 推荐使用rsync;(拷贝过来的权限是对的)
- 备份测试;(写一个备份还原测试脚本)
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 常见通用选项📢
-A, --all-databases #备份所有数据库,含create database
-B, --databases db_name… #指定备份的数据库,包括create database语句
-E, --events:#备份相关的所有event scheduler
-R, --routines:#备份所有存储过程和自定义函数
--triggers:#备份表相关触发器,默认启用,用--skip-triggers,不备份触发器
--default-character-set=utf8 #指定字符集,默认用utf-8
--master-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 一起使用实现,此时只刷新一次二进制日志。
--single-transaction 常用的必备选项,针对innodb的
--compact #去掉注释,适合调试,生产不使用
-d, --no-data #只备份表结构,不备份数据
-t, --no-create-info #只备份数据,不备份表结构,即create table
-n,--no-create-db #不备份create database,可被-A或-B覆盖
--flush-privileges #备份mysql或相关时需要使用
-f, --force #忽略SQL错误,继续执行
--hex-blob #使用十六进制符号转储二进制列,当有包括BINARY, VARBINARY,BLOB,BIT的数据类型的列时使用,避免乱码
-q, --quick #不缓存查询,直接输出,加快备份速度
常用备份命令:(推荐)
#压缩
mysqldump -A -F --single-transaction --master-data=1|gzip > /data/all-`date +%F`.sql.gz
#不压缩
mysqldump -A -F --single-transaction --master-data=1 > /data/all-`date +%F`.sql
-R选项
- 创建一个存储过程
[root@mysql ~]# mysql hellodb < testlog.sql
[root@mysql ~]# mysql hellodb
MariaDB [hellodb]> help show
MariaDB [hellodb]> SHOW PROCEDURE STATUS;
- 发现,是没有备份相关存储过程的
[root@mysql ~]# mysqldump -B hellodb > /backup/hellodb_B.sql
[root@mysql ~]# grep pro_testlog /backup/hellodb_B.sql
- 带上-R选项,再次备份,并验证
[root@mysql ~]# mysqldump -R -B hellodb > /backup/hellodb_R_B.sql
[root@mysql ~]# grep pro_testlog /backup/hellodb_R_B.sql
/*!50003 DROP PROCEDURE IF EXISTS `pro_testlog` */;
CREATE DEFINER=`root`@`localhost` PROCEDURE `pro_testlog`()
可以看到,此时备份的sql里是有相关存储过程的。
mysql数据库里面有没有存储过程呢?
是有的,因为存储过程本身就是默认存储在mysql数据库的。
[root@mysql ~]# mysqldump -B mysql > /backup/mysql.sql
[root@mysql ~]# grep pro_testlog /backup/mysql.sql
INSERT INTO `proc` VALUES ('mysql','AddGeometryColumn','PROCEDURE','AddGeometryColumn','SQL','CONTAINS_SQL','NO','INVOKER','catalog varchar(64), t_schema varchar(64),\n t_name varchar(64), geometry_column varchar(64), t_srid int','','begin\n set @qwe= concat(\'ALTER TABLE \', t_schema, \'.\', t_name, \' ADD \', geometry_column,\' GEOMETRY REF_SYSTEM_ID=\', t_srid); PREPARE ls from @qwe; execute ls; deallocate prepare ls; end','root@localhost','2024-09-21 15:23:35','2024-09-21 15:23:35','','','utf8','utf8_general_ci','latin1_swedish_ci','begin\n set @qwe= concat(\'ALTER TABLE \', t_schema, \'.\', t_name, \' ADD \', geometry_column,\' GEOMETRY REF_SYSTEM_ID=\', t_srid); PREPARE ls from @qwe; execute ls; deallocate prepare ls; end','NONE'),('mysql','DropGeometryColumn','PROCEDURE','DropGeometryColumn','SQL','CONTAINS_SQL','NO','INVOKER','catalog varchar(64), t_schema varchar(64),\n t_name varchar(64), geometry_column varchar(64)','','begin\n set @qwe= concat(\'ALTER TABLE \', t_schema, \'.\', t_name, \' DROP \', geometry_column); PREPARE ls from @qwe; execute ls; deallocate prepare ls; end','root@localhost','2024-09-21 15:23:35','2024-09-21 15:23:35','','','utf8','utf8_general_ci','latin1_swedish_ci','begin\n set @qwe= concat(\'ALTER TABLE \', t_schema, \'.\', t_name, \' DROP \', geometry_column); PREPARE ls from @qwe; execute ls; deallocate prepare ls; end','NONE'),('hellodb','pro_testlog','PROCEDURE','pro_testlog','SQL','CONTAINS_SQL','NO','DEFINER','','','begin \ndeclare i int;\nset i = 1; \nwhile i < 100000 \ndo insert into testlog(name,age) values (concat(\'wang\',i),i); \nset i = i +1; \nend while; \nend','root@localhost','2024-09-21 18:42:55','2024-09-21 18:42:55','STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION','','utf8','utf8_general_ci','utf8_general_ci','begin \ndeclare i int;\nset i = 1; \nwhile i < 100000 \ndo insert into testlog(name,age) values (concat(\'wang\',i),i); \nset i = i +1; \nend while; \nend','NONE');
[root@mysql ~]#
所以,即使你以后忘记加-R了,只要你把mysql数据库备份好了,那么相关的存储过程也算是备份下来了。
default-character-set选项
utf-8兼容latin1
[root@mysql ~]# mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 62
Server version: 10.3.17-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)]> show create database hellodb;
+----------+------------------------------------------------------------------+
| Database | Create Database |
+----------+------------------------------------------------------------------+
| hellodb | CREATE DATABASE `hellodb` /*!40100 DEFAULT CHARACTER SET utf8 */ |
+----------+------------------------------------------------------------------+
1 row in set (0.000 sec)
MariaDB [(none)]> show create database hellodb2;
+----------+---------------------------------------------------------------------+
| Database | Create Database |
+----------+---------------------------------------------------------------------+
| hellodb2 | CREATE DATABASE `hellodb2` /*!40100 DEFAULT CHARACTER SET latin1 */ |
+----------+---------------------------------------------------------------------+
1 row in set (0.000 sec)
MariaDB [(none)]> show create database mysql;
+----------+------------------------------------------------------------------+
| Database | Create Database |
+----------+------------------------------------------------------------------+
| mysql | CREATE DATABASE `mysql` /*!40100 DEFAULT CHARACTER SET latin1 */ |
+----------+------------------------------------------------------------------+
1 row in set (0.000 sec)
MariaDB [(none)]>
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 | utf8 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mariadb/charsets/ |
+--------------------------+------------------------------+
8 rows in set (0.001 sec)
MariaDB [(none)]>
##目前推荐
utf-8mb4
--master-data选项
- 测试--master-data选项
MariaDB [(none)]> select @@sql_log_bin;
+---------------+
| @@sql_log_bin |
+---------------+
| 1 |
+---------------+
1 row in set (0.000 sec)
MariaDB [(none)]> show master logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 1308 |
| mysql-bin.000002 | 950 |
| mysql-bin.000003 | 28208 |
| mysql-bin.000004 | 523073 |
+------------------+-----------+
4 rows in set (0.000 sec)
MariaDB [(none)]>
[root@mysql ~]# mysqldump -A --master-data=2 > /backup/all_2.sql
[root@mysql ~]# vim /backup/all_2.sql
如果继续修改数据库:
MariaDB [(none)]> create database db2;
Query OK, 1 row affected (0.000 sec)
MariaDB [(none)]> show master logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 1308 |
| mysql-bin.000002 | 950 |
| mysql-bin.000003 | 28208 |
| mysql-bin.000004 | 523200 |
+------------------+-----------+
4 rows in set (0.000 sec)
MariaDB [(none)]>
再次对数据库做下修改。
不小心把表给误删除了:
[root@mysql ~]# mysql hellodb
MariaDB [hellodb]> drop table students;
Query OK, 0 rows affected (0.003 sec)
MariaDB [hellodb]>
又增加了一条新记录:
MariaDB [hellodb]> insert teachers (name,age,gender)values('a',20,'M');
Query OK, 1 row affected (0.001 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 | 93 | F |
| 5 | a | 20 | M |
+-----+---------------+-----+--------+
5 rows in set (0.000 sec)
当前的环境:
看下当前最新备份的文件:
[root@mysql ~]# ll /backup/ -t
total 2108
-rw-r--r--. 1 root root 498187 Sep 22 03:08 all_2.sql
-rw-r--r--. 1 root root 484275 Sep 22 02:52 mysql.sql
-rw-r--r--. 1 root root 7864 Sep 22 02:51 hellodb2_R_B.sql
-rw-r--r--. 1 root root 9532 Sep 22 02:49 hellodb_R_B.sql
-rw-r--r--. 1 root root 8418 Sep 22 02:46 hellodb_B.sql
-rw-r--r--. 1 root root 138245 Sep 22 02:35 all.sql.gz
-rw-r--r--. 1 root root 496386 Sep 22 02:34 all.sql
-rw-r--r--. 1 root root 483318 Sep 22 01:53 mysql_2024-09-22.sql
-rw-r--r--. 1 root root 7813 Sep 22 01:53 hellodb2_2024-09-22.sql
-rw-r--r--. 1 root root 7807 Sep 22 01:53 hellodb_2024-09-22.sql
[root@mysql ~]#
开始恢复故障:
查看备份文件
从这个点往后的都是备份后新增的数据:
导出备份后改变的所有sql操作
[root@mysql ~]# ll /data/logbin/
total 552
-rw-rw----. 1 mysql mysql 1308 Sep 21 21:47 mysql-bin.000001
-rw-rw----. 1 mysql mysql 950 Sep 21 23:22 mysql-bin.000002
-rw-rw----. 1 mysql mysql 28208 Sep 21 23:23 mysql-bin.000003
-rw-rw----. 1 mysql mysql 523585 Sep 22 09:35 mysql-bin.000004
-rw-rw----. 1 mysql mysql 120 Sep 21 23:23 mysql-bin.index
[root@mysql ~]# mysqlbinlog /data/logbin/mysql-bin.000004 --start-position=523073 > /backup/inc.sql
[root@mysql ~]# vim /backup/inc.sql
[root@mysql ~]# sed -n '/^DROP TABLE/p' /backup/inc.sql
DROP TABLE `students` /* generated by server */
#删除
[root@mysql ~]# sed -i.bak '/^DROP TABLE/d' /backup/inc.sql
[root@mysql ~]# ll /backup/inc.sql
-rw-r--r--. 1 root root 2909 Sep 22 17:17 /backup/inc.sql
[root@mysql ~]# ll /backup/inc.sql.bak
-rw-r--r--. 1 root root 2957 Sep 22 17:12 /backup/inc.sql.bak
[root@mysql ~]# ll /backup/ -t
total 2116
-rw-r--r--. 1 root root 2909 Sep 22 17:17 inc.sql
-rw-r--r--. 1 root root 2957 Sep 22 17:12 inc.sql.bak
-rw-r--r--. 1 root root 498187 Sep 22 03:08 all_2.sql
恢复数据库
- 关闭二进制日志
MariaDB [(none)]> set @@sql_log_bin=0;
Query OK, 0 rows affected (0.000 sec)
MariaDB [(none)]> select @@sql_log_bin;
+---------------+
| @@sql_log_bin |
+---------------+
| 0 |
+---------------+
1 row in set (0.000 sec)
- 覆盖还原数据库
MariaDB [(none)]> source /backup/all_2.sql
MariaDB [(none)]> source /backup/inc.sql
- 打开二进制日志功能
验证
MariaDB [hellodb]> show databases;
+--------------------+
| Database |
+--------------------+
| db2 |
| hellodb |
| hellodb2 |
| information_schema |
| mysql |
| performance_schema |
+--------------------+
6 rows in set (0.000 sec)
MariaDB [hellodb]> select *from students;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
| 11 | Yuan Chengzhi | 23 | M | 6 | NULL |
| 12 | Wen Qingqing | 19 | F | 1 | NULL |
| 13 | Tian Boguang | 33 | M | 2 | NULL |
| 14 | Lu Wushuang | 17 | F | 3 | NULL |
| 15 | Duan Yu | 19 | M | 4 | NULL |
| 16 | Xu Zhu | 21 | M | 1 | NULL |
| 17 | Lin Chong | 25 | M | 4 | NULL |
| 18 | Hua Rong | 23 | M | 7 | NULL |
| 19 | Xue Baochai | 18 | F | 6 | NULL |
| 20 | Diao Chan | 19 | F | 7 | NULL |
| 21 | Huang Yueying | 22 | F | 6 | NULL |
| 22 | Xiao Qiao | 20 | F | 1 | NULL |
| 23 | Ma Chao | 23 | M | 4 | NULL |
| 24 | Xu Xian | 27 | M | NULL | NULL |
| 25 | Sun Dasheng | 100 | M | NULL | NULL |
+-------+---------------+-----+--------+---------+-----------+
25 rows in set (0.000 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 | 93 | F |
| 5 | a | 20 | M |
+-----+---------------+-----+--------+
5 rows in set (0.000 sec)
MariaDB [hellodb]>
搞定。
存在的问题:
一个库里2张表的时间可能不一致,会存在问题:😒(数据不一致问题)
理论上可以恢复,但是实际上可能存在问题;
因为只能还原到删表之前的状态:(后面的数据就是丢了,丢了的部分手工完成。)
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结合一起使用
案例:第1种方式
mysqldump [OPTIONS] database [tables] #支持指定数据库和指定多表的备份,但数据库本身定义不备份
mysqldump -uroot -p'' hellodb students
过滤下:
mysqldump -uroot -p'' hellodb students|grep -v '^\/\*'|grep -v '^--'
备份:
mysqldump -uroot -p'' hellodb students > students.sql
那么生产的这个文件就可以用来还原了。
- 模拟误操作hellodb.studnets表
mysql hellodb
select *from students;
MariaDB [hellodb]> update students set classid=1;
Query OK, 21 rows affected (0.003 sec)
Rows matched: 25 Changed: 21 Warnings: 0
select *from students;
- 一旦发现数据库故障后,立刻停止让别人访问数据库,但是自己可以访问到。待故障解决后,再让数据库提供服务。
show variables like 'skip_networking';
这个是个只读变量,只能写到数据库配置文件里,然后重启服务。
这个里如何配置,请看前面文档,此处忽略。
- 开始还原
#建议也是先停掉二级日志
mysql hellodb
MariaDB [hellodb]> set sql_log_bin=0;
Query OK, 0 rows affected (0.000 sec)
MariaDB [hellodb]> system ls /root
anaconda-ks.cfg Documents hellodb_innodb.sql ios Pictures students.sql testlog.sql
Desktop Downloads initial-setup-ks.cfg Music Public Templates Videos
MariaDB [hellodb]> source /root/students.sql
- 验证(符合预期😉)
MariaDB [hellodb]> select *from students;
+-------+---------------+-----+--------+---------+-----------+
| StuID | Name | Age | Gender | ClassID | TeacherID |
+-------+---------------+-----+--------+---------+-----------+
| 1 | Shi Zhongyu | 22 | M | 2 | 3 |
| 2 | Shi Potian | 22 | M | 1 | 7 |
| 3 | Xie Yanke | 53 | M | 2 | 16 |
| 4 | Ding Dian | 32 | M | 4 | 4 |
| 5 | Yu Yutong | 26 | M | 3 | 1 |
| 6 | Shi Qing | 46 | M | 5 | NULL |
| 7 | Xi Ren | 19 | F | 3 | NULL |
| 8 | Lin Daiyu | 17 | F | 7 | NULL |
| 9 | Ren Yingying | 20 | F | 6 | NULL |
| 10 | Yue Lingshan | 19 | F | 3 | NULL |
单表恢复有可能导致表和表之间的数据可能不一致了。。。
案例:第2种方式
mysqldump [OPTIONS] –B DB1 [DB2 DB3...] #支持指定数据库备份,包含数据库本身定义也会备份
- 查看当前数据库
[root@mysql ~]# mysql -e 'show databases'
+--------------------+
| Database |
+--------------------+
| hellodb |
| hellodb2 |
| information_schema |
| mysql |
| performance_schema |
+--------------------+
- 开始备份
mysqldump -B hellodb mysql > hellodb_mysql_B.sql
- 模拟删除数据库
mysql -e 'drop database hellodb'
- 还原数据库
mysql < hellodb_mysql_B.sql
- 验证
[root@mysql ~]# mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 41
Server version: 10.3.17-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)]> show databases;
+--------------------+
| Database |
+--------------------+
| hellodb |
| hellodb2 |
| information_schema |
| mysql |
| performance_schema |
+--------------------+
5 rows in set (0.000 sec)
MariaDB [(none)]> 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]> show tables;
+-------------------+
| Tables_in_hellodb |
+-------------------+
| classes |
| coc |
| courses |
| scores |
| students |
| teachers |
| toc |
+-------------------+
7 rows in set (0.000 sec)
可以看到,数据库被还原了,里也是有数据的。
案例:第3种方式(推荐)
[root@mysql ~]# mysql -e 'show databases'
+--------------------+
| Database |
+--------------------+
| hellodb |
| hellodb2 |
| information_schema |
| mysql |
| performance_schema |
+--------------------+
[root@mysql ~]# mysqldump -A > /backup/all.sql
[root@mysql ~]# mysqldump -A |gzip > /backup/all.sql.gz
[root@mysql ~]# ll /backup/all.sql*
-rw-r--r--. 1 root root 496386 Sep 22 02:34 /backup/all.sql
-rw-r--r--. 1 root root 138245 Sep 22 02:35 /backup/all.sql.gz
[root@mysql ~]# grep ^'CREATE DATABASE' /backup/all.sql
CREATE DATABASE /*!32312 IF NOT EXISTS*/ `hellodb` /*!40100 DEFAULT CHARACTER SET utf8 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/ `hellodb2` /*!40100 DEFAULT CHARACTER SET latin1 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysql` /*!40100 DEFAULT CHARACTER SET latin1 */;
mysqldump的MyISAM存储引擎相关的备份选项:
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 backup_hellodb.sh
#!/bin/bash
TIME=`date +%F_%H-%M-%S`
DIR=/backup
DB=hellodb
PASS=magedu
mysqldump -uroot -p "$PASS" -F –E –R --triggers --single-transaction --masterdata=2 --default-character-set=utf8 -q -B $DB | gzip >
${DIR}/${DB}_${TIME}.sql.gz
5.2.3.2 实战案例:分库备份并压缩
#案例1:grep+for循环
for db in `mysql -e 'show databases'|grep -Ev 'information_schema|performance_schema|Database'`;do mysqldump -B $db > /backup/${db}_`date +%F`.sql;done
#案例:2:grep+while read
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
#案例3:grep+sed
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
#案例4:纯sed
mysql -uroot -e 'show databases'|sed -rn '/^(Database|information_schema|performance_schema)$/!s#(.*)#mysqldump -B \1 | gzip > /backup/\1.sql.gz#p' |bash
案例1:grep+for循环
分库备份
以上是多个库备份在一起的。
那么如何分库备份呢?
mysqldump -B hellodb > hellodb_B.sql
mysqldump -B mysql > mysql_B.sql
备份命令:
#准备备份目录
mkdir /backup
#备份
for db in `mysql -e 'show databases'|grep -Ev 'information_schema|performance_schema|Database'`;do mysqldump -B $db > /backup/${db}_`date +%F`.sql;done
#验证
ll /backup/
注意:
mysql -e 'show databases'
mysql -e 'show databases'|grep -Ev 'information_schema|performance_schema|Database'
案例:2:grep+while read
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@mysql ~]# 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@mysql ~]# ll /backup/ -t
total 3228
-rw-r--r--. 1 root root 137111 Sep 23 06:51 mysql.sql.gz
-rw-r--r--. 1 root root 1900 Sep 23 06:51 hellodb2.sql.gz
-rw-r--r--. 1 root root 1971 Sep 23 06:51 hellodb.sql.gz
-rw-r--r--. 1 root root 519 Sep 23 06:51 db2.sql.gz
……
案例3:grep+sed
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@mysql ~]# 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@mysql ~]# ll /backup/ -t
total 3092
-rw-r--r--. 1 root root 137110 Sep 23 06:56 mysql.sql.gz
-rw-r--r--. 1 root root 1900 Sep 23 06:56 hellodb2.sql.gz
-rw-r--r--. 1 root root 1971 Sep 23 06:56 hellodb.sql.gz
-rw-r--r--. 1 root root 519 Sep 23 06:56 db2.sql.gz
……
说明:
这条命令的作用是备份 MySQL 数据库,并将备份文件压缩为 .sql.gz
格式。下面是每个部分的详细说明:
mysql -uroot -e 'show databases'
:- 使用
mysql
命令行客户端,以root
用户身份连接到 MySQL 数据库,并执行SHOW DATABASES
命令,列出所有数据库。
- 使用
| grep -Ev '^(Database|information_schema|performance_schema)$'
:- 将
mysql
命令的输出通过管道传递给grep
,过滤掉不需要的数据库:-E
选项允许使用扩展正则表达式。-v
选项表示反向匹配(即排除)。- 正则表达式
^(Database|information_schema|performance_schema)$
匹配数据库名称为Database
、information_schema
或performance_schema
的行,这些是默认的系统数据库,通常不需要备份。
- 将
| sed -rn 's#(.*)#mysqldump -B \1 | gzip > /backup/\1.sql.gz#p'
:- 将经过过滤的数据库列表传递给
sed
命令,进行格式化处理。 -r
选项启用扩展正则表达式,-n
选项使sed
只输出被处理的行。s#(.*)#mysqldump -B \1 | gzip > /backup/\1.sql.gz#p
:s#(.*)#...#
是替换命令,将匹配到的行替换为mysqldump
命令。\1
表示被匹配的数据库名称。- 最终输出的格式是
mysqldump -B 数据库名 | gzip > /backup/数据库名.sql.gz
。
- 将经过过滤的数据库列表传递给
| bash
:- 将构造好的命令传递给
bash
执行。 - 这样,实际的备份命令将被运行,创建数据库的备份并压缩存储到
/backup/
目录下。
- 将构造好的命令传递给
总结
整条命令的作用是:
- 连接到 MySQL,列出所有数据库。
- 排除掉系统数据库。
- 为每个剩余的数据库生成一个
mysqldump
命令,并通过gzip
压缩备份文件。 - 将备份文件保存到
/backup/
目录,文件名格式为数据库名.sql.gz
。
案例4:纯sed
mysql -uroot -e 'show databases'|sed -rn '/^(Database|information_schema|performance_schema)$/!s#(.*)#mysqldump -B \1 | gzip > /backup/\1.sql.gz#p' |bash
亲自测试:
[root@mysql ~]# mysql -uroot -e 'show databases'|sed -rn '/^(Database|information_schema|performance_schema)$/!s#(.*)#mysqldump -B \1 | gzip > /backup/\1.sql.gz#p' |bash
[root@mysql ~]# ll /backup/ -t
total 3092
-rw-r--r--. 1 root root 137111 Sep 23 06:58 mysql.sql.gz
-rw-r--r--. 1 root root 1900 Sep 23 06:58 hellodb2.sql.gz
-rw-r--r--. 1 root root 1971 Sep 23 06:58 hellodb.sql.gz
-rw-r--r--. 1 root root 519 Sep 23 06:58 db2.sql.gz
说明:
实战案例:分库备份的实战脚本😉
[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-characterset=utf8 -q -B $DB | gzip > ${DIR}/${DB}_${TIME}.sql.gz
done
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-characterset=utf8 -q -B $DB | gzip > ${DIR}/${DB}_${TIME}.sql.gz
done
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 --masterdata=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 --singletransaction --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 | 998 |
| mysql-bin.000002 | 28090 |
| mysql-bin.000003 | 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
[root@centos8 ~]#mysqlbinlog --start-position=389 /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 | 93 | F |
| 5 | wang | 30 | M |
| 6 | mage | 28 | M |
+-----+---------------+-----+--------+
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/mariadbbin.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: Perl 脚本
- xtrabackup: C/C++,编译的二进制程序
- xbcrypt: 加解密
- 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 487 Jun 12 15:07 backup-my.cnf
drwxr-x--- 2 root root 272 Jun 12 15:07 hellodb
-rw-r----- 1 root root 425 Jun 12 15:07 ib_buffer_pool
-rw-r----- 1 root root 12582912 Jun 12 15:07 ibdata1
drwxr-x--- 2 root root 4096 Jun 12 15:07 mysql
drwxr-x--- 2 root root 8192 Jun 12 15:07 performance_schema
drwxr-x--- 2 root root 8192 Jun 12 15:07 sys
-rw-r----- 1 root root 25 Jun 12 15:07 xtrabackup_binlog_info
-rw-r----- 1 root root 135 Jun 12 15:07 xtrabackup_checkpoints
-rw-r----- 1 root root 479 Jun 12 15:07 xtrabackup_info
-rw-r----- 1 root root 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安装
yum install percona-xtrabackup 在EPEL源中
最新版本下载安装:
https://www.percona.com/downloads/XtraBackup/LATEST/
dnf install -y percona-xtrabackup-24-2.4.20-1.el8.x86_64.rpm
[root@centos8 ~]# rpm -ql percona-xtrabackup-24
/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 ~]#
🍊 innobackupex工具和xtrabackup已经合二为一了:
[root@centos8 ~]# ll /usr/bin/innobackupex
lrwxrwxrwx. 1 root root 10 Apr 21 2020 /usr/bin/innobackupex -> xtrabackup
[root@centos8 ~]# ll /usr/bin/xtrabackup
-rwxr-xr-x. 1 root root 21303688 Apr 21 2020 /usr/bin/xtrabackup
5.3.3 xtrabackup用法
5.3.4 实战案例:利用xtrabackup实现完全备份及还原
2.4以后的是新版本,2.4以前的是老版本。
测试成功(2024年10月29日)
测试环境:
CentOS Linux release 8.1.1911 (Core)系统
mysql 5.7.29
xtrabackup-24-2.4.20
汇总
1 安装xtrabackup包
[root@centos8 ~]#yum -y install percona-xtrabackup-24-2.4.20-1.el8.x86_64.rpm
2 在原主机做完全备份到/backup
#/backup目录不需事先创建
[root@centos8 ~]#xtrabackup -uroot -pmagedu --backup --target-dir=/backup/
[root@centos8 ~]#scp -r /backup/* 目标主机:/backup
3 在目标主机上还原
1)预准备:确保数据一致,提交完成的事务,回滚未完成的事务
[root@centos8 ~]#xtrabackup --prepare --target-dir=/backup/
2)复制到数据库目录
注意:数据库目录必须为空,MySQL服务不能启动
[root@centos8 ~]#xtrabackup --copy-back --target-dir=/backup/
3)还原属性
[root@centos8 ~]#chown -R mysql:mysql /var/lib/mysql
4)启动服务
[root@centos8 ~]#service mysqld start
备份
- 本地数据库导入测试数据
[root@centos8 ~]# mysql -uroot -pmagedu < hellodb_innodb.sql
mysql: [Warning] Using a password on the command line interface can be insecure.
[root@centos8 ~]#
- 开始备份
[root@centos8 ~]# xtrabackup --backup --target-dir=/backup/
备份完成。
- 查看一些备份下来的文件内容。
[root@centos8 backup]# cat xtrabackup_info
uuid = 9515214f-7b9f-11ef-8d4a-000c29e77e43
name =
tool_name = xtrabackup
tool_command = --backup --target-dir=/backup/
tool_version = 2.4.20
ibbackup_version = 2.4.20
server_version = 5.7.29-log
start_time = 2024-09-26 08:37:58
end_time = 2024-09-26 08:38:00
lock_time = 1
binlog_pos = filename 'mysql-bin.000002', position '11019'
innodb_from_lsn = 0
innodb_to_lsn = 2682511
partial = N
incremental = N
format = file
compact = N
compressed = N
encrypted = N
[root@centos8 backup]# cat xtrabackup_checkpoints
backup_type = full-backuped
from_lsn = 0
to_lsn = 2682511
last_lsn = 2682520
compact = 0
recover_binlog_info = 0
flushed_lsn = 2682520
[root@centos8 backup]# cat xtrabackup_binlog_info
mysql-bin.000002 11019
[root@centos8 backup]# cat 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=897cf451-7b98-11ef-8a5e-000c29e77e43
master_key_id=0
[root@centos8 backup]# file xtrabackup_logfile
xtrabackup_logfile: data
另外,这个数据库配置文件我们得手动拷贝下:🚦
[root@centos8 backup]# cat /etc/my.cnf
[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
[root@centos8 backup]#
现在来对数据库做一下破坏:。。。
模拟数据库奔溃:。。。
把mysql数据给移动到opt目录:
[root@centos8 backup]# ls /opt/
[root@centos8 backup]# mv /data/mysql/* /opt
此时能看到当前mysql是启动失败的:
service mysqld status
虽然mysql的进程还在,但他的数据文件时已经不在了,服务也异常开了,我们来杀掉mysql的服务进程:
[root@centos8 ~]# ss -ntlp
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 0.0.0.0:111 0.0.0.0:* users:(("rpcbind",pid=981,fd=4),("systemd",pid=1,fd=42))
LISTEN 0 32 192.168.122.1:53 0.0.0.0:* users:(("dnsmasq",pid=2145,fd=6))
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1135,fd=5))
LISTEN 0 5 127.0.0.1:631 0.0.0.0:* users:(("cupsd",pid=1132,fd=10))
LISTEN 0 128 [::]:111 [::]:* users:(("rpcbind",pid=981,fd=6),("systemd",pid=1,fd=44))
LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=1135,fd=7))
LISTEN 0 5 [::1]:631 [::]:* users:(("cupsd",pid=1132,fd=9))
LISTEN 0 80 *:3306 *:* users:(("mysqld",pid=1910,fd=40))
[root@centos8 ~]# ps -aux|grep mysqld
root 1598 0.0 0.1 25380 3696 ? S 07:16 0:00 /bin/sh /usr/local/mysql/bin/mysqld_safe --datadir=/data/mysql --pid-file=/data/mysql/mysql.pid
mysql 1910 0.0 5.2 1418500 188036 ? Sl 07:16 0:00 /usr/local/mysql/bin/mysqld --basedir=/usr/local/mysql --datadir=/data/mysql --plugin-dir=/usr/local/mysql/lib/plugin --user=mysql --log-error=/data/mysql/mysql.log --pid-file=/data/mysql/mysql.pid --socket=/data/mysql/mysql.sock
root 2933 0.0 0.0 12108 972 pts/0 S+ 07:42 0:00 grep --color=auto mysqld
[root@centos8 ~]# killall mysqld
[root@centos8 ~]# ss -ntlp
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 0.0.0.0:111 0.0.0.0:* users:(("rpcbind",pid=981,fd=4),("systemd",pid=1,fd=42))
LISTEN 0 32 192.168.122.1:53 0.0.0.0:* users:(("dnsmasq",pid=2145,fd=6))
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1135,fd=5))
LISTEN 0 5 127.0.0.1:631 0.0.0.0:* users:(("cupsd",pid=1132,fd=10))
LISTEN 0 128 [::]:111 [::]:* users:(("rpcbind",pid=981,fd=6),("systemd",pid=1,fd=44))
LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=1135,fd=7))
LISTEN 0 5 [::1]:631 [::]:* users:(("cupsd",pid=1132,fd=9))
[root@centos8 ~]# ps -aux|grep mysqld
root 2946 0.0 0.0 12108 1084 pts/0 S+ 07:42 0:00 grep --color=auto mysqld
[root@centos8 ~]#
现在来开始还原下数据库:
- 必须清空里面的东西:
[root@centos8 ~]# ll /data/mysql
total 4
-rw-r-----. 1 mysql mysql 324 Oct 29 07:42 ib_buffer_pool
[root@centos8 ~]# rm -rf /data/mysql/*
- 我们来尝试手动起一下
[root@centos8 ~]# service mysqld start
Starting MySQL.Logging to '/data/mysql/mysql.log'.
... ERROR! The server quit without updating PID file (/data/mysql/mysql.pid).
[root@centos8 ~]# ll /data/mysql
total 110652
-rw-r-----. 1 mysql mysql 56 Oct 29 07:48 auto.cnf
-rw-------. 1 mysql mysql 1676 Oct 29 07:48 ca-key.pem
-rw-r--r--. 1 mysql mysql 1112 Oct 29 07:48 ca.pem
-rw-r-----. 1 mysql mysql 177 Oct 29 07:48 centos8-bin.000001
-rw-r-----. 1 mysql mysql 21 Oct 29 07:48 centos8-bin.index
-rw-r--r--. 1 mysql mysql 1112 Oct 29 07:48 client-cert.pem
-rw-------. 1 mysql mysql 1680 Oct 29 07:48 client-key.pem
-rw-r-----. 1 mysql mysql 215 Oct 29 07:48 ib_buffer_pool
-rw-r-----. 1 mysql mysql 12582912 Oct 29 07:48 ibdata1
-rw-r-----. 1 mysql mysql 50331648 Oct 29 07:48 ib_logfile0
-rw-r-----. 1 mysql mysql 50331648 Oct 29 07:48 ib_logfile1
-rw-r-----. 1 mysql mysql 9523 Oct 29 07:48 mysql.log
-rw-------. 1 mysql mysql 1680 Oct 29 07:48 private_key.pem
-rw-r--r--. 1 mysql mysql 452 Oct 29 07:48 public_key.pem
-rw-r--r--. 1 mysql mysql 1112 Oct 29 07:48 server-cert.pem
-rw-------. 1 mysql mysql 1680 Oct 29 07:48 server-key.pem
[root@centos8 ~]# rm -rf /data/mysql/*
[root@centos8 ~]# ss -ntlp
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 0.0.0.0:111 0.0.0.0:* users:(("rpcbind",pid=981,fd=4),("systemd",pid=1,fd=42))
LISTEN 0 32 192.168.122.1:53 0.0.0.0:* users:(("dnsmasq",pid=2145,fd=6))
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1135,fd=5))
LISTEN 0 5 127.0.0.1:631 0.0.0.0:* users:(("cupsd",pid=1132,fd=10))
LISTEN 0 128 [::]:111 [::]:* users:(("rpcbind",pid=981,fd=6),("systemd",pid=1,fd=44))
LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=1135,fd=7))
LISTEN 0 5 [::1]:631 [::]:* users:(("cupsd",pid=1132,fd=9))
[root@centos8 ~]# ps -aux|grep mysqld
root 3326 0.0 0.0 12108 1100 pts/0 S+ 07:51 0:00 grep --color=auto mysqld
[root@centos8 ~]#
手动起mysql是起不来了,同样我们再次删除下/data/mysql/
下文件。
还原
1)预准备:确保数据一致,提交完成的事务,回滚未完成的事务
[root@centos8 ~]#xtrabackup --prepare --target-dir=/backup/
2)复制到数据库目录 注意:数据库目录必须为空,MySQL服务不能启动
[root@centos8 backup]# ls /data/mysql
[root@centos8 backup]# ss -ntlp
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 0.0.0.0:111 0.0.0.0:* users:(("rpcbind",pid=981,fd=4),("systemd",pid=1,fd=42))
LISTEN 0 32 192.168.122.1:53 0.0.0.0:* users:(("dnsmasq",pid=2145,fd=6))
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1135,fd=5))
LISTEN 0 5 127.0.0.1:631 0.0.0.0:* users:(("cupsd",pid=1132,fd=10))
LISTEN 0 128 [::]:111 [::]:* users:(("rpcbind",pid=981,fd=6),("systemd",pid=1,fd=44))
LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=1135,fd=7))
LISTEN 0 5 [::1]:631 [::]:* users:(("cupsd",pid=1132,fd=9))
[root@centos8 backup]# xtrabackup --copy-back --target-dir=/backup/
[root@centos8 backup]# ll /data/mysql
total 122924
drwxr-x---. 2 root root 272 Oct 29 08:01 hellodb
-rw-r-----. 1 root root 425 Oct 29 08:01 ib_buffer_pool
-rw-r-----. 1 root root 12582912 Oct 29 08:01 ibdata1
-rw-r-----. 1 root root 50331648 Oct 29 08:01 ib_logfile0
-rw-r-----. 1 root root 50331648 Oct 29 08:01 ib_logfile1
-rw-r-----. 1 root root 12582912 Oct 29 08:01 ibtmp1
drwxr-x---. 2 root root 4096 Oct 29 08:01 mysql
drwxr-x---. 2 root root 8192 Oct 29 08:01 performance_schema
drwxr-x---. 2 root root 8192 Oct 29 08:01 sys
-rw-r-----. 1 root root 22 Oct 29 08:01 xtrabackup_binlog_pos_innodb
-rw-r-----. 1 root root 461 Oct 29 08:01 xtrabackup_info
-rw-r-----. 1 root root 1 Oct 29 08:01 xtrabackup_master_key_id
[root@centos8 backup]#
[root@centos8 backup]# ll -d /data/mysql
drwxr-xr-x. 6 mysql mysql 251 Oct 29 08:01 /data/mysql
3)还原属性
[root@centos8 backup]# chown -R mysql:mysql /data/mysql
4)启动服务
[root@centos8 backup]# service mysqld start
Starting MySQL.Logging to '/data/mysql/mysql.log'.
. SUCCESS!
[root@centos8 backup]# ss -ntlp
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 0.0.0.0:111 0.0.0.0:* users:(("rpcbind",pid=981,fd=4),("systemd",pid=1,fd=42))
LISTEN 0 32 192.168.122.1:53 0.0.0.0:* users:(("dnsmasq",pid=2145,fd=6))
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1135,fd=5))
LISTEN 0 5 127.0.0.1:631 0.0.0.0:* users:(("cupsd",pid=1132,fd=10))
LISTEN 0 128 [::]:111 [::]:* users:(("rpcbind",pid=981,fd=6),("systemd",pid=1,fd=44))
LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=1135,fd=7))
LISTEN 0 5 [::1]:631 [::]:* users:(("cupsd",pid=1132,fd=9))
LISTEN 0 80 *:3306 *:* users:(("mysqld",pid=3992,fd=25))
[root@centos8 backup]# mysql
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.29-log MySQL Community Server (GPL)
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> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| hellodb |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
mysql> 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
mysql> 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)
mysql> \q
Bye
[root@centos8 backup]#
完成。
旧版本
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完全,增量备份及还原
形象记忆:扎口袋
案例1:新版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
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 ~]#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 --incrementaldir=/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
案例2:旧版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 --incrementalbasedir=/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/ --incrementaldir=/data/inc1/2018-02-23_14-26-17
innobackupex --apply-log /data/2018-02-23_14-21-42/ --incrementaldir=/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
本次测试
2024年11月5日测试(测试成功)
环境
CentOS Linux release 8.1.1911 (Core)系统
mysql 5.7.29
xtrabackup-24-2.4.20
- 清空当前文件夹
[root@centos8 backup]# rm -rf /backup/*
[root@centos8 backup]# ls /backup/
- 当前数据库是有数据的
[root@centos8 backup]# mysql -e "show databases;"
+--------------------+
| Database |
+--------------------+
| information_schema |
| hellodb |
| mysql |
| performance_schema |
| sys |
+--------------------+
[root@centos8 backup]# mysql -e "select * from hellodb.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 |
+-----+---------------+-----+--------+
[root@centos8 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
- 第一次完全备份:
[root@centos8 backup]# xtrabackup --backup --target-dir=/backup/base
[root@centos8 backup]# tree -d /backup/base/
/backup/base/
├── hellodb
├── mysql
├── performance_schema
└── sys
4 directories
[root@centos8 backup]# du -sh /backup/base/
27M /backup/base/
[root@centos8 backup]# du -sh /data/mysql
135M /data/mysql
- 第一次修改数据:
[root@centos8 backup]# mysql -e "insert hellodb.teachers (name,age,gender) values('mage',30,'M')"
[root@centos8 backup]# mysql -e "insert hellodb.teachers (name,age,gender) values('wang',34,'M')"
[root@centos8 backup]# mysql -e "select * from hellodb.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 |
| 5 | mage | 30 | M |
| 6 | wang | 34 | M |
+-----+---------------+-----+--------+
[root@centos8 backup]#
- 第一次增量备份
[root@centos8 ~]#xtrabackup --backup --target-dir=/backup/inc1 --incremental-basedir=/backup/base
[root@centos8 backup]# ls /backup/
base inc1
[root@centos8 backup]# tree -d /backup/inc1/
/backup/inc1/
├── hellodb
├── mysql
├── performance_schema
└── sys
4 directories
[root@centos8 backup]# du -sh /backup/*
27M /backup/base
3.4M /backup/inc1
- 第二次修改数据
[root@centos8 ~]# mysql -e "insert hellodb.teachers (name,age,gender) values('zhang',38,'M')"
[root@centos8 ~]# mysql -e "insert hellodb.teachers (name,age,gender) values('guiyuan',28,'M')"
[root@centos8 ~]# mysql -e "select * from hellodb.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 |
| 5 | mage | 30 | M |
| 6 | wang | 34 | M |
| 7 | zhang | 38 | M |
| 8 | guiyuan | 28 | M |
+-----+---------------+-----+--------+
[root@centos8 ~]#
- 第二次增量备份
xtrabackup --backup --target-dir=/backup/inc2 --incremental-basedir=/backup/inc1
[root@centos8 ~]# du -sh /backup/*
27M /backup/base
3.4M /backup/inc1
3.4M /backup/inc2
以上备份完成。
- 模拟数据库崩溃
#先停止数据库
[root@centos8 ~]# service mysqld stop
Shutting down MySQL.. SUCCESS!
[root@centos8 ~]# ls /data/mysql
auto.cnf centos8-bin.000001 client-key.pem ibdata1 mysql private_key.pem server-key.pem xtrabackup_info
ca-key.pem centos8-bin.index hellodb ib_logfile0 mysql.log public_key.pem sys xtrabackup_master_key_id
ca.pem client-cert.pem ib_buffer_pool ib_logfile1 performance_schema server-cert.pem xtrabackup_binlog_pos_innodb
#清空数据库目录
[root@centos8 ~]# rm -rf /data/mysql/*
开始回滚:
- 预准备完成备份,此选项--apply-log-only 阻止回滚未完成的事务
[root@centos8 ~]#xtrabackup --prepare --apply-log-only --target-dir=/backup/base
- 合并第1次增量备份到完全备份
[root@centos8 ~]#xtrabackup --prepare --apply-log-only --target-dir=/backup/base --incremental-dir=/backup/inc1
- 合并第2次增量备份到完全备份:最后一次还原不需要加选项--apply-log-only
[root@centos8 ~]#xtrabackup --prepare --target-dir=/backup/base --incremental-dir=/backup/inc2
[root@centos8 ~]# du -sh /backup/*
143M /backup/base
12M /backup/inc1
12M /backup/inc2
- 复制到数据库目录,注意数据库目录必须为空,MySQL服务不能启动
[root@centos8 ~]# ss -ntlp|grep 3306
[root@centos8 ~]# ps -ef|grep mysqld
root 6499 6128 0 06:36 pts/2 00:00:00 grep --color=auto mysqld
[root@centos8 ~]#xtrabackup --copy-back --target-dir=/backup/base
[root@centos8 ~]# ll /data/mysql
total 122924
drwxr-x---. 2 root root 272 Nov 5 06:35 hellodb
-rw-r-----. 1 root root 425 Nov 5 06:35 ib_buffer_pool
-rw-r-----. 1 root root 12582912 Nov 5 06:35 ibdata1
-rw-r-----. 1 root root 50331648 Nov 5 06:35 ib_logfile0
-rw-r-----. 1 root root 50331648 Nov 5 06:35 ib_logfile1
-rw-r-----. 1 root root 12582912 Nov 5 06:35 ibtmp1
drwxr-x---. 2 root root 4096 Nov 5 06:35 mysql
drwxr-x---. 2 root root 8192 Nov 5 06:35 performance_schema
drwxr-x---. 2 root root 8192 Nov 5 06:35 sys
-rw-r-----. 1 root root 24 Nov 5 06:35 xtrabackup_binlog_pos_innodb
-rw-r-----. 1 root root 507 Nov 5 06:35 xtrabackup_info
-rw-r-----. 1 root root 1 Nov 5 06:35 xtrabackup_master_key_id
[root@centos8 ~]# du -sh /data/mysql
135M /data/mysql
- 还原属性 & 启动服务
[root@centos8 ~]#chown -R mysql:mysql /data/mysql
[root@centos8 ~]# service mysqld start
Starting MySQL.Logging to '/data/mysql/mysql.log'.
. SUCCESS!
- 验证
[root@centos8 ~]# mysql hellodb
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.29-log MySQL Community Server (GPL)
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> 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 |
| 5 | mage | 30 | M |
| 6 | wang | 34 | M |
| 7 | zhang | 38 | M |
| 8 | guiyuan | 28 | M |
+-----+---------------+-----+--------+
8 rows in set (0.00 sec)
mysql>
mysql数据库备份还原成功。
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
6.1 MySQL主从复制
6.1.1 主从复制架构和原理
6.1.1.1 服务性能扩展方式
- Scale Up,向上扩展,垂直扩展
- Scale Out,向外扩展,横向扩展
6.1.1.2 MySQL的扩展
- 读写分离
- 复制:每个节点都有相同的数据集,向外扩展,基于二进制日志的单向复制
6.1.1.3 复制的功用
- 数据分布
- 负载均衡读
- 备份
- 高可用和故障切换
- MySQL升级测试
6.1.1.4 复制架构
一主一从复制架构
一主多从复制架构
6.1.1.5 主从复制原理
主从复制相关线程
主节点:
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日志的对应关系
mariadb-relay-bin.00000#
: 中继日志,保存从主节点复制过来的二进制日志,本质就是二进制日志
范例: 中继日志
[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 Start:
binlog v 4, server v 10.3.17-MariaDB-log created 200615 17:58:48
BINLOG '
WEbnXg8cAAAA/AAAAAABAAAAAAQAMTAuMy4xNy1NYXJpYURCLWxvZwAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAA5AAEGggAAAAICAgCAAAACgoKAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
6.1.1.6 主从复制特点
- 异步复制
- 主从数据不一致比较常见
6.1.1.7 各种复制架构
- 一Master/一Slave
- 一主多从
- 从服务器还可以再有从服务器
- Master/Master
- 一从多主:适用于多个不同数据库
- 环状复制
复制需要考虑二进制日志事件记录格式
STATEMENT(5.0之前)
ROW(5.1之后,推荐)
MIXED
6.1.2 实现主从复制配置
参考官网
https://mariadb.com/kb/en/library/setting-up-replication/
https://dev.mysql.com/doc/refman/5.5/en/replication-configuration.html
主节点配置:
(1) 启用二进制日志
[mysqld]
log_bin
(2) 为当前节点设置一个全局惟一的ID号
[mysqld]
server-id=#
log-basename=master #可选项,设置datadir中日志名称,确保不依赖主机名
说明:
server-id的取值范围
1 to 4294967295 (>= MariaDB 10.2.2)
,默认值为1
0 to 4294967295 (<= MariaDB 10.2.1)
,默认值为0,如果从节点为0,所有master都将拒绝此slave的连接
[root@centos8 ~]# mysql -e 'select @@server_id'
+-------------+
| @@server_id |
+-------------+
| 1 |
+-------------+
(3) 创建有复制权限的用户账号
GRANT REPLICATION SLAVE ON *.* TO 'repluser'@'HOST' IDENTIFIED BY 'replpass';
(4) 查看从二进制日志的文件和位置开始进行复制
SHOW MASTER LOG;
从节点配置:
(1) 启动中继日志
[mysqld]
server_id=# #为当前节点设置一个全局惟的ID号
log-bin
read_only=ON #设置数据库只读,针对supper user无效
relay_log=relay-log #relay log的文件路径,默认值hostname-relay-bin
relay_log_index=relay-log.index #默认值hostname-relay-bin.index
(2) 使用有复制权限的用户账号连接至主服务器,并启动复制线程
CHANGE MASTER TO MASTER_HOST='masterhost',
MASTER_USER='repluser',
MASTER_PASSWORD='replpass',
MASTER_LOG_FILE='mariadb-bin.xxxxxx',
MASTER_LOG_POS=#;
START SLAVE [IO_THREAD|SQL_THREAD];
SHOW SLAVE STATUS;
范例:新建主从复制
#主节点
[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)]> grant replication slave on *.* to repluser@'192.168.8.%'
identified by 'magedu';
#查看二进制文件和位置
MariaDB [(none)]> show master logs;
+--------------------+-----------+
| Log_name | File_size |
+--------------------+-----------+
| mariadb-bin.000001 | 28052 |
| mariadb-bin.000002 | 545 |
+--------------------+-----------+
2 rows in set (0.001 sec)
#从节点
[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='192.168.8.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: 192.168.8.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 | Value |
+---------------------+-------+
| sync_binlog | 0 |
|---------------------+-------+
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='192.168.8.10',
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: 192.168.8.10
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;
实际测试过程
(亲自测试成功)-2024年12月6日。
环境:
centos8.1 mariadb10.3
主服务器:192.168.1.81
从服务器:192.168.1.82
- 当前主服务器已经运行了一些mysql数据了
[root@mysql ~]# mysql -e 'select * from hellodb.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 |
+-----+---------------+-----+--------+
编辑主服务器配置文件
#vim /etc/my.cnf.d/mariadb-server.cnf
log_bin
server-id=81
重启mariadb前文件如下:ls -l /var/lib/mysql/
重启mariadb后文件如下:
systemctl restart mariadb
主要多了这2个文件。
- 查看当前二进制日志的文件和位置:
MariaDB [(none)]> show master logs;
+--------------------+-----------+
| Log_name | File_size |
+--------------------+-----------+
| mariadb-bin.000001 | 330 |
+--------------------+-----------+
1 row in set (0.000 sec)
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| hellodb |
| information_schema |
| mysql |
| performance_schema |
+--------------------+
4 rows in set (0.000 sec)
MariaDB [(none)]>
存在的问题,老数据该怎么办呢?
在主服务器做完全备份
- 需要做一个数据库的完全备份,然后再从后面的数据进行同步
mkdir /backup
mysqldump -A -F --single-transaction --master-data=1 > /backup/all.sql
[root@mysql ~]# ll /backup/all.sql
-rw-r--r--. 1 root root 487675 Dec 3 21:30 /backup/all.sql
cat /backup/all.sql
#也就是说从这个位置往后就是我们要同步的内容:
CHANGE MASTER TO MASTER_LOG_FILE='mariadb-bin.000002', MASTER_LOG_POS=375;
主节点创建有复制权限的用户账号
MariaDB [(none)]> grant replication slave on *.* to repluser@'192.168.1.%' identified by '123456';
Query OK, 0 rows affected (0.000 sec)
MariaDB [(none)]> show processlist;
+----+-------------+-----------+------+---------+------+--------------------------+------------------+----------+
| Id | User | Host | db | Command | Time | State | Info | Progress |
+----+-------------+-----------+------+---------+------+--------------------------+------------------+----------+
| 2 | system user | | NULL | Daemon | NULL | InnoDB purge worker | NULL | 0.000 |
| 1 | system user | | NULL | Daemon | NULL | InnoDB purge coordinator | NULL | 0.000 |
| 3 | system user | | NULL | Daemon | NULL | InnoDB purge worker | NULL | 0.000 |
| 4 | system user | | NULL | Daemon | NULL | InnoDB purge worker | NULL | 0.000 |
| 5 | system user | | NULL | Daemon | NULL | InnoDB shutdown handler | NULL | 0.000 |
| 11 | root | localhost | NULL | Query | 0 | Init | show processlist | 0.000 |
+----+-------------+-----------+------+---------+------+--------------------------+------------------+----------+
6 rows in set (0.000 sec)
来到从节点
此时,从节点服务器是一个干净的系统。
把主节点的all.sql给复制过来:
[root@mysql ~]# scp /backup/all.sql root@192.168.1.82:/data
root@192.168.1.82's password:
all.sql 100% 476KB 67.3MB/s 00:00
[root@mysql ~]#
- 给从服务器安装mysql:
[root@mysql_backup ~]# dnf install mariadb-server -y
- 修改从服务器的数据库配置文件
[root@mysql_backup ~]# vim /etc/my.cnf.d/mariadb-server.cnf
……
[mysqld]
server-id=82
#这里先只配置server_id,可以不用配置log-bin的
- 把数据库启动起来
[root@mysql_backup ~]# systemctl restart mariadb
[root@mysql_backup ~]# ss -ntlp|grep 3306
LISTEN 0 80 *:3306 *:* users:(("mysqld",pid=45568,fd=22))
[root@mysql_backup ~]#
[root@mysql_backup ~]# mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 8
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)]>
- 现在要把数据同步过来
---参考文档:
使用有复制权限的用户账号连接至主服务器,并启动复制线程
CHANGE MASTER TO MASTER_HOST='masterhost',
MASTER_USER='repluser',
MASTER_PASSWORD='replpass',
MASTER_LOG_FILE='mariadb-bin.xxxxxx',
MASTER_LOG_POS=#;
START SLAVE [IO_THREAD|SQL_THREAD];
SHOW SLAVE STATUS;
查看帮助:
MariaDB [(none)]> help change master to;
Name: 'CHANGE MASTER TO'
Description:
Syntax:
CHANGE MASTER TO option [, option] ...
CHANGE MASTER TO
MASTER_HOST='master2.mycompany.com',
MASTER_USER='replication',
MASTER_PASSWORD='bigs3cret',
MASTER_PORT=3306,
MASTER_LOG_FILE='master2-bin.001',
MASTER_LOG_POS=4,
MASTER_CONNECT_RETRY=10;
……
编辑all.sql文件:
[root@mysql_backup ~]# vim /data/all.sql
CHANGE MASTER TO
MASTER_HOST='192.168.1.81',
MASTER_USER='repluser',
MASTER_PASSWORD='123456',
MASTER_PORT=3306,
MASTER_LOG_FILE='mariadb-bin.xxxxxx',
MASTER_LOG_POS=#;
- 导入all.sql文件(恢复了数据库,并且做了数据同步操作)
[root@mysql_backup ~]# mysql < /data/all.sql
默认是没有启动线程的:
MariaDB [(none)]>
MariaDB [(none)]> show processlist;
+----+-------------+-----------+------+---------+------+--------------------------+------------------+----------+
| Id | User | Host | db | Command | Time | State | Info | Progress |
+----+-------------+-----------+------+---------+------+--------------------------+------------------+----------+
| 1 | system user | | NULL | Daemon | NULL | InnoDB purge worker | NULL | 0.000 |
| 2 | system user | | NULL | Daemon | NULL | InnoDB purge coordinator | NULL | 0.000 |
| 3 | system user | | NULL | Daemon | NULL | InnoDB purge worker | NULL | 0.000 |
| 4 | system user | | NULL | Daemon | NULL | InnoDB purge worker | NULL | 0.000 |
| 5 | system user | | NULL | Daemon | NULL | InnoDB shutdown handler | NULL | 0.000 |
| 9 | root | localhost | NULL | Query | 0 | Init | show processlist | 0.000 |
+----+-------------+-----------+------+---------+------+--------------------------+------------------+----------+
6 rows in set (0.000 sec)
MariaDB [(none)]>
- 导入完后,运行2个线程即可
#先来看下这个状态:
MariaDB [(none)]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State:
Master_Host: 192.168.1.81
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mariadb-bin.000002
Read_Master_Log_Pos: 375
Relay_Log_File: mariadb-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File: mariadb-bin.000002
Slave_IO_Running: No
Slave_SQL_Running: No
这个Seconds_Behind_Master
参数很重要,代表主和从之间的复制延迟的,null代表还没开始复制。(最好显示0,代表已同步了)
此时,在我们系统里已经生成了若干文件:
[root@mysql_backup ~]# ll -t /var/lib/mysql/
- 启动2个线程:
MariaDB [(none)]> start slave;
Query OK, 0 rows affected (0.001 sec)
观察:
#从节点
MariaDB [(none)]> show slave status\G
主节点:
探讨个问题
当时在主服务器上执行这个命令后,是在数据库备份后操作的,那么问下,在从服务器上这个用户还存在吗?
MariaDB [(none)]> grant replication slave on *.* to repluser@'192.168.1.%' identified by '123456';
Query OK, 0 rows affected (0.000 sec)
来到从服务器上验证:
MariaDB [(none)]> select user,host from mysql.user;
+----------+-------------+
| user | host |
+----------+-------------+
| root | 127.0.0.1 |
| repluser | 192.168.1.% |
| root | ::1 |
| root | localhost |
| root | mysql |
+----------+-------------+
5 rows in set (0.001 sec)
可以看到,从服务器上这个用户也是存在的,为什么呢,因为数据被同步过来了。
#主服务器
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| hellodb |
| information_schema |
| mysql |
| performance_schema |
+--------------------+
4 rows in set (0.000 sec)
MariaDB [(none)]>
#从服务器
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| hellodb |
| information_schema |
| mysql |
| performance_schema |
+--------------------+
4 rows in set (0.000 sec)
#主服务器上创建db1
MariaDB [(none)]> create database db1;
Query OK, 1 row affected (0.000 sec)
#从服务器上立马验证,会发现立马出现了db1,由此,我们实现了主从服务器的实时同步。
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| db1 |
| hellodb |
| information_schema |
| mysql |
| performance_schema |
+--------------------+
5 rows in set (0.000 sec)
#主服务器上删除db1
MariaDB [(none)]> drop database db1;
Query OK, 0 rows affected (0.001 sec)
#从服务器上立马验证,发现db1被删除了(不要想着主从复制会备份数据,所以数据库还是得备份好。)
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| hellodb |
| information_schema |
| mysql |
| performance_schema |
+--------------------+
4 rows in set (0.000 sec)
如果是干净数据库
CHANGE MASTER TO
MASTER_HOST='master2.mycompany.com',
MASTER_USER='replication',
MASTER_PASSWORD='bigs3cret',
MASTER_PORT=3306,
MASTER_LOG_FILE='master2-bin.001',
MASTER_LOG_POS=4,
MASTER_CONNECT_RETRY=10;
……
这个命令手工巧就好,干净的数据库不需要备份。
研究下这个东西
#建议优化主和从节点服务器的性能
MariaDB [hellodb]> set global innodb_flush_log_at_trx_commit=2
MariaDB [hellodb]> set global sync_binlog=0
测试过程:
主服务器上执行:
[root@mysql ~]# cat testlog.sql
create table testlog (id int auto_increment primary key,name char(10),age int default 20);
delimiter $$
create procedure pro_testlog()
begin
declare i int;
set i = 1;
while i < 100000
do insert into testlog(name,age) values (concat('wang',i),i);
set i = i +1;
end while;
end$$
delimiter ;
[root@mysql ~]# mysql hellodb < testlog.sql
然后在从服务器上查看:(可以看到testlog这个表是空的)
MariaDB [(none)]> 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]> show tables;
+-------------------+
| Tables_in_hellodb |
+-------------------+
| classes |
| coc |
| courses |
| scores |
| students |
| teachers |
| testlog |
| toc |
+-------------------+
8 rows in set (0.000 sec)
MariaDB [hellodb]> select *from testlog;
Empty set (0.000 sec)
主服务器上:
[root@mysql ~]# mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 15
Server version: 10.3.17-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)]> 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]> select *from testlog;
Empty set (0.000 sec)
MariaDB [hellodb]>
当初手动执行这个存储过程,花费了40多s,但是有了主从复制关系后,会明显变的更慢:(2min应该是用的mysql8)
#主服务器上执行
call sp_testlog;
MariaDB [hellodb]> call pro_testlog;
Query OK, 99999 rows affected (25.180 sec)
花了2min才搞定:。。。(我的花费25s,老师的花费了2min)
#这一项默认是0,已经启用了
MariaDB [hellodb]> select @@sync_binlog;
+---------------+
| @@sync_binlog |
+---------------+
| 0 |
+---------------+
1 row in set (0.000 sec)
#这一项,写事务日志时,这个工作模式是不一样的:
set global innodb_flush_log_at_trx_commit=2
#vim /etc/my.cnf.d/mariadb-server.cnf
……
innodb_flush_log_at_trx_commit=2
#这个步骤2个几点都要设置!
#vim /etc/my.cnf.d/mariadb-server.cnf #这个步骤2个几点都要设置!
……
innodb_flush_log_at_trx_commit=2
然后重启主从mariadb服务:
systemctl restart mariadb
如果遇到在从服务器上执行show slave status\G
报错的话,就执行下如下命令:(或者等待60s后也可以的)
MariaDB [(none)]> slave stop;
MariaDB [(none)]> slave start;
来再次测试下:
主服务器:
MariaDB [hellodb]> call pro_testlog;
Query OK, 99999 rows affected (5.856 sec)
从服务器:
能够明显看到,本次速度耗时5s。🤣
更好的方式:
用事务的方式:(快的飞起🤣)(0.969s)
MariaDB [hellodb]> begin;call pro_testlog;commit;
Query OK, 0 rows affected (0.000 sec)
Query OK, 99999 rows affected (0.969 sec)
Query OK, 0 rows affected (0.107 sec)
MariaDB [hellodb]>
如何再增加一个新的从节点
给主服务器做全量备份,然后一样的操作。
主服务器:
[root@mysql ~]# mysqldump -A -F --single-transaction --master-data=1 > /backup/all.sql
复制文件:
[root@mysql ~]# scp /backup/all.sql root@192.168.1.83:/data
从服务器上执行:
#安装mariadb
[root@mysql-backup-2 ~]# dnf install mariadb-server -y
#修改配置文件
[root@mysql-backup-2 ~]# vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
log_bin
server-id=83
read_only
#重启mariadb服务
[root@mysql-backup-2 ~]# systemctl restart mariadb
#打开数据库备份文件
[root@mysql-backup-2 ~]# vim /data/all.sql
CHANGE MASTER TO
MASTER_HOST='192.168.1.81',
MASTER_USER='repluser',
MASTER_PASSWORD='123456',
MASTER_PORT=3306,
MASTER_LOG_FILE='mariadb-bin.000005', MASTER_LOG_POS=389;
#导入数据
[root@mysql-backup-2 ~]# mysql < /data/all.sql
#验证
[root@mysql-backup-2 ~]# mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 9
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 databases;
+--------------------+
| Database |
+--------------------+
| hellodb |
| information_schema |
| mysql |
| performance_schema |
+--------------------+
4 rows in set (0.000 sec)
MariaDB [(none)]>
#先来看下状态
MariaDB [(none)]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State:
Master_Host: 192.168.1.81
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mariadb-bin.000005
Read_Master_Log_Pos: 389
Relay_Log_File: mariadb-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File: mariadb-bin.000005
Slave_IO_Running: No #这2个线程还没启用
Slave_SQL_Running: No
……
#启动线程
MariaDB [(none)]> start slave;
Query OK, 0 rows affected (0.001 sec)
#再次确认
MariaDB [(none)]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.1.81
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mariadb-bin.000005
Read_Master_Log_Pos: 389
Relay_Log_File: mariadb-relay-bin.000002
Relay_Log_Pos: 557
Relay_Master_Log_File: mariadb-bin.000005
Slave_IO_Running: Yes #ok了
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: 389
Relay_Log_Space: 868
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: 81
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: 0
Slave_Non_Transactional_Groups: 0
Slave_Transactional_Groups: 0
1 row in set (0.000 sec)
MariaDB [(none)]>
MariaDB [(none)]> show processlist;
+----+-------------+-----------+------+-----------+------+-----------------------------------------------------------------------------+------------------+----------+
| Id | User | Host | db | Command | Time | State | Info | Progress |
+----+-------------+-----------+------+-----------+------+-----------------------------------------------------------------------------+------------------+----------+
| 2 | system user | | NULL | Daemon | NULL | InnoDB purge worker | NULL | 0.000 |
| 3 | system user | | NULL | Daemon | NULL | InnoDB purge worker | NULL | 0.000 |
| 4 | system user | | NULL | Daemon | NULL | InnoDB purge worker | NULL | 0.000 |
| 1 | system user | | NULL | Daemon | NULL | InnoDB purge coordinator | NULL | 0.000 |
| 5 | system user | | NULL | Daemon | NULL | InnoDB shutdown handler | NULL | 0.000 |
| 9 | root | localhost | NULL | Query | 0 | Init | show processlist | 0.000 |
| 10 | system user | | NULL | Slave_IO | 33 | Waiting for master to send event | NULL | 0.000 |
| 11 | system user | | NULL | Slave_SQL | 33 | Slave has read all relay log; waiting for the slave I/O thread to update it | NULL | 0.000 |
+----+-------------+-----------+------+-----------+------+-----------------------------------------------------------------------------+------------------+----------+
8 rows in set (0.000 sec)
MariaDB [(none)]>
#现在尝试在主服务器上新创建一个数据库
MariaDB [(none)]> 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('mage',30,'M');
Query OK, 1 row affected (0.000 sec)
#再从服务器上验证
#从服务器1
MariaDB [(none)]> 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]> select *from hellodb.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 |
| 5 | mage | 30 | M |
+-----+---------------+-----+--------+
5 rows in set (0.000 sec)
MariaDB [hellodb]>
#从服务器2
MariaDB [(none)]> 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]> select *from hellodb.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 |
| 5 | mage | 30 | M |
+-----+---------------+-----+--------+
5 rows in set (0.000 sec)
MariaDB [hellodb]>
#符合预期,数据已经同步过来了。
来模拟下这个场景:选举新的从为主
在主服务器上执行这个命令:
call pro_testlog;
然后对主服务器断电,那么2个从服务器就会进行选举新的主了。
那么问题来了,82和83 2个从服务器,你提升谁成为主服务器呢?
要提升谁,就要确认谁的数据同步的最多。
这2个值数值是一样的。
那就随便了。
当然看这里的位置也行:
如何让82成为新的主呢
手工打开它的二级日志:
[root@mysql-backup ~]# vim /etc/my.cnf.d/mariadb-server.cnf
log-bin
#并且ready-only日志开关关掉。
重启数据库服务:
[root@mysql-backup ~]# systemctl restart mariadb
自己身上还有之前残留的从服务器信息:
MariaDB [(none)]> show slave status\G
所以要把这个从信息去掉
关闭这2个线程:
MariaDB [(none)]> stop slave;
Query OK, 0 rows affected (0.001 sec)
在从节点清楚信息:
MariaDB [(none)]> reset slave;
Query OK, 0 rows affected (0.001 sec)
#从服务器清除master.info ,relay-log.info, relay log ,开始新的relay log
删除后:
删除前:
要想彻底删除干净,就加个all:
MariaDB [(none)]> reset slave all;
Query OK, 0 rows affected (0.000 sec)
MariaDB [(none)]> show slave status\G #这里的东西就没了
Empty set (0.000 sec)
此时,它就成为一台真正的独立服务器,并不成为任何人的从了。
在另一台83从上配置信息
#目前指向的任然是旧主
MariaDB [(none)]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Reconnecting after a failed master event read
Master_Host: 192.168.1.81
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mariadb-bin.000005
Read_Master_Log_Pos: 25302076
Relay_Log_File: mariadb-relay-bin.000002
Relay_Log_Pos: 25302202
Relay_Master_Log_File: mariadb-bin.000005
Slave_IO_Running: Connecting
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: 25302034
Relay_Log_Space: 25302555
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: 2003
Last_IO_Error: error reconnecting to master 'repluser@192.168.1.81:3306' - retry-time: 60 maximum-retries: 86400 message: Can't connect to MySQL server on '192.168.1.81' (111 "Connection refused")
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 81
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: 0
Slave_Non_Transactional_Groups: 0
Slave_Transactional_Groups: 92424
1 row in set (0.000 sec)
如何改变他的新主人,将82作为他的新主人
#关闭2个线程
MariaDB [(none)]> stop slave;
Query OK, 0 rows affected (0.001 sec)
MariaDB [(none)]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State:
Master_Host: 192.168.1.81
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mariadb-bin.000005
Read_Master_Log_Pos: 25302076
Relay_Log_File: mariadb-relay-bin.000002
Relay_Log_Pos: 25302202
Relay_Master_Log_File: mariadb-bin.000005
Slave_IO_Running: No
Slave_SQL_Running: No
#把刚才的同步信息清理掉
MariaDB [(none)]> reset slave all;
Query OK, 0 rows affected (0.002 sec)
MariaDB [(none)]> show slave status\G
Empty set (0.000 sec)
#重新建立新的主关系
本身我们看到那个数据位置是一样的,那么这里就不做复制了。(否则是要备份复制数据的)
要指定复制的账号和位置;
复制的账号之前已经复制过来了;
MariaDB [(none)]> select user,host from mysql.user;
+----------+-------------+
| user | host |
+----------+-------------+
| root | 127.0.0.1 |
| repluser | 192.168.1.% |
| root | ::1 |
| root | localhost |
| root | mysql |
+----------+-------------+
5 rows in set (0.000 sec)
MariaDB [(none)]> show master logs;
+--------------------+-----------+
| Log_name | File_size |
+--------------------+-----------+
| mariadb-bin.000001 | 28210 |
| mariadb-bin.000002 | 493926 |
| mariadb-bin.000003 | 412 |
| mariadb-bin.000004 | 367 |
| mariadb-bin.000005 | 367 |
| mariadb-bin.000006 | 367 |
| mariadb-bin.000007 | 344 |
+--------------------+-----------+
7 rows in set (0.000 sec)
#在83上使用复制信息
CHANGE MASTER TO
MASTER_HOST='192.168.1.82',
MASTER_USER='repluser',
MASTER_PASSWORD='123456',
MASTER_PORT=3306,
MASTER_LOG_FILE='mariadb-bin.000007',
MASTER_LOG_POS=344;
MariaDB [(none)]> CHANGE MASTER TO
-> MASTER_HOST='192.168.1.82',
-> MASTER_USER='repluser',
-> MASTER_PASSWORD='123456',
-> MASTER_PORT=3306,
-> MASTER_LOG_FILE='mariadb-bin.000007',
-> MASTER_LOG_POS=344;
Query OK, 0 rows affected (0.016 sec)
#启用2个线程
MariaDB [(none)]> start slave;
Query OK, 0 rows affected (0.001 sec)
#查看下
MariaDB [(none)]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.1.82
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mariadb-bin.000007
Read_Master_Log_Pos: 344
Relay_Log_File: mariadb-relay-bin.000002
Relay_Log_Pos: 557
Relay_Master_Log_File: mariadb-bin.000007
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
验证下:
#82主服务器上创建db2
MariaDB [(none)]> create database db2;
Query OK, 1 row affected (0.000 sec)
#83从服务器上确认(符合预期)
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| db2 |
| hellodb |
| information_schema |
| mysql |
| performance_schema |
+--------------------+
5 rows in set (0.000 sec)
以上,新主就提升好了。
这种方法理论可行,但实际上实施起来可行新很差。
好像有些麻烦哈,哈哈哈。。。。
那么有没有什么更简洁的方式呢???
mha--自动提升。
The end。
6.1.3 主从复制相关
1、限制从服务器为只读
read_only=ON
#注意:此限制对拥有SUPER权限的用户均无效
##配置过程
vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
……
read_only
systemctl restart mariadb
MariaDB [(none)]> select @@read_only;
+-------------+
| @@read_only |
+-------------+
| 1 |
+-------------+
1 row in set (0.000 sec)
注意:以下命令会阻止所有用户, 包括主服务器复制的更新
FLUSH TABLES WITH READ LOCK;
2、在从节点清除信息
注意:以下都需要先 STOP SLAVE
RESET SLAVE #从服务器清除master.info ,relay-log.info, relay log ,开始新的relay log
RESET SLAVE ALL #清除所有从服务器上设置的主服务器同步信息,如HOST,PORT, USER和
PASSWORD 等
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 | 28303 |
| mariadb-bin.000002 | 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 | 28303 |
| mariadb-bin.000002 | 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)
范例:主主复制(测试成功)-2024.12.8
自己测试过程
以下将测试主-主 mysql情况。
- 修改2台主机名称,方便区分:
192.168.1.81 master1
192.168.1.82 master2
#都是centos8环境
CentOS Linux release 8.1.1911 (Core)
10.3.17-MariaDB MariaDB Server
- 这里的主主配置和单主配置是类似的
主主复制可能存在主键冲突问题。
- 保持2台服务器为干净数据
rm -rf /var/lib/mysql/
dnf remove -y mariadb-server
dnf install -y mariadb-server
systemctl enable --now mariadb
在第一个master节点上实现
[root@master1 ~]# vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id=81
log-bin
auto_increment_offset=1
auto_increment_increment=2
#关键数据就2行,哪个自动增长其实加和不加都不是必须得,这里是为了看效果加上的。(实际工作里,另一个主是当从来用的)
#重启数据库
[root@master1 ~]# systemctl restart mariadb
#创建个授权账号
MariaDB [(none)]> grant replication slave on *.* to repluser@'192.168.1.%' identified by '123456';
Query OK, 0 rows affected (0.000 sec)
#看下位置
MariaDB [(none)]> show master logs;
+--------------------+-----------+
| Log_name | File_size |
+--------------------+-----------+
| mariadb-bin.000001 | 585 |
| mariadb-bin.000002 | 389 | #这里
+--------------------+-----------+
2 rows in set (0.000 sec)
#备份数据
[root@master1 ~]# mysqldump -A -F --single-transaction --master-data=1 > /data/all-`date +%F`.sql
[root@master1 ~]# ll /data/all-2024-12-07.sql
-rw-r--r--. 1 root root 487922 Dec 7 11:01 /data/all-2024-12-07.sql
#拷贝备份文件到master2
[root@master1 ~]# scp /data/all-2024-12-07.sql root@192.168.1.82:/data
root@192.168.1.82's password:
all-2024-12-07.sql 100% 476KB 64.7MB/s 00:00
[root@master1 ~]#
在第二个master节点上实现
#修改配置文件
[root@master1 ~]# vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id=82
log-bin
auto_increment_offset=2
auto_increment_increment=2
#这个主节点也是必须要启用二进制日志的。
#重启数据库服务
[root@master2 ~]# systemctl restart mariadb
#编辑刚才复制过来的二进制日志文件
[root@master2 ~]# vim /data/all-2024-12-07.sql
MASTER_HOST='192.168.1.81',
MASTER_USER='repluser',
MASTER_PASSWORD='123456',
MASTER_PORT=3306,
CHANGE MASTER TO
MASTER_HOST='192.168.1.81',
MASTER_USER='repluser',
MASTER_PASSWORD='123456',
MASTER_PORT=3306,
MASTER_LOG_FILE='mariadb-bin.000003', MASTER_LOG_POS=389;
#复制的位置是自动生成的。
#但此时的导入可能会有一个缺点,可能会生成大量的二级日志
#因此,可以考虑先进入暂时关闭二级日志
MariaDB [(none)]> set sql_log_bin=0;
Query OK, 0 rows affected (0.000 sec)
MariaDB [(none)]> show master logs;
+--------------------+-----------+
| Log_name | File_size |
+--------------------+-----------+
| mariadb-bin.000001 | 330 |
+--------------------+-----------+
1 row in set (0.000 sec)
MariaDB [(none)]> source /data/all-2024-12-07.sql
MariaDB [mysql]> set sql_log_bin=1;
Query OK, 0 rows affected (0.000 sec)
MariaDB [mysql]> show databases;
+--------------------+
| Database |
+--------------------+
| hellodb |
| information_schema |
| mysql |
| performance_schema |
+--------------------+
4 rows in set (0.000 sec)
MariaDB [mysql]>
#到此,数据库是还原过来了。
#因为之前master1备份是在创建账号之后做的,因此master2上这个复制账号也是存在的
MariaDB [mysql]> select u
+----------+-------------
| user | host
+----------+-------------
| root | 127.0.0.1
| repluser | 192.168.1.%
| root | ::1
| root | localhost
| root | master1
+----------+-------------
5 rows in set (0.000 sec)
#开启复制线程
MariaDB [mysql]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State:
Master_Host: 192.168.1.81
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
MariaDB [mysql]> start slave;
Query OK, 0 rows affected (0.001 sec)
MariaDB [mysql]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.1.81
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.000002
Relay_Log_Pos: 557
Relay_Master_Log_File: mariadb-bin.000003
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
#到此,我们实现了单向的复制(master1-->mater2)
#再次确认这个要复制的位置
#master2
MariaDB [mysql]> show master logs;
+--------------------+-----------+
| Log_name | File_size |
+--------------------+-----------+
| mariadb-bin.000001 | 330 |
+--------------------+-----------+
1 row in set (0.000 sec)
#先测试下单向复制成功么?
#在master1上创建数据库db1
MariaDB [(none)]> create database db1;
Query OK, 1 row affected (0.001 sec)
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| db1 |
| hellodb |
| information_schema |
| mysql |
| performance_schema |
+--------------------+
5 rows in set (0.000 sec)
#在maste2上确认
MariaDB [mysql]> show master logs;
+--------------------+-----------+
| Log_name | File_size |
+--------------------+-----------+
| mariadb-bin.000001 | 330 |
+--------------------+-----------+
1 row in set (0.000 sec)
MariaDB [mysql]>
MariaDB [mysql]>
MariaDB [mysql]> show databases;
+--------------------+
| Database |
+--------------------+
| db1 |
| hellodb |
| information_schema |
| mysql |
| performance_schema |
+--------------------+
5 rows in set (0.000 sec)
MariaDB [mysql]> show master logs;
+--------------------+-----------+
| Log_name | File_size |
+--------------------+-----------+
| mariadb-bin.000001 | 330 |
+--------------------+-----------+
1 row in set (0.000 sec)
MariaDB [mysql]>
##但是,发现了一个神奇的现象,就是master2这里有数据同步过来了,但是二级日志没发生变化,这是为什么呢?
数据库复制的时候,是利用了3个线程来实现的。
我的二级日志没有增长,但是我的数据库却增长过来了。
我的二级日志文件只记录本机收到的对数据库的操作,从relay log里传来的东西不进行记录!
继续配置
在master1上执行
在master2上查看下内容,并编辑代码:
#master2
MariaDB [(none)]> show master logs;
+--------------------+-----------+
| Log_name | File_size |
+--------------------+-----------+
| mariadb-bin.000001 | 330 |
+--------------------+-----------+
1 row in set (0.000 sec)
#编辑好的内容
CHANGE MASTER TO
MASTER_HOST='192.168.1.82',
MASTER_USER='repluser',
MASTER_PASSWORD='123456',
MASTER_PORT=3306,
MASTER_LOG_FILE='mariadb-bin.000001',
MASTER_LOG_POS=330;
先来master1上查看下:
#目前自己是个纯纯的主
MariaDB [(none)]> show slave status\G
Empty set (0.000 sec)
MariaDB [(none)]> show master logs;
+--------------------+-----------+
| Log_name | File_size |
+--------------------+-----------+
| mariadb-bin.000001 | 585 |
| mariadb-bin.000002 | 438 |
| mariadb-bin.000003 | 521 |
+--------------------+-----------+
3 rows in set (0.000 sec)
在master1上执行:
CHANGE MASTER TO
MASTER_HOST='192.168.1.82',
MASTER_USER='repluser',
MASTER_PASSWORD='123456',
MASTER_PORT=3306,
MASTER_LOG_FILE='mariadb-bin.000001',
MASTER_LOG_POS=330;
MariaDB [(none)]> CHANGE MASTER TO
-> MASTER_HOST='192.168.1.82',
-> MASTER_USER='repluser',
-> MASTER_PASSWORD='123456',
-> MASTER_PORT=3306,
-> MASTER_LOG_FILE='mariadb-bin.000001',
-> MASTER_LOG_POS=330;
Query OK, 0 rows affected (0.003 sec)
#开启2个线程
MariaDB [(none)]> start slave;
Query OK, 0 rows affected (0.014 sec)
验证下:
MariaDB [(none)]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Connecting to master
Master_Host: 192.168.1.82
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mariadb-bin.000001
Read_Master_Log_Pos: 330
Relay_Log_File: mariadb-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File: mariadb-bin.000001
Slave_IO_Running: Connecting
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: 330
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: 2013
Last_IO_Error: error connecting to master 'repluser@192.168.1.82:3306' - retry-time: 60 maximum-retries: 86400 message: Lost connection to MySQL server at 'reading initial communication packet', system error: 0 "Internal error/check (Not system 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 has read all relay log; waiting for the slave I/O thread to update it
Slave_DDL_Groups: 0
Slave_Non_Transactional_Groups: 0
Slave_Transactional_Groups: 0
1 row in set (0.000 sec)
MariaDB [(none)]>
咦,报错了。。。
可能还是数据库两边复制不同步导致的。🤣
重新再把数据库重新备份下:
master1:
MariaDB [(none)]> show master logs;
+--------------------+-----------+
| Log_name | File_size |
+--------------------+-----------+
| mariadb-bin.000001 | 585 |
| mariadb-bin.000002 | 438 |
| mariadb-bin.000003 | 653 |
+--------------------+-----------+
3 rows in set (0.000 sec)
#重新备份下数据库:
[root@master1 ~]# mysqldump -A -F --single-transaction --master-data=1 > /data/all-`date +%F`.sql
[root@master1 ~]# scp /data/all-2024-12-08.sql root@192.168.1.82:/data
root@192.168.1.82's password:
all-2024-12-08.sql 100% 477KB 104.8MB/s 00:00
[root@master1 ~]#
在master2上重新还原下:
[root@master2 ~]# mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 22
Server version: 10.3.17-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)]> set sql_log_bin=0;
Query OK, 0 rows affected (0.000 sec)
#把刚复制过来的文件恢复下
MariaDB [(none)]> source /data/all-2024-12-08.sql
MariaDB [mysql]> show master logs;
+--------------------+-----------+
| Log_name | File_size |
+--------------------+-----------+
| mariadb-bin.000001 | 330 |
+--------------------+-----------+
1 row in set (0.000 sec)
MariaDB [mysql]> set sql_log_bin=1;
Query OK, 0 rows affected (0.000 sec)
#数据库重新启动下
[root@master2 ~]# systemctl restart mariadb
#我们重新再来一遍,把这个数据库彻底还原下
[root@master2 ~]# mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 13
Server version: 10.3.17-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)]> set sql_log_bin=0;
Query OK, 0 rows affected (0.000 sec)
MariaDB [(none)]> source /data/all-2024-12-08.sql
MariaDB [mysql]> show master logs;
+--------------------+-----------+
| Log_name | File_size |
+--------------------+-----------+
| mariadb-bin.000001 | 353 |
| mariadb-bin.000002 | 330 |
+--------------------+-----------+
2 rows in set (0.000 sec)
MariaDB [mysql]> set sql_log_bin=1;
Query OK, 0 rows affected (0.000 sec)
#此时,两边的数据库是一模一样的了。
#master2
MariaDB [mysql]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.1.81
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mariadb-bin.000004
Read_Master_Log_Pos: 389
Relay_Log_File: mariadb-relay-bin.000006
Relay_Log_Pos: 557
Relay_Master_Log_File: mariadb-bin.000004
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: 389
Relay_Log_Space: 868
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: 81
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: 0
Slave_Non_Transactional_Groups: 0
Slave_Transactional_Groups: 0
1 row in set (0.000 sec)
MariaDB [mysql]>
#master1
MariaDB [(none)]> show master logs;
+--------------------+-----------+
| Log_name | File_size |
+--------------------+-----------+
| mariadb-bin.000001 | 585 |
| mariadb-bin.000002 | 438 |
| mariadb-bin.000003 | 702 |
| mariadb-bin.000004 | 389 |
+--------------------+-----------+
4 rows in set (0.000 sec)
在master2上操作:
MariaDB [(none)]> show master logs;
+--------------------+-----------+
| Log_name | File_size |
+--------------------+-----------+
| mariadb-bin.000001 | 585 |
| mariadb-bin.000002 | 438 |
| mariadb-bin.000003 | 702 |
| mariadb-bin.000004 | 389 |
+--------------------+-----------+
4 rows in set (0.000 sec)
MariaDB [(none)]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.1.82
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mariadb-bin.000002
Read_Master_Log_Pos: 330
Relay_Log_File: mariadb-relay-bin.000004
Relay_Log_Pos: 631
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: 330
Relay_Log_Space: 1243
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: 82
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: 0
Slave_Non_Transactional_Groups: 0
Slave_Transactional_Groups: 0
1 row in set (0.000 sec)
MariaDB [(none)]>
我这里好了,老师的还有问题。
我跟着老师重新再做下:
#master1。停服务器,删除配置信息
MariaDB [(none)]> stop slave;
Query OK, 0 rows affected (0.001 sec)
MariaDB [(none)]> reset slave all;
Query OK, 0 rows affected (0.000 sec)
MariaDB [(none)]> show slave status\G
Empty set (0.000 sec)
#重新建立复制关系
CHANGE MASTER TO
MASTER_HOST='192.168.1.82',
MASTER_USER='repluser',
MASTER_PASSWORD='123456',
MASTER_PORT=3306,
MASTER_LOG_FILE='mariadb-bin.000002',
MASTER_LOG_POS=330;
MariaDB [(none)]> CHANGE MASTER TO
-> MASTER_HOST='192.168.1.82',
-> MASTER_USER='repluser',
-> MASTER_PASSWORD='123456',
-> MASTER_PORT=3306,
-> MASTER_LOG_FILE='mariadb-bin.000002',
-> MASTER_LOG_POS=330;
Query OK, 0 rows affected (0.003 sec)
MariaDB [(none)]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State:
Master_Host: 192.168.1.82
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mariadb-bin.000002
Read_Master_Log_Pos: 330
Relay_Log_File: mariadb-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File: mariadb-bin.000002
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: 330
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: 82
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;
Query OK, 0 rows affected (0.001 sec)
MariaDB [(none)]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.1.82
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mariadb-bin.000002
Read_Master_Log_Pos: 330
Relay_Log_File: mariadb-relay-bin.000002
Relay_Log_Pos: 557
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: 330
Relay_Log_Space: 868
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: 82
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: 0
Slave_Non_Transactional_Groups: 0
Slave_Transactional_Groups: 0
1 row in set (0.000 sec)
MariaDB [(none)]>
可以看到,这会彻底好了,符合预期。
此时,完成了双主的配置。
测试
master2:
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| db1 |
| db2 |
| hellodb |
| information_schema |
| mysql |
| performance_schema |
+--------------------+
6 rows in set (0.000 sec)
MariaDB [(none)]> create database db3;
Query OK, 1 row affected (0.000 sec)
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| db1 |
| db2 |
| db3 |
| hellodb |
| information_schema |
| mysql |
| performance_schema |
+--------------------+
7 rows in set (0.000 sec)
MariaDB [(none)]>
#master1验证
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| db1 |
| db2 |
| db3 |
| hellodb |
| information_schema |
| mysql |
| performance_schema |
+--------------------+
7 rows in set (0.000 sec)
MariaDB [(none)]>
同理可测试mater1-->master2的效果。
如果出现两边数据库不一致情况,该怎么办呢?
笨方法2:重新来一遍。
办法2:把其中1台临时关闭二进制日志,然后手动创建,再开启二进制日志。
验证下那个id问题
在master1:
#创建一个测试表
use hellodb;
MariaDB [hellodb]> create table test(id int auto_increment primary key,name char(10));
Query OK, 0 rows affected (0.002 sec)
因为复制关系,另一台机器上这个表也被复制过来了:
#master1
MariaDB [hellodb]> show tables;
+-------------------+
| Tables_in_hellodb |
+-------------------+
| classes |
| coc |
| courses |
| scores |
| students |
| teachers |
| test |
| toc |
+-------------------+
8 rows in set (0.000 sec)
MariaDB [hellodb]> select *from test;
Empty set (0.000 sec)
#master2
MariaDB [(none)]> 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]> show tables;
+-------------------+
| Tables_in_hellodb |
+-------------------+
| classes |
| coc |
| courses |
| scores |
| students |
| teachers |
| test |
| toc |
+-------------------+
8 rows in set (0.000 sec)
MariaDB [hellodb]> select *from test;
Empty set (0.000 sec)
在master1插入信息:
MariaDB [hellodb]> insert test(name)values('a');
Query OK, 1 row affected (0.001 sec)
MariaDB [hellodb]> select *from test;
+----+------+
| id | name |
+----+------+
| 1 | a |
+----+------+
1 row in set (0.000 sec)
#当然master2上数据也过来了
MariaDB [hellodb]> select *from test;
+----+------+
| id | name |
+----+------+
| 1 | a |
+----+------+
1 row in set (0.000 sec)
在master2插入信息:
MariaDB [hellodb]> insert test(name)values('b');
Query OK, 1 row affected (0.001 sec)
MariaDB [hellodb]> select *from test;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
+----+------+
2 rows in set (0.000 sec)
#当然master1上数据也过来了
MariaDB [hellodb]> select *from test;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
+----+------+
2 rows in set (0.000 sec)
模拟2个人同时干:(利用xshell同时给2个终端发送一条相同的命令)
insert test(name)values('c');
都让你成功,错峰解决。
请问这个的结果呢?(是奇数)
#master1上执行
MariaDB [hellodb]> insert test(name)values('d'),('e'),('f');
Query OK, 3 rows affected (0.001 sec)
Records: 3 Duplicates: 0 Warnings: 0
MariaDB [hellodb]> select *from test;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
| 3 | c |
| 4 | c |
| 5 | d |
| 7 | e |
| 9 | f |
+----+------+
7 rows in set (0.000 sec)
MariaDB [hellodb]>
#master2
MariaDB [hellodb]> select *from test;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
| 3 | c |
| 4 | c |
| 5 | d |
| 7 | e |
| 9 | f |
+----+------+
7 rows in set (0.000 sec)
MariaDB [hellodb]>
master2上:(是偶数)
MariaDB [hellodb]> insert test(name)values('dd'),('ee'),('ff');
Query OK, 3 rows affected (0.001 sec)
Records: 3 Duplicates: 0 Warnings: 0
MariaDB [hellodb]> select *from test;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
| 3 | c |
| 4 | c |
| 5 | d |
| 7 | e |
| 9 | f |
| 10 | dd |
| 12 | ee |
| 14 | ff |
+----+------+
10 rows in set (0.000 sec)
MariaDB [hellodb]>
#master1
MariaDB [hellodb]> select *from test;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
| 3 | c |
| 4 | c |
| 5 | d |
| 7 | e |
| 9 | f |
| 10 | dd |
| 12 | ee |
| 14 | ff |
+----+------+
10 rows in set (0.000 sec)
结论:
这个id只会往上涨,不会给你塞缝里。😂
自己可以填坑:
MariaDB [hellodb]> insert test values(6,'x');
Query OK, 1 row affected (0.001 sec)
MariaDB [hellodb]> select *from test;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
| 3 | c |
| 4 | c |
| 5 | d |
| 6 | x |
| 7 | e |
| 9 | f |
| 10 | dd |
| 12 | ee |
| 14 | ff |
+----+------+
11 rows in set (0.000 sec)
MariaDB [hellodb]>
结论
双主看起来很美,但实际上有严重的可能产生冲突的情况存在。
例如:我两边同时创建数据库
#master1
MariaDB [hellodb]> create database testdb1;
Query OK, 1 row affected (0.000 sec)
#master2
MariaDB [hellodb]> create database testdb1;
Query OK, 1 row affected (0.001 sec)
复制的时候是异步复制,复制时间间隔很长。
实际使用姿势:
一个当主,一个当从。
配的时候这么配没错,但是用的时候要一主一从这么使用。(读写分离)
The end。
6.2 MySQL 中间件代理服务器
6.3 MySQL高可用
7、性能优化
关于我
我的博客主旨:
- 排版美观,语言精炼;
- 文档即手册,步骤明细,拒绝埋坑,提供源码;
- 本人实战文档都是亲测成功的,各位小伙伴在实际操作过程中如有什么疑问,可随时联系本人帮您解决问题,让我们一起进步!
🍀 微信二维码 x2675263825 (舍得), qq:2675263825。
🍀 微信公众号 《云原生架构师实战》
🍀 个人博客站点
🍀 csdn https://blog.csdn.net/weixin_39246554?spm=1010.2135.3001.5421
🍀 知乎 https://www.zhihu.com/people/foryouone
最后
好了,关于本次就到这里了,感谢大家阅读,最后祝大家生活快乐,每天都过的有意义哦,我们下期见!