01-MySQL数据库

MySQL数据库

目录

一、MySQL的安装

  • 方式一:yum安装
  • 方式二:rpm包安装(需要解决依赖)
  • 方式三:源码安装(安装较慢,安装时间长)
  • 方式四:二进制安装(企业常用安装方式,不挑系统)

1.下载MySQL软件包

2.系统环境准备

  • 操作系统:Centos7.9(3.10.0-1160.119.1.el7.x86_64)
  • 关闭系统安全服务
[root@db01 ~]# systemctl stop firewalld 
[root@db01 ~]# systemctl disable firewalld
[root@db01 ~]# setenforce 0
[root@db01 ~]# sed -i '7s#enforcing#disabled#g' /etc/selinux/config
  • 创建数据库服务管理用户及数据目录
[root@db01 ~]# useradd mysql -M -s /sbin/nologin
[root@db01 ~]# id mysql
uid=1000(mysql) gid=1000(mysql) groups=1000(mysql)

[root@db01 ~]# mkdir -p /data/3306/data
[root@db01 ~]# chown mysql.mysql /data/3306/data
[root@db01 ~]# ll -d  /data/3306/data/
drwxr-xr-x 7 mysql mysql 4096 Feb 20 02:57 /data/3306/data/
  • 卸载系统中默认数据库程序(根据自身系统情况调整)
[root@db01 ~]# rpm -qa|grep mysql
[root@db01 ~]# yum remove -y `rpm -qa|grep mysql`
  • 安装软件所需的程序依赖
[root@db01 ~]# yum install -y libaio-devel

3.数据库程序包安装部署(二进制包)

[root@db01 ~]# cd /usr/local/
[root@db01 ~]# ll mysql-8.0.36-linux-glibc2.12-x86_64.tar.xz 
-rw-r--r-- 1 root root 618056612 Feb 20 10:32 mysql-8.0.36-linux-glibc2.12-x86_64.tar.xz

[root@db01 ~]# tar xf mysql-8.0.36-linux-glibc2.12-x86_64.tar.xz
[root@db01 ~]# ln -s mysql-8.0.36-linux-glibc2.12-x86_64 mysql    
bin/mysql程序命令-mysql 登录数据库 
[root@db01 ~]# vim /etc/profile 
export PATH="$PATH:/usr/local/mysql/bin"
[root@db01 ~]# source /etc/profile
[root@db01 ~]# mysql -V

4.初始化数据库

#确保/data/3306/data 为空(不为空初始化会失败)
[root@db01 ~]# mysqld --initialize-insecure  --user=mysql  --datadir=/data/3306/data  --basedir=/usr/local/mysql
--initialize-insecure  #可以实现不安全初始化  数据库没有默认密码设置(免密登录)
--initialize           #可以实现安全初始化    数据库会有默认密码设置 后续也需要重新设置
--user=mysql           #指定创建数据库默认数据属主和属组 以及指定数据库进程管理用户信息
--datadir              #指定数据库存储和加载数据目录
--basedir              #指定数据库二进制程序目录

5.编写数据库服务配置文件

  • 作用:

​ 可以设置数据库服务功能并使功能永久生效

​ 可以让数据库服务进程加载

[root@db01 ~]# vim /etc/my.cnf
[mysqld] 
user=mysql
basedir=/usr/local/mysql
datadir=/data/3306/data
socket=/tmp/mysql.sock
  • 配置文件详解
[mysqld]     --配置标签信息(服务端配置标签 客户端配置标签) 
user=mysql   --数据库进程用户信息
basedir=/usr/local/mysql   -- 加载程序目录  Linux系统 mysql5.6  mysql5.7 mysql8.0 (多实例)   
datadir=/data/3306/data    -- 加载数据目录
socket=/tmp/mysql.sock     -- 配置连接数据库的socket(客户端命令可以连接访问服务端)

6.启动运行数据库服务

①启动方式

  • 方式一:使用源码包中的脚本文件启动停止
[root@db01 ~]# /usr/local/mysql/support-files/mysql.server 
Usage: mysql.server  {start|stop|restart|reload|force-reload|status}  [ MySQL server options ]

#为了方便使用将脚本文件复制到/etc/init.d/中
[root@db01 ~]# cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld

#使用方式
[root@db01 ~]# /etc/init.d/mysqld start|stop|restart|reload|force-reload|status

  • 方式二:service命令启动数据库服务
service mysqld start
service mysqld stop
  • 方式三:systemctl命令启动数据库服务
systemctl enable mysqld
systemctl start mysqld
systemctl stop mysqld
  • 方式四:编写数据库服务service文件
[root@db01 ~]# cat /usr/lib/systemd/system/mysql.service
[Unit]
Description=Mysql Server
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
ExecStart=/usr/local/mysql/support-files/mysql.server start
ExecStop=/usr/local/mysql/support-files/mysql.server stop
ExecRestart=/usr/local/mysql/support-files/mysql.server restart
[Install]
WantedBy=multi-user.target
[root@db01 ~]# systemctl daemon-reload
[root@db01 ~]# systemctl start mysql.service

②启动日志

cat /data/3306/data/db01.err

二、数据库服务密码管理

1.设置初始密码

  • 注意:如果使用--initialize(安全初始化)会生成一个随机密码

①使用shell命令设置

[root@db01 ~]# mysqladmin -uroot password '密码'

②使用SQL语句设置

[root@db01 ~]# mysql
mysql> alter user root@'localhost' identified by '密码';

2.修改密码信息

①使用shell命令设置

[root@db01 ~]# mysqladmin -uroot -p321321 password '456456'

②使用SQL语句设置

[root@db01 ~]# mysql
mysql> alter user root@'localhost' identified by '密码';

3.重置密码信息(遗忘密码)

①关闭数据库服务

[root@db01 ~]# systemctl stop mysql.service 

②采用安全模式启动数据库(免密登录)

[root@db01 ~]# mysqld --skip-grant-tables --skip-networking  &
--skip-grant-tables   启动数据库不会加载授权表
--skip-networking     启动数据库只会创建进程信息,不会生成网络端口信息

③重置密码信息

img

[root@db01 ~]# mysql
mysql> flush privileges;	-- 重新将磁盘授权表加载到内存中
mysql> alter user root@'localhost' identified by '密码';

④重新正常启动数据库服务

[root@db01 ~]# pkill mysql
[root@db01 ~]# /etc/init.d/mysqld start
[root@db01 ~]# mysql -uroot -p密码

三、数据库服务用户管理

1.创建用户信息

①设置用户主机域/白名单信息方式

  • 语法格式
用户名@'作用域'
  • 作用域格式
##本地访问
localhost		#仅本地可访问
127.0.0.1		#仅本地可访问(效果与localhost相同)

##远程访问
主机名			  #db主机要能解析到
IP地址		   #允许单个IP地址访问
10.0.0.%		
10.0.%	10.%	#允许此网段内访问
%				#允许任意客户端主机连接访问

②创建用户信息

  • 语法格式
create user 用户名@'作用域';						#免密登录
create user 用户名@'作用域' identified by '密码'   #设置密码

③用户登录

本地用户
mysql -uroot -p密码
远程用户
mysql -uroot -p密码 -h数据库服务端地址  -P数据库服务端口

2.查看用户信息

  • 语法格式
用户信息存储在mysql.user表中,我们只查看用户名,作用域,密码
#查看所有用户信息
mysql> select user,host,authentication_string from mysql.user;

#查看当前登录用户信息
mysql> select user();

3.删除用户信息

  • 语法格式
mysql> drop user 用户名@'作用域'

#下方操作慎用,操作不当会造成表内容全部丢失
delete from mysql.user where user='用户名' and host=‘作用域’;

四、数据库服务权限管理

1.查看所有权限

mysql> show privileges;
Delete           Tables						-- 可以删除表中数据  	
Insert           Tables						-- 可以插入数据权限  	
Select           Tables						-- 可以查询表数据信息	
Update           Tables						-- 可以修改表数据信息 	
--------------------------------------------------------
Alter            Tables                  	-- 修改表的属性信息 
Create           Databases,Tables,Indexes	-- 创建数据库和数据表权限
Create user      Server Admin 				-- 可以创建新用户
Drop             Databases,Tables			-- 可以删除库,可以删除表
Grant option     Databases,Tables			-- 可以给别人进行授权的权限
Show databases   Server Admin				-- 可以查看所有数据库信息
Usage            Server Admin				-- 只能登录数据库权限

2.设置用户权限

  • 语法格式
grant 权限01,权限02,权限03..  on 操作对象 to 用户名@'白名单'
  • 操作对象
*.*       	 -- 可以管理所有库,以及库中的所有表
库名.*    	-- 可以管理指定库,以及库中的所有表 
库名.表名      -- 可以管理指定库,以及库中的指定表
  • 针对不同用户设置权限
##针对管理员设置权限:DBA 
grant all on *.* to admin@'localhost';
##针对运维人员设置权限:SA 
grant Alter,Create,Delete,Drop,Insert,Select,Update on www.* to ops@'localhost';
##针对开发人员设置权限:DEV
grant Delete,Insert,Select,Update on www.t1 to dev@'localhost';
  • 版本命令彩蛋
mysql 8.0之前版本:可以利用授权命令进行授权 并创建用户
grant select on *.* name@'localhost' identified by '123456';
mysql 8.0之后版本:授权和用户创建要分开执行 
create user ...
grant 权限 ...

3.查看用户权限

show grants for 用户名@'作用域'

4.撤销用户权限

revoke DROP on 操作对象 from 用户名@'作用域';
revoke DROP on `www`.* from `dev`@`localhost`;

5.用户权限授权表

  • 都存放于mysql库中

①全局授权信息

user表			#用户对所有库所有表的权限信息  全局权限设置

②数据库授权信息

db表				#用户对指定库所有表的权限信息  针对数据库权限设置

③数据表授权信息

tables_priv表	#用户对指定库指定表的权限信息  针对数据表权限设置

五、数据库连接管理

1.数据库连接方法

①本地连接

  • 利用套接字文件(利用本地socket文件) 客户端加载socket文件 =(路径/名称)= 服务端创建socket文件

  • 当客户端加载的sock文件 和 服务端创建sock文件不匹配,应

    • 修改服务端配置信息
    • 调整客户端连接方式(加载的sock信息)
    mysql -uroot -p123123 -S /data/3306/data/mysql.sock
    

②远程连接

  • 利用TCP/IP网络协议
mysql -uroot -p012012 -h 数据库服务端地址  -P 数据服务端端口

2.数据库连接方式

①利用客户端命令进行连接

  • 缺点:命令参数不便于记忆 连接登录后的语句操作没有补全功能

  • 使用mysql命令登录

本地登录: mysql -u用户  -p密码   -S指定套接字文件
远程登录: mysql -u用户  -p密码	 -h数据库服务端地址  -P数据库服务端端口
  • 使用mysqladmin登录更改密码
本地登录:mysqladmin -u用户  -p密码   -S指定套接字文件  password '新密码'
远程登录:mysqladmin -u用户  -p密码	 -h数据库服务端地址  -P数据库服务端端口  password '新密码'
  • 使用mysqldump登录保存、备份数据
本地备份 :mysqldump -u用户  -p密码   -S指定套接字文件 备份参数信息
远程备份 :mysqldump -u用户  -p密码 -h 数据库服务端地址  -P 数据服务端端口 备份参数信息

②利用客户端工具进行连接

1)创建远程用户信息
mysql> create user root@'10.0.0.%' identified by '123456';

#直接授权用户所有权限,默认不会给用户创建用户的权限,需要加with grant option
mysql> grant all on *.* to root@'10.0.0.%' with grant option;

image-20250222154801596

③利用程序代码连接数据库

python    连接数据库驱动-pymysql 
golang    连接数据库驱动-gomysql
java      连接数据库驱动-jar 
php       连接数据库驱动-phpmysql

六、数据库服务配置管理

1.加载数据库配置文件

  • 默认路径信息:
/etc/my.cnf 
/etc/mysql/my.cnf 
/usr/local/mysql/etc/my.cnf 
~/.my.cnf
  • 自定义路径信息:
# 以放在/data/mysql01.conf为例  使用--defaults-file指定加载配置文件
mysqld --defaults-file=/data/mysql01.conf &

这条命令的作用是:
启动 MySQL 数据库服务(mysqld)。
使用 /data/mysql01.conf 文件作为配置文件(而不是默认的配置文件)。
将 mysqld 进程放到后台运行。

2.进程信息

[root@db01 ~]# ps -ef  | grep mysqld
root       5231      1  0 Feb21 ?        00:00:00 /bin/sh /usr/local/mysql/bin/mysqld_safe --datadir=/data/3306/data --pid-file=/data/3306/data/db01.pid


mysql      5372   5231  0 Feb21 ?        00:03:47 /usr/local/mysql/bin/mysqld --basedir=/usr/local/mysql --datadir=/data/3306/data --plugin-dir=/usr/local/mysql/lib/plugin --user=mysql --log-error=db01.err --pid-file=/data/3306/data/db01.pid --socket=/tmp/mysql.sock
  • 主进程:管理进程 管理子进程状态
root       5231      1  0 Feb21 ?        00:00:00 /bin/sh /usr/local/mysql/bin/mysqld_safe --datadir=/data/3306/data --pid-file=/data/3306/data/db01.pid
  • 子进程:工作进程 处理客户端请求(SQL语句请求)
mysql      5372   5231  0 Feb21 ?        00:03:47 /usr/local/mysql/bin/mysqld --basedir=/usr/local/mysql --datadir=/data/3306/data --plugin-dir=/usr/local/mysql/lib/plugin --user=mysql --log-error=db01.err --pid-file=/data/3306/data/db01.pid --socket=/tmp/mysql.sock

3.编写数据库配置文件

  • 配置文件中主要通过设置标签来定义配置,标签用[]定义

  • 标签信息的类型

    • 客户端标签

      • [client](全局定义)
      • [mysql][mysqladmin][mysqldump](局部定义)
    • 服务端标签

      • [server](全局定义)
      • [mysqld][mysqld_safe] (局部定义)
  • 标签中的配置项

    • 使用 便签名 --help 获取标签选项信息

七、数据库服务实例应用

1.功能作用

  • 提高数据库高可用能力
  • 可以提高数据库安全性
  • 便于对数据库进行监控
  • 可以减少企业运营成本

2.同版本构建多实例

  • 多实例规划(三个)
主机IP 端口 数据库目录 配置文件 套接字文件
10.0.0.51 3306 /data/3306/data /data/3306/my3306.cnf /tmp/mysql3306.sock
10.0.0.51 3307 /data/3307/data /data/3307/my3307.cnf /tmp/mysql3307.sock
10.0.0.51 3308 /data/3308/data /data/3308/my3308.cnf /tmp/mysql3308.sock

①进行多实例数据库目录初始化

#创建数据库目录
[root@db01 ~]# mkdir -p /data/3306/data
[root@db01 ~]# mkdir -p /data/3307/data
[root@db01 ~]# mkdir -p /data/3308/data
[root@db01 ~]# chown -R  mysql.mysql /data/

#进行服务初始化
[root@db01 ~]# mysqld --initialize-insecure --user=mysql --datadir=/data/3306/data --basedir=/usr/local/mysql 
[root@db01 ~]# mysqld --initialize-insecure --user=mysql --datadir=/data/3307/data --basedir=/usr/local/mysql
[root@db01 ~]# mysqld --initialize-insecure --user=mysql --datadir=/data/3308/data --basedir=/usr/local/mysql

②写多实例配置文件

#3306实例
[root@db01 ~]# vim /data/3306/my3306.cnf
port=3306
user=mysql
basedir=/usr/local/mysql
datadir=/data/3306/data
socket=/tmp/mysql3306.sock

#3307实例
[root@db01 ~]# vim /data/3307/my3307.cnf
[mysqld] 
port=3307
user=mysql
basedir=/usr/local/mysql
datadir=/data/3307/data
socket=/tmp/mysql3307.sock

#3308实例
[root@db01 ~]# vim /data/3308/my3308.cnf
[mysqld] 
port=3308
user=mysql
basedir=/usr/local/mysql
datadir=/data/3308/data
socket=/tmp/mysql3308.sock

③运行启动多实例服务

[root@db01 ~]# mysqld --defaults-file=/data/3306/my3306.cnf &
[root@db01 ~]# mysqld --defaults-file=/data/3307/my3307.cnf &
[root@db01 ~]# mysqld --defaults-file=/data/3308/my3308.cnf &

④查看端口号,多实例是否启动

[root@db01 ~]# netstat  -tnulp | grep mysql
tcp6       0      0 :::3306      :::*      LISTEN      31871/mysqld        
tcp6       0      0 :::3307      :::*      LISTEN      31462/mysqld        
tcp6       0      0 :::3308      :::*      LISTEN      31526/mysqld

⑤指定套接字文件尝试登录

[root@db01 ~]# mysql -S/tmp/mysql3306.sock
[root@db01 ~]# mysql -S/tmp/mysql3307.sock 
[root@db01 ~]# mysql -S/tmp/mysql3308.sock

3.不同版本构建多实例

①下载、安装、初始化

#下载
https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.36-linux-glibc2.12-x86_64.tar.gz
https://downloads.mysql.com/archives/get/p/23/file/mysql-5.6.42-linux-glibc2.12-x86_64.tar.gz

[root@db-01 local 08:40]# ll mysql-5.6.48-linux-glibc2.12-x86_64.tar.gz 
-rw-r--r-- 1 root root 343082156 Oct 27  2022 mysql-5.6.48-linux-glibc2.12-x86_64.tar.gz
[root@db-01 local 08:40]# ll mysql-5.7.30-linux-glibc2.12-x86_64.tar.gz 
-rw-r--r-- 1 root root 660017902 Oct 27  2022 mysql-5.7.30-linux-glibc2.12-x86_64.tar.gz
#安装
tar xf mysql-5.6.48-linux-glibc2.12-x86_64.tar.gz
tar xf mysql-5.7.30-linux-glibc2.12-x86_64.tar.gz

ln -s mysql-5.6.48-linux-glibc2.12-x86_64 mysql56 
ln -s mysql-5.7.30-linux-glibc2.12-x86_64 mysql57 

#初始化
mkdir -p /data/3356/data && chown mysql.mysql /data/3356/data
mkdir -p /data/3357/data && chown mysql.mysql /data/3357/data

/usr/local/mysql56/scripts/mysql_install_db --user=mysql --datadir=/data/3356/data --basedir=/usr/local/mysql56   
/usr/local/mysql57/bin/mysqld --initialize-insecure --user=mysql --datadir=/data/3357/data --basedir=/usr/local/mysql57

②编写数据库服务配置文件

cat >/data/3356/my.cnf<<EOF
[mysqld]
port=3356
user=mysql 
basedir=/usr/local/mysql56
datadir=/data/3356/data
socket=/tmp/mysql3356.sock 
EOF 

cat >/data/3357/my.cnf<<EOF
[mysqld]
port=3357
user=mysql 
basedir=/usr/local/mysql57
datadir=/data/3357/data
socket=/tmp/mysql3357.sock 
EOF

③启动运行不同版本多实例

cat>/etc/systemd/system/mysql56.service<<EOF
[Unit]
Description=MySQL Server
Documentation=man:mysqld(8)
Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
After=network.target
After=syslog.target

[Install]
WantedBy=multi-user.target

[Service]
User=mysql
Group=mysql
ExecStart=/usr/local/mysql56/bin/mysqld --defaults-file=/data/3356/my.cnf
LimitNOFILE=5000
EOF

cat>/etc/systemd/system/mysql57.service<<EOF
[Unit]
Description=MySQL Server
Documentation=man:mysqld(8)
Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
After=network.target
After=syslog.target

[Install]
WantedBy=multi-user.target

[Service]
User=mysql
Group=mysql
ExecStart=/usr/local/mysql57/bin/mysqld --defaults-file=/data/3357/my.cnf
LimitNOFILE=5000
EOF

systemctl daemon-reload 
systemctl start mysql56
systemctl start mysql57

八、数据库服务SQL语句分类

  • **数据库主要使用 SQL语句(Structured Query Language)具有循环语句 判断语句功能 -- 数据库存储过程(数据库中的脚本) **

1.DDL语句(定义)

  • 数据定义语句 Data Definition Language
create:创建数据库 创建数据表 创建索引信息 
alter :修改数据库属性信息(字符集 校对规则)  修改数据表属性信息(字符集 校对规则 表结构-列名 数据类型 约束属性 索引 引擎? 名称)
drop  :删除数据库 删除数据表(磁盘层面删除数据) 慎用
show  :做以上操作的查看确认

1)数据库管理操作语句CADU

①创建库

CREATE DATABASE db_name;  
CREATE SCHEMA db_name;

#设置字符集和校对规则
CREATE DATABASE db_name CHARACTER SET charset_name COLLATE collation_name; 

②修改库

alter  DATABASE db_name CHARACTER SET charset_name COLLATE collation_name;

③删除库

drop database db_name;  
注意:逻辑上是把数据库信息删除了 | 物理上是包数据库目录和数据表文件从磁盘上删除了   慎用

④切换库

use db_name;
use db_name.tb_name;

2)数据表管理操作语句

①创建表

create table 表名 (
    字段名 数据类型 约束 属性,
    字段名 数据类型 约束 属性,索引设置
) 引擎设置 字符集 校对规则

e.g:
CREATE TABLE student (
  id INT NOT NULL AUTO_INCREMENT,
  name VARCHAR(10) NOT NULL,
  mobile num CHAR(11) NOT NULL DEFAULT '未知',
  PRIMARY KEY (`id`),
  UNIQUE INDEX `mobile num_UNIQUE` (`mobile num` ASC) VISIBLE)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_bin;

②修改表

1)修改表名
ALTER TABLE oldname RENAME TO  newname;
rename table newname to oldname;

2)修改字符集/校对规则 
ALTER TABLE tb_name  CHARACTER SET gbk , COLLATE gbk_chinese_ci ;

3)修改表字段信息
添加新的字段:
#添加的列在表中所有字段最后面  默认添加到最后边
ALTER TABLE table_name ADD COLUMN 字段名 数据类型 约束 属性;
#添加的列在表中指定列后面   after
ALTER TABLE table_name ADD COLUMN 字段名 数据类型 约束 属性 AFTER `字段名`;  
#添加的列在表中首行   first
ALTER TABLE table_name ADD COLUMN 字段名 数据类型 约束 属性 first;

③修改原有字段

1)修改字段名称
ALTER TABLE table_name CHANGE COLUMN old_column_name new_column_name 约束属性信息;
注意:修改字段名称也要添加其原有的约束属性信息

2)修改字段数据类型 属性 约束 
ALTER TABLE table_name CHANGE COLUMN column_name  约束属性信息;
e.g:
ALTER TABLE student CHANGE COLUMN age CHAR(3) NULL DEFAULT '20' ,ADD UNIQUE INDEX `age_UNIQUE` (`age` ASC) VISIBLE;

3)删除已有字段:
ALTER TABLE table_name DROP COLUMN column_name;

④删除表

1)表和数据都删除		---将磁盘中的表文件删除,删除后会释放磁盘空间
drop table 表名;

2)只删除表中数据		---清空数据表
truncate 表名;		效率快;可以释放磁盘空间;会清空自增序列	(常用)
delete from 表名;		效率慢;无法释放磁盘空间(标记删除);不会重置自增序列

⑤查看表的结构和属性

#获取创建表语句 从而了解表的结构 表的引擎和字符集/校对规则 还有注释信息		更详细
show create table table_name;

#获取表结构 数据类型 约束属性设置
desc table_name;

#查看表的详细索引设置
show index from table_name;

3)数据库的别名设置/视图设置

①表别名设置
  • 语法格式
SELECT a.id, a.name, b.order_date
FROM customers AS a					#将customers表设置别名为a
JOIN orders AS b					#将orders表设置别名为 b	这两处的AS均可省略
ON a.id = b.customer_id;
  • 示例
select a.tno,a.tname,b.cname,group_concat(d.sno)from teacher as a 
   join course b 
   on a.tno=b.tno 
   join sc c 
   on b.cno=c.cno 
   join student d 
   on c.sno=d.sno 
   where c.score<60
   group by a.tno,b.cname
②列别名设置
  • 语法格式
SELECT customer_name AS 'Customer Name'
FROM customers;
  • 示例
select a.tno as '讲师编号',a.tname as '讲师名字',b.cname as '课程名称',group_concat(d.sno) as '学生学号',group_concat(d.sname) as '学生姓名' from teacher as a 
   join course b 
   on a.tno=b.tno 
   join sc c 
   on b.cno=c.cno 
   join student d 
   on c.sno=d.sno 
   where c.score<60
   group by a.tno,b.cname;
③视图设置
  • 语法设置
CREATE VIEW view_name AS
SELECT column1, column2, ...
FROM table_name
WHERE condition;
  • 示例
   create view stunde_fail as select a.tno as '讲师编号',a.tname as '讲师名字',b.cname as '课程名称',group_concat(d.sno) as '学生学号',group_concat(d.sname) as '学生姓名' from teacher as a 
   join course b 
   on a.tno=b.tno 
   join sc c 
   on b.cno=c.cno 
   join student d 
   on c.sno=d.sno 
   where c.score<60
   group by a.tno,b.cname;
   
   select * from stunde_fail;

2.DCL语句(控制)(三、四)

  • 数据控制语句 Data Control Language
grant: 授权权限信息
revoke:回收权限信息
create user:创建用户  
alter user: 修改用户
commit:  操作提交语句  -- 数据库事务知识
rollback:操作回滚语句  -- 数据库事务知识

3.DML语句(操作)

  • 数据操作语句 Data Manipulation Language

1)数据表相关数据管理

  • 运维人员:插入数据 修改数据 删除数据 查询数据
  • 开发人员:CRUD(create=创建数据-注册 read=读取数据-登录 update=修改数据-信息调整 delete=删除数据-订单信息删除)

2)插入数据 insert

①标准插入方式

insert into 表名 (列名01,列名02...) values (值01,值02,....)

②简单插入方式

#若表中具有自增列 默认值的列 可以为空的列 都可以忽略插入
insert into 表名 (列名01,列名02...) values (值01,值02,....)
#假设第一列为自增列
insert into city values (0,值01,值02,....);

③批量插入方式

insert into city values (0,值01,值02,....),(0,值01,值02,....);

3)修改数据 update

update 表名 set 列名01=值01,列名02=值02 where 条件表达式
PS:如果update不加where进行修改,表示对全表所有行数据进行修改
e.g:	update city set name='ding',district='sex' where id=4085;

4)删除数据 delete

delete from city where 条件表达式
PS:如果delete不加where进行删除,表示对全表所有行数据进行删除

4.DQL语句(查询)

  • 数据查询语句 Data Query Language
查看表中的数据  select 
查看单表数据信息 select + from + where + group by + having + order by + limit  
查看多表数据信息 select + join on + union all 
其他信息查看
查看数据库变量信息(内置变量-状态变量 功能变量)
查看数据库函数信息(获取特定数据)
https://dev.mysql.com/doc/refman/8.4/en/indexes.html

1)单表查询数据

①全表数据查询
select * from 表名;        -- 整个表数据都加载,需要对磁盘性能消耗更多
select 列名1,列名2 from 表名 -- 指定列信息全部显示
②条件查询数据 where
select */列名称 from 表名 where 条件表达式

以官网给出的测试库为例,创建测试数据:https://dev.mysql.com/doc/index-other.html

mysql -uroot -p123123  <./world.sql
mysql> desc city;
+-------------+----------+------+-----+---------+----------------+
| Field       | Type     | Null | Key | Default | Extra          |
+-------------+----------+------+-----+---------+----------------+
| ID          | int      | NO   | PRI | NULL    | auto_increment |    id主键列 序号
| Name        | char(35) | NO   |     |         |                |    城市信息 
| CountryCode | char(3)  | NO   | MUL |         |                |    国家编码 
| District    | char(20) | NO   |     |         |                |    省份信息
| Population  | int      | NO   |     | 0       |                |    人口数量 
+-------------+----------+------+-----+---------+----------------+
条件表达式写法
  • 等值查询数据
select * from 表名 where 列名='字段';
#查询中国的所有城市信息
select * from city where CountryCode='CHN';
  • 范围查询数据
select * from 表名 where 列名<num;
#范围的表示方式:< > <= >=   <> | !=不等于
#查询全世界所有城市信息,人口数量小于10000;
select * from city where Population<10000;
  • 多条件查询数据(and / or)
and:根据第一个条件先进行筛选过滤,然后将筛选后的结果在交给第二条件进行筛选过滤
or: 根据第一个条件先进行筛选过滤,然后在经过第二个条件重新筛选过滤,将两个条件筛选后的数据做合并
#查询中国的所有城市信息,并且人口数量小于100000;
select * from city where CountryCode='CHN' and Population<100000
#查询美国和中国所有城市信息
select * from city where CountryCode='CHN' or CountryCode='USA';
#查询中国所有城市信息,并且人口数量小于100000,再查询美国所有城市信息,并且人口数量大于1000000;
select * from city where CountryCode='CHN' and Population<100000 or CountryCode='USA' and Population>1000000;
  • 使用in / not in /between and 代替多条件查询
select * from 表名 where 列名 in (字段1,字段2);
select * from 表名 where 列名 not in (字段1,字段2);
select * from 表名 where 列名 between num1 and num2;
e.g.
#查询美国和中国所有城市信息
select * from city where CountryCode in ('CHN','USA');
select * from city where CountryCode not in ('CHN','USA');
#查询全世界的所有城市信息,并且人口数量小于100000,但是大于10000;
select * from city where population between 10000 and 100000;
③特殊方式查询 like
  • 匹配查询
select * from 表名 where 列名 like  '字符串%'  #查找此列中以字符串开头的行
  • 去重查询
select count(Distinct 列名) from 表名 where 列名='字段';
#Distinct为去重函数,count为统计个数的函数
  • 查看空字段信息
select * from 表名 where 列名 is null;   
select * from 表名 where 列名 is not null;  
④分组查询数据 group by

实现分组查询的步骤:

  • 指定分组查询的列
  • 将分组列相同信息做排序
  • 将排序后相同行信息进行合并

示例:

#查询统计每个国家的人口总数  
select CountryCode,sum(population) from city group by CountryCode;
#查询中国每个省份的城市数量 
select District,count(name) from city where CountryCode='CHN' group by District;
#查询中国每个省份的城市数量,并且显示对应城市信息
select District,count(name),group_concat(name) from city where CountryCode='CHN' group by District;

扩展说明:

1)聚合函数
count()   -- 做计数统计函数(统计行数)
sum()     -- 对数值列进行求和
max()     -- 取出指定数值列最大值
min()     -- 取出指定数值列最小值
avg()     -- 取出指定数值列平均值 sum()/count()
group_concat -- 将多行信息整合为一行显示
2)sql_mode配置项 
保证数据库录入数据和显示数据的合理性
⑤聚合过滤查询 having
  • where : 根据条件信息过滤数据 指定过滤数据表中有的数据 不识别聚合函数
  • having : 根据条件信息过滤数据 过滤聚合处理的数据信息,在表中并不存在 支持识别聚合函数

示例:

#查询中国每个省份城市数量,并且将城市数量大于10的省份显示
select District,count(name) from city where CountryCode='CHN'  group by District having count(name)>10;
#查询全世界各个国家人口数量,并且将人口数量大于500w国家显示输出
select countrycode,sum(population) from city group by countrycode  having sum(population)>5000000;
⑥排序查询数据 order by
  • desc(descending order) -- 降序排序
  • asc (ascending order) -- 升序排序 默认

示例:

#查询全世界各个国家人口数量,并且将人口数量大于500w国家显示输出,将国家人口数量进行排序显示
select countrycode,sum(population) from city group by countrycode  having sum(population)>5000000 order by sum(population);
-- 默认order by采用升序排序
select countrycode,sum(population) from city group by countrycode  having sum(population)>5000000 order by sum(population) desc;
-- 可以利用desc实现降序排序
⑦截取数据信息 limit

语法格式

limit n;		   --- 取前n行
limit n,m;         --- n表示从第几行后开始截取,m表示截取几行信息
limit n offset m;  --- n表示截取几行信息,m表示从第几行开始截取

示例:

#查询全世界各个国家人口数量,并且将人口数量大于500w国家显示输出,将国家人口数量进行排序显示,显示人口数量最多的前5名国家信息  
select countrycode,sum(population) from city group by countrycode  having sum(population)>5000000 order by sum(population) desc limit 5;

2)多表查询数据(连表查询数据)

  • 创建测试数据
创建测试数据表
create database school;

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

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

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

CREATE TABLE teacher (
    tno INT NOT NULL PRIMARY KEY COMMENT '教师编号',
    tname VARCHAR(20) NOT NULL COMMENT '教师名字'
) ENGINE=INNODB CHARSET=utf8;

# 在数据库与数据表中插入模拟数据
INSERT INTO student(sno,sname,sage,ssex)
VALUES
(1,'zhang3',18,'m'),
(2,'zhang4',18,'m'),
(3,'li4',18,'m'),
(4,'wang5',19,'f'),
(5,'zh4',18,'m'),
(6,'zhao4',18,'m'),
(7,'ma6',19,'f'),
(8,'dezyan',20,'m'),
(9,'oldgirl',20,'f'),
(10,'oldp',25,'m');

INSERT INTO teacher(tno,tname)
VALUES
(101,'dezyan'),
(102,'xiaoQ'),
(103,'xiaoA'),
(104,'xiaoB');

INSERT INTO course(cno,cname,tno)
VALUES
(1001,'linux',101),
(1002,'python',102),
(1003,'mysql',103),
(1004,'go',105);

INSERT INTO sc(sno,cno,score)
VALUES
(1,1001,80),
(1,1002,59),
(2,1002,90),
(2,1003,100),
(3,1001,99),
(3,1003,40),
(4,1001,79),
(4,1002,61),
(4,1003,99),
(5,1003,40),
(6,1001,89),
(6,1003,77),
(7,1001,67),
(7,1003,82),
(8,1001,70),
(9,1003,80),
(10,1003,96);
①笛卡尔乘积方式进行多表连接
#直接将两表拼接,没有逻辑性关系性可言
mysql> select * from teacher,course;
②内连接方式,实现多表拼接
#当两表的tno列相同,拼接成一个表
select * from teacher,course where teacher.tno=course.tno;
#使用inner join   on	拼接多个数据表更简单
select * from teacher inner join course on teacher.tno=course.tno;
--多个数据使用可使用多次join …… on
③外连接方式,实现多表拼接 (索引应用有关)
  • 定义驱动表(主表),在定义被驱动表(子表)

    ​ 左外连接:左边为驱动表,右边为被驱动

    ​ 右外连接:右边为驱动表,左边为被驱动

  • 驱动表所有数据信息都要显示,被驱动和驱动有关联数据要显示,无关联数据用null填充

  • 左外连接

左侧表的tno有值的一列全部显示
select * from teacher left join course on teacher.tno=course.tno;
  • 右外连接
select * from teacher right join course on teacher.tno=course.tno;
④多表拼接的两种方式
  • **方式一:横向拼接 当调取数据出自多张表 ** 使用join
  • 方式二:纵向拼接 可以将多个相同数据表做合并 使用union
一个大表生成时,会将大表进行拆分(可以增加并发量 可以减少磁盘IO消耗)
student_2024 + student_2025  纵向 
select * from student union select * from student02;         -- 拼接完信息,若有重复情况 会取重显示
select * from student union all select * from student02;     -- 拼接完信息, 所有行信息都会显示,包含重复信息

3)特殊信息查询

①变量查询
  • 分类:

​ 状态变量:不能进行改动配置,只能用于查看(可以配合监控平台 监控数据运行情况)

​ 系统变量:可以进行改动配置,会影响数据功能和性能

  • 查看方式
show variables                       	-- 查看所有变量
show variables like '匹配变量字段'  	-- 过滤查看指定变量
select @@sql_mode;
  • 设置方式:
临时设置:
set global    变量名=变量值 (字符串加引号 数值不用加引号)  -- 全局设置 (变量设置 会影响所有用户 只有重启数据服务才会还原)
set [session] 变量名=变量值 (字符串加引号 数值不用加引号)  -- 会话设置 (变量设置 会影响当前用户 当会话断开变量设置还原)
永久设置:
在配置文件中添加
②函数查询
  • 查看方式
select 函数();
③数据库中的元数据信息
  • 元数据信息==数据库属性信息
select * from  information_schema.表名\G
  TABLE_CATALOG: def
   TABLE_SCHEMA: school         -- 库名
     TABLE_NAME: student02      -- 表名
     TABLE_TYPE: BASE TABLE
         ENGINE: InnoDB         
        VERSION: 10
     ROW_FORMAT: Dynamic
     TABLE_ROWS: 4              -- 行数
 AVG_ROW_LENGTH: 4096           -- 每行占用磁盘字节量(平均)
    DATA_LENGTH: 16384
MAX_DATA_LENGTH: 0
   INDEX_LENGTH: 0              -- 索引结构占用磁盘情况
      DATA_FREE: 0              -- 数据存储碎片情况
 AUTO_INCREMENT: 5
    CREATE_TIME: 2025-02-25 11:01:43
    UPDATE_TIME: 2025-02-25 11:08:39
     CHECK_TIME: NULL
TABLE_COLLATION: utf8mb3_general_ci
       CHECKSUM: NULL
 CREATE_OPTIONS: 
  TABLE_COMMENT:

4)统计数据库资产信息(数据资产)(面试)

①获取每个库中表的个数和名称信息
#统计有几个数据库服务器;统计数据库实例数量;统计每个实例中有多少数据库 show databases;  统计每个数据库中表信息和数量
 select table_schema,count(*),group_concat(table_name) 
 from information_schema.tables 
 where table_schema not in ('mysql','sys','performance_schema','information_schema') 
 group by table_schema;
+--------------+----------+---------------------------------------+
| TABLE_SCHEMA | count(*) | group_concat(table_name)              |
+--------------+----------+---------------------------------------+
| school       |        5 | course,sc,student,stunde_fail,teacher |
| test01       |        1 | test01                                |
| world        |        3 | city,country,countrylanguage          |
+--------------+----------+---------------------------------------+

②获取每个数据库数据占用磁盘空间
#上一个工作数据库的存储量
select table_schema,sum(table_rows*avg_row_length+index_length)/1024/1024
from information_schema.tables 
where table_schema not in ('mysql','sys','performance_schema','information_schema') 
group by table_schema;
+--------------+-------------------------------------------------------+
| TABLE_SCHEMA | sum(table_rows*avg_row_length+index_length)/1024/1024 |
+--------------+-------------------------------------------------------+
| school       |                                            0.06248379 |
| test01       |                                            0.01562405 |
| world        |                                            0.76261139 |
+--------------+-------------------------------------------------------+
③获取具有碎片信息的表
select table_schema,table_name,data_free 
from information_schema.tables 
where table_schema not in ('mysql','sys','performance_schema','information_schema') and data_free >0 ;
---------------------------------------
table_schema | table_name | data_free |
---------------------------------------

#整理碎片数据表
alter table table_schema.table_name engine=innodb;
#批量整理碎片数据表
select concat("alter table ",table_schema,".",table_name," engine=innodb;") 
from information_schema.tables 
where table_schema not in ('mysql','sys','performance_schema','information_schema') and data_free >0 ;

5)练习

0F8C0EB77D4B705EFAA0CF0535CF5E98

1)统计zhang3,学习了几门课?
解题思路步骤:
a 需要建立多个表的关联模型(E-R模型)
b 根据需求,确认需要查询的数据表 
  student sc course 
c 将多张表信息做拼接(内连接方式) 大表==单表 
  select * from student 
  join sc
  on student.sno=sc.sno
  join course 
  on sc.cno=course.cno;
d 利用大表(单表查询) select+from+where+group by+having+order by+limit 
  select student.sname,count(course.cname) from student 
  join sc
  on student.sno=sc.sno
  join course 
  on sc.cno=course.cno
  where student.sname='zhang3';  

2)查询zhang3,学习的课程名称有哪些?#假设有重名的情况
  select student.sno,student.sname,group_concat(course.cname) from student 
  join sc
  on student.sno=sc.sno
  join course 
  on sc.cno=course.cno
  where student.sname='zhang3'
  group by student.sno; 

3)查询xiaoA老师教的学生名?
  select teacher.tno,teacher.tname,group_concat(student.sname) from teacher
  join course
  on teacher.tno=course.tno
  join sc
  on course.cno=sc.cno
  join student
  on sc.sno=student.sno
  where teacher.tname='xiaoA'
  group by teacher.tno;   
   +-----+-------+---------------------------------------------+
   | tno | tname | group_concat(student.sname)                 |
   +-----+-------+---------------------------------------------+
   | 103 | xiaoA | zhang4,li4,wang5,zh4,zhao4,ma6,oldgirl,oldp |
   +-----+-------+---------------------------------------------+


4)查询xiaoA老师教课程的平均分数?
   select teacher.tno,teacher.tname,course.cname,avg(sc.score) from teacher 
   join course 
   on teacher.tno=course.tno 
   join sc 
   on course.cno=sc.cno
   where teacher.tname='xiaoA'
   group by teacher.tno,course.cno;  
   +-----+-------+-------+---------------+
   | tno | tname | cname | avg(sc.score) |
   +-----+-------+-------+---------------+
   | 103 | xiaoA | mysql |       76.7500 |
   +-----+-------+-------+---------------+

5)每位老师所教课程的平均分,并按平均分排序?
   select teacher.tno,teacher.tname,course.cname,avg(sc.score) from teacher 
   join course 
   on teacher.tno=course.tno 
   join sc 
   on course.cno=sc.cno
   group by teacher.tno,course.cno
   order by avg(sc.score);
   +-----+--------+--------+---------------+
   | tno | tname  | cname  | avg(sc.score) |
   +-----+--------+--------+---------------+
   | 102 | xiaoQ  | python |       70.0000 |
   | 103 | xiaoA  | mysql  |       76.7500 |
   | 101 | dezyan | linux  |       80.6667 |
   +-----+--------+--------+---------------+


6)查询xiaoA老师教的不及格的学生姓名?
   select teacher.tno,teacher.tname,course.cname,group_concat(student.sno),group_concat(student.sname) from teacher 
   join course 
   on teacher.tno=course.tno 
   join sc 
   on course.cno=sc.cno 
   join student 
   on sc.sno=student.sno
   where teacher.tname='xiaoA' and sc.score<60
   group by teacher.tno,course.cname;
   +-----+-------+-------+---------------------------+-----------------------------+
   | tno | tname | cname | group_concat(student.sno) | group_concat(student.sname) |
   +-----+-------+-------+---------------------------+-----------------------------+
   | 103 | xiaoA | mysql | 3,5                       | li4,zh4                     |
   +-----+-------+-------+---------------------------+-----------------------------+

7)查询所有老师所教学生不及格的信息?
   select teacher.tno,teacher.tname,course.cname,group_concat(student.sno),group_concat(student.sname) from teacher 
   join course 
   on teacher.tno=course.tno 
   join sc 
   on course.cno=sc.cno 
   join student 
   on sc.sno=student.sno
   where sc.score<60
   group by teacher.tno,course.cname;
   +-----+-------+--------+---------------------------+-----------------------------+
   | tno | tname | cname  | group_concat(student.sno) | group_concat(student.sname) |
   +-----+-------+--------+---------------------------+-----------------------------+
   | 102 | xiaoQ | python | 1                         | zhang3                      |
   | 103 | xiaoA | mysql  | 3,5                       | li4,zh4                     |
   +-----+-------+--------+---------------------------+-----------------------------+


6)子查询-嵌套查询

select * from (
   select * from t1 where id=(
     select id from t2
   )
   )

九、数据库服务字符设置

1.查看可以设置的编码

mysql> show charset;
#主要使用一下四种
| gb2312   | GB2312 Simplified Chinese       | gb2312_chinese_ci   |      2 |
| gbk      | GBK Simplified Chinese          | gbk_chinese_ci      |      2 |
| utf8mb3  | UTF-8 Unicode                   | utf8mb3_general_ci  |      3 |   
| utf8mb4  | UTF-8 Unicode                   | utf8mb4_0900_ai_ci  |      4 |   
  • utf8mb3 等价于早期的utf8字符编码 可以识别中文信息 每个字符占用3字节
  • utf8mb4 支持utf8mb3的所有以及emoji表情 每个字符占用4字节

2.设置字符编码

  • 修改配置文件
[root@db01 ~]# vim /etc/my.cnf
[mysqld]
#添加一行
character-set-server=utf8mb3
  • 查看字符设置
方式一:
mysql> show create database test01;
……DEFAULT CHARACTER SET utf8mb4……

方式二:
mysql> select @@character_set_server;
+------------------------+
| @@character_set_server |
+------------------------+
| utf8mb3                |
+------------------------+

3.设置校对规则/排序规则

  • 校对规则功能作用
    • 可以实现区分大小写查询数据
    • 可以影响数据显示的默认排序
  • 设置校对规则
show collation; 			#查看所有校对规则信息
utf8mb4_0900_ai_ci   | utf8mb4  | 255 | Yes  | Yes  |  0 | NO PAD   |
ci  	不区分大小写,Case-insensitive的缩写  utf8mb4_0900_ai_ci
cs  	区分大小写,Case-sensitive的缩写      utf8mb4_0900_as_cs
_bin 	采用二进制方式存储,影响数据排序 

#创建方法示例
use test01 
create table t1(info char(3)) charset utf8mb4 collate utf8mb4_0900_ai_ci;
create table t2(info char(3)) charset utf8mb4 collate utf8mb4_0900_as_cs;
create table t3(info char(3)) charset utf8mb4 collate utf8mb4_bin;
-- 创建三个测试数据表,并设置不同校对规则

十、数据库数据类型

  • 创建数据表时,需要对表的列指定数据类型(合理录入数据 控制数据磁盘占用 影响索引应用)

1.数值类型

  • 整数类型
tinyint  	微小整数  1个字节  范围(-128~127)     				范围(0~255)  
smallint 	小型整数  2个字节  范围(-32768~32767)  				范围(0~65535)
mediumint	中型整数  3个字节  范围(-8388608~8388607)			范围(0~16777215)
int         标准整数  4个字节  范围(-2147483648~2147483647)
bigint      大型整数  8个字节  范围(+-9.22*10的18次方)
  • 浮点类型
float    单精度浮点类型  可以保留的小数位最多 6   无论小数位有多少都只会保存6位
double   双精度浮点类型  可以保留的小数位最多 17  无论小数位有多少最多保存17位
decimal  定点数类型      可以自定义
mysql> create table decimal01 (num decimal(20,19));

2.字符类型

char(n)     存储字符范围 最多255个字符     固定长度字符类型(提高数据检索效率) 
varchar(n)  存储字符范围 最多65535个字符   可变长度字符类型(提高磁盘利用率)

3.日期类型

date  		日期类型  		存储年月日
time  		时间类型  		存储小时分钟秒
datetime   	日期时间类型  	存储年月日 小时分钟秒 1000~9999          
timestamp   日期时间类型   	存储年月日 小时分钟秒 1970~2037

十一、数据库数据约束属性

1.约束设置

  • 主键约束(PK primary key)

    • 主键索引 :限制列信息非空且唯一
      CREATE TABLE `xiaoA`.`test01` (
      `id` INT NOT NULL,
      PRIMARY KEY (`id`));
    
  • 唯一约束(UQ unique)

    • 唯一索引:限制列的信息不能重复,但可以输入空值
      ALTER TABLE `xiaoA`.`test01` 
      ADD COLUMN `name` VARCHAR(10) NULL AFTER `id`,
      ADD UNIQUE INDEX `name_UNIQUE` (`name` ASC) VISIBLE;
      ;
    
  • 非空约束(NN not null)

    • 限制列的信息不能为空,但是可以重复
      ALTER TABLE `xiaoA`.`test01` 
      ADD COLUMN `gender` ENUM('男', '女') NOT NULL AFTER `name`;
    
  • 外键约束

    • 当业务功能需要操作多张数据表时,需要控制操作表的顺序
    • 当多张表插入数据和删除数据都会有合理顺序
      create table class(
       id int primary key auto_increment,            		      主键(主表)  
       name varchar(10) not null comment "班级名字,不能为空",   云计算运维班  
       room varchar(10) comment '教室:允许为空'     			  06              
      ) charset utf8;
    
      create table student(
       id int primary key auto_increment,                         01 02
       number char(10) not null unique comment "学号:不能重复",  2406xx
       name varchar(10) not null comment "姓名",                  张三      97 98 26 27
       c_id int,                                                  外键 (子表)       
       foreign key(c_id) references class(id) 
      ) charset utf8;
    
    
      create table class(
       id int primary key auto_increment, 
       name varchar(10) not null comment "班级名字,不能为空",
       room varchar(10) comment '教室:允许为空'        
      ) charset utf8;
    
      create table student(
       id int primary key auto_increment,
       number char(10) not null unique comment "学号:不能重复",
       name varchar(10) not null comment "姓名", 
       c_id int, 
       foreign key(c_id) references class(id) 
      ) charset utf8;
      
      -- 当设置外键约束,插入数据信息时,需要先在主表中插入数据,然后才能在子表中插入对应数据;
      -- 当设置外键约束,删除数据信息时,需要先在子表中删除数据,然后才能在主表中删除对应数据;
    

PS: 以上4种约束信息,其中PK UQ NN约束需要创建表时进行设置,FK约束可以创建表后进行设置

2.属性设置

#系统中的一些默认变量
default          设定默认数据信息,可以实现自动填充
auto_increment   设定数值信息自增,可以实现数值编号自增填充(一般配合主键使用)
comment          设定数据注释信息                                    
unsigned         设定数值信息非负,可以实现数值信息列不能出现负数信息

PS:

  • 自增列自定义起始值
#创表时设置:
CREATE TABLE example (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50),
    AUTO_INCREMENT = 100
);
#创表后设置
alter table example auto_increment=100;
  • 定义自增的间隔数值
#动态设置(该值默认为1)
SET SESSION auto_increment_increment = 100;  -- 当前会话生效
SET GLOBAL auto_increment_increment = 100;   -- 全局生效

#在配置文件中设置
[mysqld]
auto_increment_increment=100
  • sql_mode功能配置作用:保证数据存储和数据调取合理性
#临时配置:
set global sql_mode=配置的项目信息

#永久配置:配置文件中配置
vi /etc/my.cnf 
[mysqld]
sql_mode=配置的项目信息 

#查看sql_mode所有的配置项
show variables like 'sql_mode';
ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
#配置项详解
ONLY_FULL_GROUP_BY:保证在分组查询数据信息时,分组合并的数据,和其他行数据只能一对一显示,不能出现异常显示输出
STRICT_TRANS_TABLES:可以保证数据录入的完整性 日期信息出现不合理情况
NO_ZERO_IN_DATE,NO_ZERO_DATE:在时间类型中,不能出现0000-00-00时间信息
ERROR_FOR_DIVISION_BY_ZERO:保证数据表中数据信息做除法运算时,被除数不能为0;

十二、数据定义语句定义数据库、表规范说明

**数据定义语句定义数据库规范说明:**   
- 创建数据库名称规范:要和业务有关,不要有大写字母(为了多平台兼容),不要数字开头,不要含有系统关键字信息;
- 创建数据库明确字符:创建数据库时明确(显示)的设置字符集信息,为了避免跨平台兼容性与不同版本兼容性问题;
- 删除数据库操作慎用:在对数据库进行删除操作时,一定要经过严格审计后再进行操作,并且数据库普通用户不能有drop权限;

**数据定义语句定义数据表规范说明:**  
- 创建数据表名称规范:要和业务有关(含库前缀),不要有大写字母,不要数字开头,不要含有系统关键字信息,名称不要太长;
- 创建数据表属性规范:属性信息显示设置,引擎选择InnoDB,字符集选择utf8/utf8mb4,表信息添加注释;
- 创建数据列属性规范:名称要有意义,不要含有系统关键字信息,名称不要太长;
- 创建数据类型的规范:数据类型选择合适的、足够的、简短的; 
- 创建数据约束的规范:每个表中必须都要有主键,最好是和业务无关列,实现自增功能,建议每个列都非空(避免索引失效)/加注释
- 删除数据表操作规范:对于普通用户不能具有删表操作,需要操作删表时需要严格审核
- 修改数据表结构规范:在数据库8.0之前,修改数据表结构需要在业务不繁忙时进行,否则会产生严重的锁

十三、数据库服务体系结构

1.基础结构分析

客户端 -(本地/远程)- 服务端
命令 工具 代码 进程/线程

2.逻辑结构/物理结构

字段
数据目录 数据文件.ibd ibd文件中的数据

3.数据库处理SQL语句层次结构

img

  • 服务端、客户端

    -------------------------------------- 服务层

  • 连接器:实现验证,确保会话连接,产生会话线程

​ show full processlist; -- 会话线程数量上限 受max_connections变量控制

  • 分析器:完成SQL语句的语法分析和词法分析

语法分析:判断SQL语句是否存在语法异常情况

​ 例如:

​ 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 'tabll t1' at line 1

词法分析:分析SQL语句类型 -- 确认操作权限 确认操作对象是否存在

​ 例如:

​ 权限异常:

​ ERROR 1142 (42000): SELECT command denied to user 'test02'@'localhost' for table 'user'

​ 对象异常:

​ mysql> select user,host from mysql.users;

​ ERROR 1146 (42S02): Table 'mysql.users' doesn't exist

​ mysql> select user,host from mysqls.user;

​ ERROR 1049 (42000): Unknown database 'mysqls

  • 优化器:根据语句信息进行处理 会选择最优语句处理方案(与索引有关)
    生成多种数据查询方案(解析树):全表扫描 主键索引 其他索引
    根据查询方案进行数据库处理代价成本评估:CPU资源消耗少 MEM资源消耗少 IO资源消耗少
    获取SQL语句执行方案(最优)

  • 执行器:将SQL语句进行处理 执行结果(获取数据引擎中的存储位置--引擎中位置信息)

-----------------------引擎层

  • 引擎层(read io线程/write io线程)数据引擎(innodb myisam) 等同于linux系统中的文件系统(xfs ext4 ext3)

​ 进行数据存储 (磁盘位置点)
​ 进行数据调取 (磁盘调取 -- 内存中 IO消耗)

​ 数据库存储引擎不能直接控制管理硬件磁盘,而是借助CPU,再由CPU控制硬件完成数据处理工作

引擎结构

数据页   (page)   :引擎中最小的数据存储单元		最大16KB
数据区/簇(extent) :包含连续的多个数据页形成数据区 	  最大1MB
数据段   (segment):包含连续的多个数据区形成数据段    表文件大小

十四、数据库服务索引知识

  • 索引的作用:加快数据查询 -- 数据库表数据信息目录

1.索引结构构建方法 (提高数据查询方法)

  • 全表扫描/遍历查询

    • 缺陷:当并发量大 表数据量大时 消耗磁盘IO资源多 导致查询变慢
  • **二叉树结构查询 **

    • 改善:减少磁盘查询数据IO消耗
    • 缺陷:查询数据时,消耗IO量不一致,造成有些数据查询快 有些数据查询慢
  • **B+TREE **

    • 改善:可以保证查询任意数据 消耗IO资源均衡 查询任意数据时间代价成本相等
    • 适合范围数据查询 ,一个数据页加载 == 磁盘中1个IO消耗

img

B+TREE索引结构
根节点(唯一节点)              存储数据范围和指针信息
支节点(多个节点 连续数据页) 	存储数据范围和指针信息
页节点(多个节点 连续数据页) 	用于存储数据信息	     便于范围查询语句页节点之间会有横向指针

2.常见的索引分类方式

①按索引的存储方式

1)聚簇索引方式应用
  • 利用主键列建立索引结构 BTREE结构数据页中会存储每行数据

    • 主要是:将多个簇(区-64个数据页-1M)聚集在一起就构成了所谓聚簇索引,也可以称之为主键索引;

    • 作用:用来组织存储表的数据行信息的,也可以理解为数据行信息都是按照聚簇索引结构进行存储的,即按区分配空间的;

    • 存储:聚簇是多个簇,簇是多个连续数据页(64个),页是多个连续数据块(4个),块是多个连续扇区(8个);

  • 聚簇索引的构建方式

    • 数据表创建时,显示的构建了主键信息(pk),主键(pk)就是聚簇索引; ******
    • 数据表创建时,没有显示的构建主键信息时,会将第一个不为空的UK的列做为聚簇索引;
    • 数据表创建时,以上条件都不符合时,生成一个6字节的隐藏列作为聚簇索引;
  • 应用聚簇索引结构

    • 利用根节点 可以获取主键范围信息 和指针信息 从而调取对应支节点数据页
    • 利用支节点 可以获取主键范围信息 和指针信息 从而调取对应页节点数据页
    • 利用页节点 可以对比查询的主键值 获取最终需要显示的数据行内容

img

2)非聚簇(辅助)索引方式应用
  • 利用指定索引列结构 获取对应主键列信息 在利用主键列进行回表查询 可以获得指定行的完成数据

    • 主要是:主要用于辅助聚簇索引查询的索引,一般按照业务查找条件,建立合理的索引信息,也可以称之为一般索引/普通索引/二级索引;
    • 作用:主要是将需要查询的列信息可以和聚合索引信息建立有效的关联,从而使数据查询过程更高效,节省IO和CPU消耗
    • 存储:调取需要建立的辅助索引列信息,并加上相应主键列的所有信息,存储在特定的数据页中;
  • 辅助索引的构建方式

    • 数据表创建时,显示的构建了一般索引信息(mul),一般索引信息(mul)就是辅助索引;
    • 数据表创建时,没有显示的构建一般索引信息时,在查询检索指定数据信息,会进行全表扫描查找数据;
  • 应用辅助索引结构

    • 利用根节点 可以获取索引列范围信息 和指针信息 从而调取对应支节点数据页
    • 利用支节点 可以获取索引列范围信息 和指针信息 从而调取对应页节点数据页
    • 利用页节点 可以对比查询的索引列值 获取对应的主键信息 在利用主键信息进行回表查询 从而得到完成数据行信息

img

②按索引的用途

  • 注意:当数据表的数据量较多时(上万行),可以创建列的索引;但数据量较少时(小于万行),不用创建索引信息
1)普通索引(一般索引、二级索引)
  • 普通索引是MySQL中的基本索引类型,使用key或index定义,不需要添加任何限制条件(其他关键语句);
  • 应用场景:经常进行条件查询的列,并且此列不具有唯一性 select * from student where name=xxx
  • 查询缺陷:当索引出现多个相同数值信息时,查询过程会造成回表次数过多的情况
2)唯一索引
  • 创建唯一索引的字段允许有NULL值,但需要保证索引对应字段中的值是唯一的
  • 应用场景:字段列是唯一的,并且唯一字段列经常作为条件查询 select * from emp where phone='xxxx'
  • 查询缺陷:如果唯一索引列出现空值信息存储,也会影响查询效率
3)主键索引
  • 主键索引是一种特殊的唯一性索引,用于根据主键自身的唯一性标识每一条记录,主键索引的字段不允许有NULL值
  • 应用场景:每个表中都需要有主键索引,便于利用主键索引查询表中所有数据信息 select * from user where id=xxx
  • 查询缺陷:不便于将主键列作为查询条件列
4)全文索引
  • 全文索引主要用于提高在数据量较大的字段中的查询效率。全文索引和SQL中的LIKE模糊查询类似;
  • 不同的是LIKE模糊查询适合用于在内容较少的文本中进行模糊匹配,全文检索更擅长在大量的文本中进行数据检索。
  • 全文索引只能创建在CHAR、VARCHAR或TEXT类型的字段上。
5)空间索引
  • 空间索引只能创建在空间数据类型的字段上,其中空间数据类型存储的空间数据是指含有位置、大小、形状以及自身分布特征等多方面信息数据;
  • MySQL中的空间数据类型有4中,分别是GEOMETRY、POINT、LINESTRING和POLYGON。
  • 需要注意的是,对于创建空间索引的字段,必须将其声明为NOT NULL。

③按索引的结构

1)单列索引
  • 单列索引指的是在表中单个字段上创建索引,它可以是普通索引、唯一索引或主键索引,只要保证该表索引只对应表中一个字段即可;
2)复合索引(联合索引) 减少回表次数
  • 复合索引指的是在表中多个字段上创建一个索引,并且只有在查询条件中使用了这些字段中的第一个字段时,该索引才会被使用;
  • 例如:在员工表emp的ename和deptno字段上创建一个复合索引,那么只有查询条件中使用了ename字段时,该索引才会被使用。

3.索引的创建方式

①普通索引创建 (MUL)

  • 方式1:在创建表时创建索引
#语法
create table 表名 (字段名1 数据类型 [约束属性信息],...
{index|key} [索引名][索引类型](字段列表));  
#示例
create table test_index01 (id int not null,name char(10) not null,index (name));
  • 方式2:在创建表后再单独创建索引
#语法
create index 索引名 [索引类型] on 数据表名 (字段列表);
#示例
create index name on test_index02 (name);
  • 方式3:修改表信息时创建索引
#语法
alter table 数据表名 add {index|key} [索引名] [索引类型] (字段列表);  
#示例
alter table test_index02 add key (id);

②唯一索引创建 (UNI)

  • 与普通索引创建方法相比,唯一索引创建多了关键字 unique

  • 方式1:在创建表时创建索引

create table 表名 (字段名1 数据类型 [约束属性信息],...
UNIQUE  {index|key} [索引名][索引类型](字段列表));
  • 方式2:在创建表后再单独创建索引
create UNIQUE index 索引名 [索引类型] on 数据表名 (字段列表);
  • 方式3:修改表信息时创建索引
alter table 数据表名 add UNIQUE {index|key} [索引名] [索引类型] (字段列表);

③主键索引创建 (PRI)

  • 主键索引不能创完表后再单独创建
  • 方式1:在创建表时创建索引
#语法
create table 表名 (字段名1 数据类型 [约束属性信息],...
PRIMARY KEY [索引类型](字段列表));  
#示例
create table test_index05 (id int,name char(10),primary key (id));
  • 方式2:修改表信息时创建索引
#语法
alter table 数据表名 add PRIMARY KEY [索引类型] (字段列表);
#示例
alter table test_index06 add primary key (id);

4.查看索引的方式

①desc命令

#语法
desc 表名;
#示例		其中Key列显示索引类型
mysql> create table test_index03 (id int,name char(10),unique index (name));
Query OK, 0 rows affected (0.00 sec)

mysql> desc test_index03;
+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id    | int      | YES  |     | NULL    |       |
| name  | char(10) | YES  | UNI | NULL    |       |
+-------+----------+------+-----+---------+-------+
2 rows in set (0.00 sec)

②show命令

#语法
show index from 表名;
#示例
mysql> show index from test_index03\G
*************************** 1. row ***************************
        Table: test_index03
   Non_unique: 0
     Key_name: name
 Seq_in_index: 1
  Column_name: name
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment: 
Index_comment: 
      Visible: YES
   Expression: NULL
1 row in set (0.00 sec)

输出的列信息解释说明:

img

PS:其中有值得注意的两个字段
  • Sub_part字段

    • 当索引信息中,Sub_part字段不是为null时,表示创建了一个特殊前缀索引;

    • alter table 表 add key (字段名(数值));

    • 前缀索引作用:有效控制索引结构的高度,从而控制扫描索引树时,减少消耗的IO资源

    • 当索引树高度过高时,也会产生大量IO消耗,影响查询数据效率/存储数据效率(建议3-4层 最多不超过5层)

    • 可以将存储到索引页节点的信息进行控制,只存储少量关键信息

  • 总结:前缀索引可以控制索引层次结构,减少索引树高度,从而减少IO消耗

  • Visible字段

    • 用于禁用或启用索引功能,在进行数据表数据批量插入时,可以临时禁用索引功能,提高批量插入数据效率
    • 默认为启用,启用方法为:
    ALTER TABLE 表名 ALTER INDEX 索引名 VISIBLE;
    
    • 禁用方法为:
    ALTER TABLE 表名 ALTER INDEX 索引名 INVISIBLE;
    

5.索引的删除方式

①普通索引删除

alter table 表名 drop index 索引名; 
drop index 索引名 on 数据表名; 

②唯一索引删除

  • 与普通索引删除方式相同
alter table 表名 drop index 索引名;  
drop index 索引名 on 数据表名;

③主键索引删除

alter table 表名 drop primary key;
drop index primary on 数据表名; 

6.数据库索引应用总结

1)数据库索引信息管理由专业人员进行操作;
2)是否创建索引取决于表的数据量
- 基本表中的记录的数据量越多,记录越长,越有必要创建索引。
  创建索引后,查询速度的提升效果会很明显;
  要避免对经常更新的表创建过多的索引,索引中的列也要尽可能少;
- 数据量小的表最好不要使用索引,由于数据较少,查询花费的时间可能比遍历索引的时间还要短,创建索引可能不会产生优化效果
  对经常用于查询的字段应该创建索引,但要避免添加不必要的字段;
3)索引数据量要适度  
- 索引文件占用文件目录和存储空间,因此索引过多会加重系统负担;
- 索引需要自身维护,当基本表的数据增加、删除或修改时,索引也会进行调整和更新,索引文件也要随之变化,以保持与基本表一致;
- 索引过多会影响数据增、删、改的速度;
  索引并非越多越好,一张表中如果有大量的索引,不仅占用磁盘空间,而且还会影响insert、delete、update等操作的性能;
4)避免给表创建索引
- 包含太多重复值的字段;
- 查询中很少被引用的字段;
- 值特别长的字段;
- 查询返回率很高的字段;
- 具有很多NULL值的字段;
- 需要经常增、删、改的字段;
- 记录较少的表;
- 需要频繁、大批量进行数据更新的基本表;

7.数据表访问压力测试(验证数据表索引价值)

  • 表没有索引进行测试
[root@db01 ~]# mysqlslap --defaults-file=/etc/my.cnf --concurrency=10 --iterations=1 --create-schema='dezyan' --query="select * from dezyan.t100w where k2='VWlm'" engine=innodb --number-of-queries=1000 -uroot -p123456 -h10.0.0.51 -verbose

#命令详解
--defaults-file:   需要加载压力测试实例的配置文件 
--concurrency:		模拟高并发访问的数量
--iterations:      并发压力测试的重复次数
--create-schema:   指定数据库信息,表示切换到对应数据库
--query             进行查询压力测试 
--number-of-queries 并发访问的总请求数

#输出结果  用时257秒
Benchmark
	Running for engine rbose
	Average number of seconds to run all queries: 257.327 seconds
	Minimum number of seconds to run all queries: 257.327 seconds
	Maximum number of seconds to run all queries: 257.327 seconds
	Number of clients running queries: 10
	Average number of queries per client: 100

  • 表创建索引后测试
mysql> alter table t100w add key (k1);
mysql> alter table t100w add key (k2);
#输出结果	用时1.4秒,明显快不少
Benchmark
	Running for engine rbose
	Average number of seconds to run all queries: 1.460 seconds
	Minimum number of seconds to run all queries: 1.460 seconds
	Maximum number of seconds to run all queries: 1.460 seconds
	Number of clients running queries: 10
	Average number of queries per client: 100

十五、数据库服务执行计划

  • 功能作用:可以看到优化器进行优化选择后的执行方案信息

1.查看执行计划信息

desc SQL语句    
explain SQL语句
#输出结果
mysql> explain select * from dezyan.t100w where k2='VWlm'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t100w
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 997335
     filtered: 10.00
        Extra: Using where

img

2.执行计划索引类型信息(key)

  • 第七列key输出的内容可能是以下几种

  • 注:本表设置了k1和k2列作为普通索引,其余列都没设

  • ALL:表示全表扫描方式,没用利用索引扫描类型

    • 出现原因:
    #一:查找条件没有应用索引列
    例如:指定了num列作查找
    mysql> explain select * from dezyan.t100w where num='25503'\G
    #二:查询方式应用了匹配查询 匹配条件信息前出现了%字段  注意!是信息前!
    例如:
    mysql> explain select * from dezyan.t100w where k1 like '%QJ';
    #三:查询条件使用的了排除法  使用了not in   或  不等于
    例如:
    mysql> explain select * from dezyan.t100w where k1 not in ('At');
    mysql> explain select * from dezyan.t100w where k1<>'At';
    
  • index - 表示全索引扫描方式,需要将索引树全部遍历,才能获取查询的信息

    • 出现原因:
    #一:扫描查询列设置了辅助索引信息,但是没有基于索引列设置查询条件
    例如:就指定了一列,没有指定具体要查找的信息
    mysql> explain select k1 from dezyan.t100w;
    补充:在数据库中,有一种特殊索引应用:覆盖索引应用 可以避免出现回表情况(配合联合索引应用 确认数据是否存在)
    select k1 from dezyan.t100w where k1='At';  -- 信息确认 不会进行回表查询
    select name from dezyan.t100w where id=001; -- 利用联合索引查询特定数据,可以不用回表查询
    
  • range - 表示范围索引方式,按照索引的区域范围扫描数据,获取查询的数据信息

    • 出现原因:
    #一:找条件是范围信息(> < >= <= between and in or)
    例如:
    explain select * from dezyan.t100w where k1='At' or k1='ft' or k1='kk';
    #二:行模糊配置查询 应用匹配数据方式 字段后出现了%		注意!是字段后!
    例如:
    explain select * from dezyan.t100w where k1 like 'A%';
    
  • **ref - 表示辅助索引等值(常量)查询,精准定义辅助索引的查询条件 **

    • 出现原因:
    #精准查找索引列的一个存在的数据
    mysql> explain select * from dezyan.t100w where k1='At';
    
  • eq_ref - 表示多表连接查询时,被驱动表的连接条件是主键或者唯一键时,获取的数据信息过程;

    • 出现原因:
    desc select city.name, country.name,city.population from city left join country on city.countrycode=country.code;
    
  • const - 表示主键索引等值(常量)查询 (没有回表过程 调用辅助索引结构 可以直接应用聚簇索引)

    • 出现原因:
    #设置id为主键,精确查找主键的数值
    mysql> desc select * from t100w where id=5\G
    
  • system -- 当表中只有一行数据,并且表的引擎设置为myisam,此时查询表数据信息回显示system类型

十六、数据库服务日志管理

1.数据库服务中的日志及其功能作用

  • 错误日志: 数据目录/db-01.err
    • 用于记录客户端连接信息,记录用户登录后的操作行为(SQL语句)
  • 通用日志: 自定义设置
    • 记录数据库服务启动运行状态信息(正常提示信息 错误提示信息) 用于排查数据库运行异常原因
  • 二进制日志:数据目录/binlog
    • 主要记录数据库中的事务信息(DML语句信息 DDL语句信息 DCL语句信息 )
  • 慢查询日志:slow-xx.log
    • 记录在数据库中出现的慢操作的语句,以及没有应用索引的语句

2.创建生成日志信息

  • 建议将日志都放在同一目录下
[root@db01 ~]# mkdir /data/3306/log
[root@db01 ~]# chown mysql.mysql  /data/3306/log

①通用日志

  • 默认不存在 (企业环境一般无需生成)

  • 查看状态

mysql> select @@general_log;
+---------------+
| @@general_log |
+---------------+
|             0 |
+---------------+			输出值为布尔类型,0代表关闭
  • 配置开启
#在my.cnf配置文件中启用,并可以设置日志存放路径
general_log=ON
general_log_file=/data/3306/log/general.log

②错误日志

  • 默认创建
  • 查看状态
mysql> select @@log_error;
+-------------+
| @@log_error |
+-------------+
| ./db01.err  |
+-------------+			输出结果为日志存放路径
  • 修改存放路径
#在my.cnf配置文件设置日志存放路径
log_error=/data/3306/log/error.log

③二进制日志

  • 默认创建 查看需要应用mysqlbinlog命令查看

  • 修改存放路径

log_bin=/data/3306/log/binlog

④慢查询日志

  • 默认不存在
  • 启用:
slow_query_log      			-- 开启慢查询日志功能
slow_query_log_file 			-- 指定慢查询日志路径/名称
long_query_time     			-- 定义超过多长时间执行的语句就是慢查询语句
log_queries_not_using_indexes   -- 当没有走索引的查询语句也要记录到慢查询日志

#在my.cnf中配置,重启数据库生效
vim /data/3306/my3306.cnf
[mysqld]
slow_query_log=1
slow_query_log_file=/data/3306/log/slow.log
long_query_time=0.01
log_queries_not_using_indexes=1

3.二进制日志管理

①如何查看二进制日志

  • 方式一:在数据库中进行查看
mysql> show binary logs;   -- 查看数据库生成哪些二进制日志
mysql> show master status; -- 查看数据库中正在加载的二进制日志
mysql> show binlog events in 'binlog.000002';  -- 查看具体binlog文件中内容

show master status输出信息详解

mysql> show master status\G
*************************** 1. row ***************************
             File: binlog.000014
         Position: 21107179			#可以理解为日志大小/存储事务信息位置点  
     Binlog_Do_DB: 					#设置什么库的语句操作(DDL DML)会记录到binlog  binlog日志进行记录的白名单设置
 Binlog_Ignore_DB: 					#设置什么库的语句操作(DDL DML)不记录到binlog  binlog日志进行记录的黑名单设置
Executed_Gtid_Set: 					#用于给每个事务操作设置一个唯一标识信息

show binlog events in 输出信息详解

mysql>MASTER_LOG_POS=157
*************************** 1. row ***************************
   Log_name: binlog.000002
        Pos: 4				#事件在 binlog 文件中的起始位置偏移量
 Event_type: Format_desc	#表示事件的类型,描述了 binlog 中记录的具体操作。
  Server_id: 1				#表示生成该 binlog 事件的 MySQL 服务器的 ID
End_log_pos: 126			#事件在 binlog 文件中的结束位置偏移量
       Info: Server ver: 8.0.36, Binlog ver: 4
							#事件的详细信息,执行语句
							
注意:
       DDL DCL 语句信息可以正常记录 可以直接在binlog中看到SQL语句
	   DML     语句信息无法正常记录 不能直接在binlog中看到SQL语句
  • 方式二:在命令行中进行查看(mysqlbinlog)
[root@db01 ~]# mysqlbinlog binlog.000002

注意:在binlog文件中查看 DDL DCL是可以明文查看的,文件中看到的DML语句是进行编码转换后的信息

如果要查看具体语句信息,可使用以下命令

[root@db01 ~]# mysqlbinlog --base64-output=decode-rows -vvv  binlog.000002

②binlog的记录格式

  • 查看
mysql> select @@binlog_format;
+-----------------+
| @@binlog_format |
+-----------------+
| ROW             |
+-----------------+
1 row in set, 1 warning (0.00 sec)
  • 类型
ROW 		:行格式进行信息记录    	(RBR)    DML语句不能直接记录
e.g:	INSERT INTO `xiaoC`.`t2`SET @1=2  @2='xiaoB' @3='2025:02:27'

STATEMENT	:语句格式进行信息记录	   	(SBR)    DML语句可以直接记录
e.g:	insert into xiaoC.t1 values (2,'xiaoB',now())

mixed       :混合格式进行信息记录	   	(MBR)
		根据DML语句的应用情况 会自动选择明文 和 编码方式记录
  • 优缺点
ROW(最常用) 
好处:保证数据恢复或者主从同步时,数据信息的一致性  
坏处:DML语句信息不便于阅读

STATEMENT   
好处:DML语句信息便于阅读
坏处:会造成恢复数据或主从同步数据不一致

③应用二进制日志恢复数据

1)创建二进制测试数据
create database xiaoD;
use xiaoD;
create table t1 (id int,name char(10),time datetime);
insert into t1 values (1,'xiaoA',now()),(2,'xiaoB',now());

create database xiaoE;
use xiaoE;
create table t1 (id int,name char(10),time datetime);
insert into t1 values (1,'xiaoC',now()),(2,'xiaoD',now());

2)模拟误操作行为
mysql> drop database xiaoD;

3)查看二进制日志
mysql> show binlog events in 'binlog.000016'\G
*************************** 3. row ***************************
   Log_name: binlog.000016
        Pos: 157				起始点
 Event_type: Anonymous_Gtid
  Server_id: 1
End_log_pos: 234
       Info: SET @@SESSION.GTID_NEXT= 'ANONYMOUS'
*************************** 4. row ***************************
   Log_name: binlog.000016
        Pos: 234
 Event_type: Query
  Server_id: 1
End_log_pos: 345
       Info: create database xiaoD /* xid=2218 */
*************************** 20. row ***************************
   Log_name: binlog.000016
        Pos: 1576
 Event_type: Xid
  Server_id: 1
End_log_pos: 1607				结束点
       Info: COMMIT /* xid=2231 */
恢复数据起始位置:pos 157  --start-position
恢复数据结束位置:pos 1607 --stop-position

4)应用binlog日志信息截取
[root@db01 ~]#mysqlbinlog --start-position=157 --stop-position=1607  /data/3306/data/binlog.000016 >/tmp/xiaoD_bak.sql
[root@db01 ~]# ll /tmp/*.sql
-rw-r--r-- 1 root root 8007 Feb 27 07:55 /tmp/xiaoD_bak.sql

5)进行数据信息恢复
[root@db01 ~]# mysql -uroot -p123123  </tmp/xiaoD_bak.sql
mysql> show databases;
| xiaoD              |

④二进制日志如何进行切割处理

  • 方式一:编写脚本实现日志切割
[root@db01 ~]# mysql -uroot -p123123  -e 'flush logs'
[root@db01 ~]# mysqladmin -uroot -p123123  flush-logs
  • 方式二:设置数据库服务配置项实现切割
max_binlog_size  -- 定义binlog日志大小进行切割的变量
#默认日志大小超过1G便会自动切割
mysql> select (@@max_binlog_size/1024/1024/1024);
+------------------------------------+
| (@@max_binlog_size/1024/1024/1024) |
+------------------------------------+
|                     1.000000000000 |
+------------------------------------+
注:默认单位为字节,这里将其转化成了GB为单位

⑤二进制日志信息清理方法

方式一:进行自动清理

binlog_expire_logs_seconds   2592000
-- 按照秒确认切割日志存在的时间,超过配置时间会自动清理,默认为30天
expire_logs_days             0
-- 按照天确认切割日志存在的时间,超过配置时间会自动清理,默认不启用
注:当变量值为0时,代表不启用此配置,按秒和按天分割只能同时启用其中之一
mysql> select @@binlog_expire_logs_seconds;
+------------------------------+
| @@binlog_expire_logs_seconds |
+------------------------------+
|                      2592000 |
+------------------------------+
1 row in set (0.00 sec)

mysql> select @@expire_logs_days;
+--------------------+
| @@expire_logs_days |
+--------------------+
|                  0 |
+--------------------+

  • 方式二:进行手工清理
purge binary logs to 'binlog日志名';				#清理此日志
PURGE BINARY LOGS BEFORE '2019-04-02 22:46:26';	  #清理此事件之前的日志
  • 注意:用rm的方式虽然能删除,但是尽量不要使用,容易使数据库崩溃

⑥二进制日志远程备份

  • 作用

    • 可以将多个数据库实例二进制日志汇总保存
    • 可以实现高可用架构中的数据补偿
  • 实现备份功能的步骤

1)创建新的数据库日志备份服务器
需安装好数据库程序(不用启动)
本次以kylin系统10.0.0.52服务器为备份服务器,主机名为db02

2)创建日志备份存储目录
[root@db02 ~]# mkdir -p /backup/db01-3306/
[root@db02 ~]# cd /backup/db01-3306/

3)执行远程备份命令
[root@db02 db01-3306]#mysqlbinlog -R --host=10.0.0.51 --user=root --password=123456 --raw --stop-never binlog.000016  &
此命令表示从binlog.000016日志开始,及以后所有的binlog日志都会自动备份到执行此命令时所在的目录
[root@db02 ~]# ll
-rw-r-----  1 root root 2573 Feb 27 08:16 binlog.000016
-rw-r-----  1 root root  157 Feb 27 08:16 binlog.000017

4.慢查询日志应用管理:(运维)

①查看慢查询日志

  • 配置启用慢查询日志后记得重启数据库服务
[root@db01 ~]# service mysqld stop
[root@db01 ~]# service mysqld start
  • 删除原有索引,查询测试
use dezyan;  
SET timestamp=1740629303;			---设置当前时间戳
select * from t100w where k1='At';
  • 查看慢查询日志
[root@db01 log]# cat /data/3306/log/slow.log 
# Time: 2025-02-27T13:30:14.713009Z
				---慢查询语句执行时间
# User@Host: root[root] @ localhost []  Id:     8
				---触发慢查询语句客户端信息
# Query_time: 0.407583  Lock_time: 0.000002 Rows_sent: 1056 Rows_examined: 1000000 
				---慢查询时间信息统计Query_time,获取数据行Rows_sent,扫描的数据行Rows_examined
use dezyan;	
				---数据库信息
SET timestamp=1740663014;
select * from t100w where k1='At';
				---SQL语句

②分析慢查询日志

[root@db01 ~]# mysqldumpslow -s c -t 3 /data/3306/log/slow.log
-t 3为可选参数
  • 可选参数
al: average lock time  -- 根据平均数据表锁定时间进行统计
ar: average rows sent  -- 根据平均值找到输出结果集多的语句
at: average query time -- 根据平均查询时间找到对应查询语句
 c: count              -- 根据语句执行次数进行分析
 l: lock time          -- 根据语句锁定时间进行分析
 r: rows sent          -- 根据语句结果集指定行数进行分析
 t: query time         -- 根据语句指定时间进行分

十七、数据库服务备份恢复

1.数据库服务备份数据方式

①物理方式(备份的数据量在50G以上)

  • 采用拷贝物理文件数据进行备份的方式,数据库服务物理数据文件存放路径是:/data/3306/data

  • 实现方式

    • 可以在某个特定时间点停机或停止业务访问,然后利用cp和tar命令将物理数据文件备份或打包;(不常用)
    • 可以在任意时间节点在不停机不停止业务时,然后利用专业的xtrabackup(Percona Xtrabackup)热备工具进行数据库数据备份;
  • 应用场景

    • 当企业数据库服务产生的需要备份的数据量在50G以上,可以选择物理备份(xtrabackup)

②逻辑方式(备份的数据量在50G以内)

  • 可以采用以SQL语句形式把数据库的数据导出保存备份为数据库文件(xxx.sql),文件中会含有大量SQL语句信息;

  • 逻辑方式备份好的数据可以进行更灵活的数据恢复

  • 实现方式

    • 可以在任意时间节点在不停机不停止业务时,然后利用专业的mysqldump(MDP)逻辑备份工具进行数据备份;(可以保存更全的数据)
    • 可以在任意时间节点在不停机不停止业务时,然后利用二进制日志binlog文件实现逻辑备份数据操作; (可以保存实时数据信息)
    • 可以在任意时间节点在不停机不停止业务时,然后利用主从数据库架构实现备份数据信息;
  • 应用场景

    • 当企业数据库服务产生的需要备份的数据量在50G以内,可以选择逻辑备份(mysqldump);

2.数据库服务备份恢复步骤

①逻辑备份与恢复mysqldump

  • 方式一:实现数据全备,恢复
1)备份
本地备份:mysqldump -uroot -p123123  -A >/tmp/all.sql
远程备份:mysqldump -uroot -p123123 -h10.0.0.51 -P3306 -A >/tmp/all.sql
-A参数表示备份所有数据库

2)恢复
命令行:mysql -uroot -p123123 -S /tmp/mysql3306.sock </tmp/all.sql
数据库中:mysql> source /tmp/all.sql;
  • 方式二:实现分库备份(指定库备份)
1)备份
本地备份:mysqldump -uroot -p123123  -B 库名y >xxx.sql
远程备份:mysqldump -uroot -p123123 -h10.0.0.51 -B 库名  >xxx.sql
-B, --databases      实现指定数据库进行备份

2)恢复
命令行:mysql -uroot -p123123 -S /tmp/mysql3306.sock <xxx.sql
数据库中:mysql> source /tmp/dezyan.sql;
  • 方式三:实现分表备份(指定表备份)
1)备份
本地备份:mysqldump -uroot -p123123 库名 表名 >xxx.sql
远程备份:mysqldump -uroot -p123123 -h10.0.0.51 库名 表名>xxx.sql

2)恢复
mysql -uroot -p123123  库名 <xxx.sql

②物理备份与恢复

方式一:cp、tar命令

利用cp或者tar命令进行数据目录物理备份(需要停止数据库服务)

步骤一:需要停止数据库服务 
步骤二:将数据目录进行备份
[root@db01 ~]# cp -a /data/3306/data/* /backup/

步骤三:模拟进行数据删除
[root@db01 ~]# drop database dezyan;

步骤四:利用备份数据目录进行恢复数据
确认数据库服务器进程停止,并清理数据目录(rm -rf /data/3306/data/*)
[root@db01 ~]# cp -a /backup/* /data/3306/data/
数据库恢复完毕,重启数据库服务
方式二:xbk工具

利用xbk工具实现数据目录物理备份(可以实现热备操作 恢复数据需要停止服务)

  • 下载安装xtrabackup工具
步骤一:下载工具软件包(安装xbk工具)
下载地址:https://www.percona.com/downloads
查看mysql8.0.36所对应的xtrabackup版本
https://docs.percona.com/percona-xtrabackup/8.0/index.html
使用版本为:percona-xtrabackup-80-8.0.35-31.1.el7.x86_64.rpm

步骤二: 安装软件程序
[root@db01 ~]# yum localinstall -y percona-xtrabackup-80-8.0.35-31.1.el7.x86_64.rpm
若下载失败需解决依赖问题

PS:kylin v10 sp3目前只能使用二进制安装
[root@kylin-db01 ~]# tar xf percona-xtrabackup-8.0.35-30-Linux-x86_64.glibc2.17.tar.gz
[root@kylin-db01 ~]# ln -s percona-xtrabackup-8.0.35-30-Linux-x86_64 percona
[root@kylin-db01 ~]# cd percona/bin  -- xtrabackup
[root@kylin-db01 ~]# xport PATH="$PATH:/usr/local/percona/bin"
  • 全量备份与恢复
------------------------------全量备份-----------------------------
步骤1:创建备份数据目录,进行数据备份 
[root@db01 ~]# mkdir /backup/full -p
[root@db01 ~]# xtrabackup --defaults-file=/data/3306/my3306.cnf --host=10.0.0.51 --port=3306 --user=root --password=123456  --backup  --target-dir=/backup/full

#参数详解
--target-dir=/backup/full
--defaults-file   加载备份数据库实例配置文件
--host            连接数据库实例(地址信息)
--port            连接数据库实例(端口信息)
--user            登录信息(用户信息)
--password        登录信息(密码信息)
--backup          进行备份操作
--target-dir      指定保存备份数据目录

###注意注意:
01 确认备份数据的目录一定是空目录
02 xbk工具只能安装到数据库服务器中 实现本地数据备份


步骤2:模拟数据库数据损坏
[root@db01 ~]# rm -rf /data/3306/data/*

----------------------------------全量恢复------------------------
步骤3:停止数据库服务
步骤4:执行数据恢复操作
[root@db01 ~]# chown -R mysql.mysql /data/3306/
[root@db01 ~]# xtrabackup --defaults-file=/data/3306/my3306.cnf --prepare  --target-dir=/backup/full
--prepare  :可以将备份过程中,没有保存的数据恢复到内存中
[root@db01 ~]# xtrabackup --defaults-file=/data/3306/my3306.cnf --copy-back --target-dir=/backup/full
--copy-back:可以将原有数据目录数据(磁盘数据)进行恢复还原

步骤5:需要重新启动数据库服务
  • 增量备份与恢复
------------------------------增量备份-----------------------------
步骤1:需要先进行全量备份
[root@db01 ~]# xtrabackup --defaults-file=/data/3306/my3306.cnf --host=10.0.0.51 --port=3306 --user=root --password=123456  --backup  --target-dir=/backup/full --parallel=4
注:--parallel=4    增加xtrabackup工具备份线程(默认1线程),提高备份数据效率

步骤2:再进行增量备份
注:增量备份需要再创建一个新的目录,且新目录也要为空
-创建新增数据:
create database xiaoA;
use xiaoA;
create table t1 (id int);
insert into t1 values (1),(2),(3);

-创建第一次增量备份存放目录
[root@db01 ~]# mkdir -p /backup/week01
-进行第一次增量备份
[root@db01 ~]# xtrabackup --defaults-file=/data/3306/my3306.cnf --host=10.0.0.51 --port=3306 --user=root --password=123456 --backup --parallel=4 --target-dir=/backup/week01  --incremental-basedir=/backup/full

-再创建新增数据
create database xiaoB;
use xiaoB;
create table t2 (id int);
insert into t2 values (4),(5),(6);

-创建第二次增量备份存放目录
[root@db01 ~]# mkdir -p /backup/week02
-进行第二次增量备份
[root@db01 ~]# xtrabackup --defaults-file=/data/3306/my3306.cnf --host=10.0.0.51 --port=3306 --user=root --password=123456 --backup --parallel=4 --target-dir=/backup/week02  --incremental-basedir=/backup/week01

----------------------------------增量恢复------------------------
步骤1:模拟数据损坏
rm -rf /data/3306/data/*
ll /data/3306/data/

步骤2:进行数据恢复
1.加载全量备份中,需要进行内存恢复数据
[root@db01 ~]# xtrabackup --defaults-file=/data/3306/my3306.cnf --prepare  --apply-log-only  --target-dir=/backup/full

2.加载第一次增量备份时,需要进行内存恢复数据,并和全量数据进行整合
[root@db01 ~]# xtrabackup --defaults-file=/data/3306/my3306.cnf --prepare  --apply-log-only  --target-dir=/backup/full --incremental-dir=/backup/week01
		
3.加载第二次增量备份时,需要进行内存恢复数据,并和全量数据进行整合
[root@db01 ~]# xtrabackup --defaults-file=/data/3306/my3306.cnf --prepare  --apply-log-only  --target-dir=/backup/full --incremental-dir=/backup/week02

4. 将全量和增量整合后数据,恢复到内存中				
[root@db01 ~]# xtrabackup --defaults-file=/data/3306/my3306.cnf --prepare   --target-dir=/backup/full

5.加载全备数据目录,实现数据库数据目录恢复(磁盘
[root@db01 ~]# xtrabackup --defaults-file=/data/3306/my3306.cnf --copy-back --target-dir=/backup/full

6.重新对数据目录赋权
[root@db01 ~]# chown -R mysql.mysql /data/3306/

步骤3:重新启动数据库服务,进行测试检查

--apply-log-only  保证保存数据不会进行撤销回滚操作(rollback),在备份过程中没有提交的数据 (主要应用在增量恢复数据)

十八、数据库服务存储引擎(面试)

1.什么是存储引擎(可以和磁盘对接)

  • MySQL数据库存储引擎类似是数据库服务中的文件系统,用户可以根据应用的需要选择如何存储和索引数据

​ 操作系统程序本身不能直接控制硬件,而是通过内核和设备驱动程序来调用和管理硬件资源。内核提供了系统调用接口,应用程序(包括数据库)通过这些接口间接访问硬件。
​ 数据库本身是一个应用程序,它没有内核,因此无法直接将数据写入磁盘。数据库通过存储引擎来管理数据的存储和检索。存储引擎的作用类似于操作系统中的文件系统和内存管理模块,它负责将数据组织成适合存储和检索的格式,并通过操作系统的系统调用与磁盘等硬件交互。存储引擎并不是操作系统的内核,而是数据库系统内部的一个组件,它依赖于操作系统的内核来完成底层的硬件操作。

2.存储引擎的类型

①常用的存储引擎

mysql> show engines;
InnoDB  新版本默认的存储引擎,相较于MyISAM功能更多,支持的特性也更多
MyISAM  旧版本默认的存储引擎
MEMORY  非关系型数据库的存储引擎

②InnoDB核心特性有哪些,以及与MyISAM存储引擎之间的区别: (面试题)

  • InnoDB支持:事务、mvcc(实现多读写并发)、聚簇索引、外键、缓冲区(新版本默认取消了)、AHI、DW(保证数据保存安全性);MyISAM均不支持
  • InnoDB支持:行级锁,MyISAM只支持表级锁;
  • InnoDB支持:数据热备,可以保证业务正常运行,对业务影响低,MyISAM只支持温备份,需要锁表备份;
  • InnoDB支持:支持CR自动故障恢复,宕机自动恢复,数据安全和一致性可以得到保证;MyISAM不支持,宕机可能丢失当前数据;

3.如何设置存储引擎

①方式一:默认设置

default_storage_engine  -- 利用此配置项或变量调整默认存储引擎
set global default_storage_engine='MyISAM';

②方式二:对表单独设置

alter table t1 engine='MyISAM';

4.存储引擎结构组成

①磁盘组成部分

1)系统表空间(文件 ibdata1)

  • 作用:
    • 早前:用于存储数据库服务所有数据信息(元数据信息 数据信息)
    • 当前:用于change buffer数据信息(存储内存区域中的数据)

2)独立表空间(文件 .ibd)

  • 作用:用于保存表中数据信息

    • 早期:ibd文件只保存数据信息 (表.ibd 表.frm(存储表结构信息) 表名.MYI (存储索引信息)?)
    • 当前:ibd文件只保存数据信息 保存表的结构信息 保存表的索引信息
  • 可以利用ibd文件恢复数据信息:独立表空间迁移过程

步骤一:在数据库中创建测试数据
mysql -uroot -S /tmp/mysql3306.sock <~/t100w_dezyan.sql

步骤二:提前获取恢复数据表的结构信息
show create table t100w;
CREATE TABLE `t100w` (
  `id` int DEFAULT NULL,
  `num` int DEFAULT NULL,
  `k1` char(2) DEFAULT NULL,
  `k2` char(4) DEFAULT NULL,
  `dt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

步骤三:模拟数据库宕机
....

步骤四:部署新的数据库实例
....

步骤五:在新的数据库实例中创建库和表信息
create database dezyan;
use dezyan;
CREATE TABLE `t100w` (
  `id` int DEFAULT NULL,
  `num` int DEFAULT NULL,
  `k1` char(2) DEFAULT NULL,
  `k2` char(4) DEFAULT NULL,
  `dt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

步骤六:实现独立表空间迁移
alter table dezyan.t100w discard tablespace;
-- 物理删除表文件,但逻辑表信息仍然存在
cp -a /data/3306/data/dezyan/t100w.ibd /data/3307/data/dezyan/t100w.ibd
-- 迁移数据表文件
alter table dezyan.t100w import tablespace;
-- 重新加载磁盘中数据表

3)双写文件区域 (文件 #ib_16384_0.dblwr #ib_16384_1.dblwr)

  • 功能作用:
    • 可以保证内存数据到磁盘中,不会出现损坏的数据,避免数据库异常宕机的数据无法加载情况;(利用CR机制)
    • 防止部分写失效:在将数据页写入磁盘时,如果发生崩溃,可能导致数据页部分写入,从而损坏数据。双写机制通过在双写缓冲区中保留副本,避免了这种问题。
    • 提高数据可靠性:即使在系统崩溃或硬件故障的情况下,双写机制也能确保数据的完整性和一致性

4)重做文件区域 (文件 #ib_redo0)

  • 功能作用:
    • 可以保证内存数据到磁盘中,不会出现损坏的数据,避免数据库异常宕机的数据无法加载情况;(利用CR机制)

5)撤销文件区域 (文件 undo_001 undo_002)

  • 功能作用:
    • 可以将没有提交的数据,进行撤销操作 rollback
    • 可以将redo中的某些记录信息,进行回滚操作

6)临时表空间(文件 ibtmp1 temp_1.ibt)

  • 功能作用:
    • 可以存储临时表数据信息(排序操作 连表 子查询 -- 内存)
    • 可以保存用户连接时,查询数据信息
  • PS:利用临时表,可以快速恢复内存数据,减少IO消耗

7)缓存文件区域 (文件 ib_buffer_pool)

  • 功能作用:
    • 将内存区域对应buffer_pool中存在的信息(热点数据信息),可以快速恢复

②内存组成部分

  • buffer pool

    • 功能作用:存储磁盘中加载数据页信息
    • 调整此区域大小:在my.cnf中配置innodb_buffer_pool_size =
    • 设置多少?通常建议设置为服务器物理内存的 60%-80%
    • 计算公式:buffer_pool_size = (Total RAM - OS Reserve - Other Processes) * 0.75
  • AHI

    • 功能作用:可以给内存区域的热点数据页建立索引,便于从buffer pool区域快速找到所需数据页
  • innodb_adaptive_hash_index=ON

  • Change buffer

    • 功能作用:可以减少辅助索引的频繁变更情况,降低对数据业务操作的影响
    • 调整此区域大小:Change Buffer 的值范围为 0 到 50,占用 Buffer Pool 空间的默认比例为 25%
      • 在my.cnf中设置innodb_change_buffer_max_size =
      • 根据实际业务场景调整。如果写操作较多且读操作较少,可以适当增大 Change Buffer 的比例(例如 30%-40%),以提高写性能
  • log buffer

​ 功能作用:会将数据库产生日志信息先保存到日志缓冲区,在把缓冲区数据写入到磁盘,减少IO消耗

十九、数据库数据恢复痛点

1.情况一:日志文件被清理过,可能建库语句所在日志已经丢失(数据损坏量大)

  • 方案一:使用最近一次全备,将误删之前所有的binlog,一并恢复
  • 方案二:利用延时从库,进行数据恢复
利用延时从库进行数据恢复是一种有效的策略,尤其适用于主库发生误操作(如误删除表或库)时。以下是基于延时从库进行数据恢复的详细步骤和方法:

### 1. 配置延时从库
首先需要在从库上配置延时复制。例如,设置从库延迟3600秒(1小时)同步主库数据:

STOP SLAVE;
CHANGE MASTER TO master_delay = 3600;
START SLAVE;

通过 `SHOW SLAVE STATUS\G` 可以查看延时从库的延迟时间是否生效。

### 2. 模拟误操作并定位问题
假设主库发生误操作,如删除了一个表:

DROP TABLE some_table;

此时,延时从库会延迟同步该操作,因此在从库上该表仍然存在。

### 3. 停止从库的SQL线程
在从库上停止SQL线程,以防止误操作被同步:

STOP SLAVE SQL_THREAD;

此时,从库的IO线程仍然运行,继续接收主库的二进制日志。

### 4. 查找误操作的Binlog位置
通过 `mysqlbinlog` 工具查找误操作在主库Binlog中的位置:

mysqlbinlog --base64-output=decode-rows -vvv /path/to/binlog | grep -A 50 -B 50 'DROP TABLE'

确定误操作前后的Binlog位置。

### 5. 设置从库同步到误操作前
将从库的复制延迟设置为0,并指定从库同步到误操作前的位置:

CHANGE MASTER TO master_delay = 0;
START SLAVE SQL_THREAD UNTIL MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=1234;

等待从库同步到指定位置后,SQL线程会停止。

### 6. 备份从库数据
使用工具如 `mysqldump` 或 `Xtrabackup` 备份从库中的数据:

mysqldump -h from_host -P port -u user -p database_name table_name > backup.sql

或者:

xtrabackup --backup --target-dir=/path/to/backup

### 7. 恢复数据到主库
将备份的数据恢复到主库:

mysql -h master_host -P port -u user -p database_name < backup.sql

在恢复过程中,建议关闭二进制日志以避免再次触发误操作。

### 8. 重新设置延时从库
恢复完成后,重新设置从库的延时复制:

STOP SLAVE;
CHANGE MASTER TO master_delay = 3600;
START SLAVE;

### 注意事项
1. **备份的重要性**:在进行任何操作前,建议对从库进行备份,以防止恢复失败。
2. **延时时间的选择**:延时时间应根据业务需求和误操作的发现时间来设定,常见的延时时间为1小时。
3. **双延时从库策略**:为了进一步提高数据安全性,可以配置多个延时从库,例如两个延时从库的同步时间错开。

通过以上步骤,可以利用延时从库快速恢复误操作的数据,减少数据丢失的风险。

2.情况二:所需日志跨越多个文件,如何进行日志信息的截取(数据损坏量大)

  • 启用GTID(全局事务ID)方式

​ 无论跨越多少个日志文件,每个事务操作的事件ID信息都是唯一且递增的(5.6+引入)

  • GTID功能技术概述:

​ GTID(global transation id)称为全局事务(事件)ID,标识binlog日志记录的唯一性; server_uuid(实例标识信息)+事件编号==GTID

  • GTID功能开启设置
在my.cnf配置文件中添加
gtid_mode=on
enforce_gtid_consistency=on
  • 利用gtid截取binlog信息,从而恢复数据

    • 在数据库的每次操作,都会被记录事物编号,编号唯一。
  • 常用参数

    • include-gtids=事务编号 -- 可以截取需要恢复的事务范围信息
    语法:
    mysqlbinlog --include-gtids=事务编号 binlog日志文件名
    示例:
    mysqlbinlog --include-gtids=59617675-f589-11ef-9c2f-000c29141679:1-5 binlog.000005 binlog.000006 binlog.000007 >/tmp/add.sql
    
    • exclude-gtids=name -- 连续截取多个范围事务信息时,可以排除中间的某个事务不进行截取
    语法:
    mysqlbinlog --include-gtids=事务编号 --exclude-gtids=事务编号 binlog日志文件名
    示例:
    mysqlbinlog --include-gtids=59617675-f589-11ef-9c2f-000c29141679:1-5 binlog.000005 binlog.000006 binlog.000007 --exclude-gtids=59617675-f589-11ef-9c2f-000c29141679:2 >/tmp/add02.sql
    
    • skip-gtids -- 在截取后文件中,不记录gtid信息(主要用于将截取后文件进行恢复数据)

PS:在利用gtid截取文件默认恢复数据时,具有幂等特性,已经完成过的操作事件信息不回重复执行

3.情况三:如何从日志文件中恢复单库、单表、或者部分行数据信息(少量数据损坏 如何快速修复数据)

  • 方案一:可以利用命令单独截取某个数据库的日志信息;(分库备份+截取某个数据库日志信息)使用情况二中的方法
  • 方案二:利用第三方工具(binlog2sql),实现数据闪回功能
1)下载数据闪回工具(binlog2sql)
https://github.com/danfengcao/binlog2sql

2)安装,编辑requirements.txt设定版本
Mysql版本:8.0.36
[root@db01 ~]# vim requirements.txt
PyMySQL==0.9.3
wheel==0.29.0
mysql-replication==0.13

3)安装依赖,检查版本
[root@db01 ~]# yum install -y python3
[root@db01 ~]# pip3 install -r requirements.txt

[root@db01 ~]# pip3 show pymysql
[root@db01 ~]# pip3 show wheel
[root@db01 ~]# pip3 show mysql-replication

4)应用
[root@db01 ~]# cd /root/binlog2sql-master/binlog2sql
命令格式:
python binlog2sql.py -h <hostname> -P <port> -u <username> -p'<password>' -d 库名 -t 表名 --start-file='mysql-bin.000001' --start-position=4 --sql-type=delete
		-h 连接数据库服务端(服务端地址)
		-P 连接数据库服务端(服务端端口)
		-u 登录数据库服务端(用户名)
		-p 登录数据库服务端(密码)      
		--start-file='binlog.000008'  需要从哪个binlog中读取SQL信息
		-d 指定过滤库信息
		-t 指定过滤表信息
		--sql-type  指定过滤的语句类型
		--start-position:指定起始解析位置
		-B  取误操作撤销后的还原语句
		
示例:
[root@db01 ~]# python3 binlog2sql.py -h 10.0.0.51 -P 3306 -u root -p 123123 -d world -t city --sql-type=delete --start-file='binlog.000019' -B

5)恢复方法
[root@db01 ~]# python3 binlog2sql.py -h 10.0.0.51 -P 3306 -u root -p 123123 -d world -t city --sql-type=delete --start-file='binlog.000019' -B > /tmp/re.sql
[root@db01 ~]# mysql -uroot -p123123 < /tmp/re.sql

PS:在使用该工具时,可能会遇见如下错误

RuntimeError: cryptography is required for sha256_password or caching_sha2_password

这种情况跟密码插件有关

  • 密码插件的作用:可以保证数据库中记录密文密码的加密方式

    • mysql_native_password:加密方式比较简单 生成密文信息简单
    • caching_sha2_password:加密方式比较复杂 生成密文信息复杂
  • 错误解决方案

    ALTER USER 'your_username'@'your_host' IDENTIFIED WITH mysql_native_password BY 'your_password';
    FLUSH PRIVILEGES;
    

面试:数据库数据闪回逻辑

1) 需要扫描binlog文件信息
2) 可以过滤binlog文件信息(过滤-库/表/语句)
3)可以将过滤后的语句进行反向操作(生成反向操作语句)
   insert -- 反向语句 -- delete 
   delete -- 反向语句 -- insert 
   update -- 反向语句 -- 将语句中 条件部分信息和修改部分信息最互换

面试:日常企业进行数据备份方案

全备份:
	数据量增长快:每周全备份一次。
	数据量增长慢:每月全备份一次。
	备份工具:xbk+mdp,从从库备份。
增量备份:
	使用 binlog 进行增量备份。
	全备份周期长:保存更多的增量文件。
	全备份周期短:保存较少的增量文件。
恢复策略:
	在恢复数据时,首先恢复最近一次的全备份,然后依次应用增量备份文件,直到恢复到所需的时间点。

二十、数据库服务事务机制

客户端与服务端在交互过程-存储/调取的过程中,需要保证数据的完整性/一致性

利用Innodb引擎,采用事务机制进行数据存储和调取,可以更好的保证数据的完整性和一致性(安全性)

事务机制有如下几大特性:

A - (atomicity): 原子性

  • 当一系列DML操作语句执行时,要么所有操作都成功,要么所有操作都失败。

  • 具有此特性的原因:数据库中具有事务生命周期机制

@控制事务开始与提交结束

mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            1 |
+--------------+
1为自动控制,0为手动
  • 人为控制事务开始到结束(事务开始: begin;每个事务操作结束:commit / rollback )

    • 多条 SQL 语句会被组合成一个事务,直到显式调用 COMMIT 提交事务,或者调用 ROLLBACK 回滚事务。
    • 在事务提交之前,所有操作都不会永久生效,可以随时回滚到事务开始之前的状态。
    • 适用于需要批量操作、复杂逻辑处理或确保数据一致性的场景
    begin;
    DML01;
    DML02;
    DML03;
    commit  原子特性所有操作都成功
    
    begin;
    DML01;  成功  
    DML02;  成功 
    DML03;  失败		--此次失败会将前面两次成功的操作都rollback回滚
    commit/quit   原子特性所有操作都失败
    
  • 自动控制事务开始到结束

    • 每次执行单条 SQL 语句(如 INSERTUPDATEDELETE)时,MySQL 会自动将该操作作为一个独立的事务提交。
    • 这意味着每次操作都会立即生效,不需要手动调用 COMMIT
    • 适用于简单的操作场景,或者不需要显式事务控制的场景。
    • 自动触发提交机制
      • 1)DDL DCL语句执行时,会自动触发提交机制
      • 2)开启自动提交功能,dml执行完,会自动触发提交机制
    • 自动触发回滚机制
      • 1)语句操作失败会触发回滚机制
      • 2)断开会话连接
      • 3)重启数据库服务

C - (consistency): 一致性

  • 当数据库服务出现异常重启之后,需要保证数据库服务重启前和重启后的数据一致.

  • 是应用DWB文件+CR机制实现的

I - (isolation):隔离性

  • 控制大量并发访问,对数据库进行查询或存储的冲突问题
    • 两个并发:
      • 一个客户端访问进行数据存储操作 不断存数据
      • 一个客户端访问进行数据查询操作 查询的数据总是变化(分析统计)

①基于数据库隔离级别 读隔离 (MVCC机制-扩展)

读隔离有以下几种隔离级别:

1.READ UNCOMMITTED -- RU(读未提交)

并行处理能力最强 会出现读的问题(脏读 不可重复读 幻读)

  • set global transaction_isolation='READ-UNCOMMITTED';
  • 脏读情况: 并行多个会话事务读取数据时,可以读取未提交的修改记录(读取脏页信息)
  • 不可重复读:当利用数据表进行数据统计时,每次统计的数据信息不一致
  • 幻读情况: 当进行范围数据修改时,其他会话同时插入了范围以内数据信息,导致范围修改结果和修改语句不一致(影响范围数据修改调整删除信息)
2.READ COMMITTED -- RC(读已提交)

会出现读的问题(不可重复读 幻读)

  • set global transaction_isolation='READ-COMMITTED';
  • 脏读情况: 已解决
  • 不可重复读:依然存在
  • 幻读情况: 依然存在
3.REPEATABLE READ -- RR(重复提交) 默认

会出现读的问题 - 读隔离

  • set global transaction_isolation='REPEATABLE-READ';
  • 脏读情况: 已解决
  • 不可重复读:已解决(便于进行数据统计)
  • 幻读情况: 已解决(便于进行数据范围处理)
4.SERIALIZABLE -- SR(串行级别)

并行处理能力最弱 会出现读的问题 - 将并发读操作进行锁定

  • set global transaction_isolation='SERIALIZABLE';
  • 写入操作:会将整个表进行锁定(表级锁)
  • 查看操作:会将整个表进行锁定(表级锁)

②- 基于数据库锁机制 写隔离

写隔离有以下几种级别:

  • RU级别 -- 只有行锁机制

  • RC级别 -- 只有行锁机制

  • RR级别 -- 会有行锁机制+间隙锁=邻键锁

  • SR级别 -- 基于表级锁(只有读锁不会阻塞读锁,其余全部都会堵塞;读锁 -- 阻塞写锁 写锁 -- 阻塞读锁 写入 -- 阻塞写锁)

    ​ Myisam 基于表级锁(读锁 -- 不会阻塞写锁 写锁 -- 阻塞写锁 )

D -(durability):持久性

  • 可以保证数据库存储的数据信息,可以更好的保存到磁盘中

  • innodb_flush_log_at_trx_commit -- 影响持久性-- 影响redo信息记录redo日志

    • innodb_flush_log_at_trx_commit=1 -- 每次提交事务都会写入log buffer,并写入redo
    • innodb_flush_log_at_trx_commit=0 -- 每次log buffer 和 redo信息的写入,会间隔1s钟;
    • innodb_flush_log_at_trx_commit=2 -- 每次提交事务先写入log buffer,每间隔1s,将log buffer信息写入到redo
  • sync_binlog -- 影响持久性 -- 影响binlog信息记录到binlog文件

    • sync_binlog=0 -- 禁止写入binlog信息
    • sync_binlog=1 -- log buffer 有新的binlog信息,会马上同步到binlog文件
    • sync_binlog=N -- log buffer 有新的binlog信息, 积攒到N个事务之后,才会同步到binlog文件
  • sql_log_bin-- 设置是否有些事务操作,进行binlog记录 (恢复数据信息 / 不需要同步从库数据信息)

    • sql_log_bin=1 -- 会做事务操作记录到binlog
    • sql_log_bin=0 -- 不会做事务操作记录到binlog
  • innodb_file_per_table -- 影响表数据保存位置

    • innodb_file_per_table=1 -- 表示表数据信息会单独保存到对应独立表空间文件中 t1.ibd
    • innodb_file_per_table=0 -- 表示表数据信息会汇总保存到共享表空间文件 ibdate1

面试题:持久性的双一配置

“双一配置”是 MySQL 中用于确保事务持久性和数据一致性的关键设置。通过将 innodb_flush_log_at_trx_commitsync_binlog 都设置为 1,可以最大限度地减少数据丢失的风险,但需要根据实际业务需求权衡性能和安全

posted @ 2025-03-21 16:49  丁志岩  阅读(21)  评论(0)    收藏  举报