写在最后

image-20220509233129490

一些体会写出来:

  • 享受工作,享受学习,享受娱乐
  • 知识系统
    • 阅读大量书
    • 一路走来回头看时,一切都很清晰
  • 珍惜时间

其它数据库日志

1. MySQL支持的日志

1.1 日志类型

MySQL有不同类型的日志文件,用来存储不同类型的日志,分为二进制日志错误日志通用查询日志慢查询日志,这也是常用的4种。MySQL 8又新增两种支持的日志:中继日志数据定义语句日志。使用这些日志文件,可以查看MySQL内部发生的事情。

  • 慢查询日志:记录所有执行时间超过long_query_time的所有查询,方便我们对查询进行优化。

  • 通用查询日志:记录所有连接的起始时间和终止时间,以及连接发送给数据库服务器的所有指令,对我们复原操作的实际场景、发现问题,甚至是对数据库操作的审计都有很大的帮助。

  • 错误日志:记录MySQL服务的启动、运行或停止MySQL服务时出现的问题,方便我们了解服务器的状态,从而对服务器进行维护。

  • 二进制日志:记录所有更改数据的语句,可以用于主从服务器之间的数据同步,以及服务器遇到故障时数据的无损失恢复。

  • 中继日志:用于主从服务器架构中,从服务器用来存放主服务器二进制日志内容的一个中间文件。从服务器通过读取中继日志的内容,来同步主服务器上的操作。

  • 数据定义语句日志:记录数据定义语句执行的元数据操作。

除二进制日志外,其他日志都是文本文件。默认情况下,所有日志创建于MySQL数据目录中。

1.2 日志的弊端

  • 日志功能会降低MySQL数据库的性能

  • 日志会占用大量的磁盘空间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
+ redo、undo 日志
+ 数据库日志
+ 数据复制
+ 数据恢复
+ 发现错误
+ 操作审计
+ 数据一致性、持久性等
+ mysql日志
+ 慢查询日志
+ 通用查询日志
+ 错误日志
+ 二进制日志
+ 更改数据日志
+ 主从同步
+ 中继日志
+ 从服务器同步日志
+ 数据定义语句日志
+ 日志的弊端
+ 降低性能
+ 空间

2. 通用查询日志(general query log)

通用查询日志用来记录用户的所有操作,包括启动和关闭MySQL服务、所有用户的连接开始时间和截止时间、发给 MySQL 数据库服务器的所有 SQL 指令等。当我们的数据发生异常时,查看通用查询日志,还原操作时的具体场景,可以帮助我们准确定位问题。

2.1 查看当前状态

1
mysql> SHOW VARIABLES LIKE '%general%';

2.2 启动日志

方式1:永久性方式

1
2
3
[mysqld] 
general_log=ON
general_log_file=[path[filename]] #日志文件所在目录路径,filename为日志文件名

方式2:临时性方式

1
2
3
4
SET GLOBAL general_log=on; # 开启通用查询日志
SET GLOBAL general_log_file=’path/filename’; # 设置日志文件保存位置
SET GLOBAL general_log=off; # 关闭通用查询日志
SHOW VARIABLES LIKE 'general_log%'; # 查看设置后情况

2.3 停止日志

方式1:永久性方式

1
2
[mysqld] 
general_log=OFF

方式2:临时性方式

1
2
SET GLOBAL general_log=off;
SHOW VARIABLES LIKE 'general_log%';

3.错误日志(error log)

3.1 启动日志

在MySQL数据库中,错误日志功能是默认开启的。而且,错误日志无法被禁止

1
2
[mysqld] 
log-error=[path/[filename]] #path为日志文件所在的目录路径,filename为日志文件名

3.2 查看日志

1
mysql> SHOW VARIABLES LIKE 'log_err%';

3.3 删除\刷新日志

1
2
install -omysql -gmysql -m0644 /dev/null /var/log/mysqld.log
mysqladmin -uroot -p flush-logs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
+ 记录用户的所有操作
+ 查看状态
+ 默认关闭
+ 文件目录
+ 开启日志
+ 日志内容
+ 停止日志
+ 删除刷新日志
+ 错误日志
+ 默认开启
+ 启动日志
+ 查看日志
+ 删除等
+ 8.0新特性

4. 二进制日志(bin log)

4.1 查看默认情况

1
mysql> show variables like '%log_bin%';

4.2 日志参数设置

方式1:永久性方式

1
2
3
4
[mysqld] 
#启用二进制日志
log-bin=atguigu-bin
binlog_expire_logs_seconds=600 max_binlog_size=100M

设置带文件夹的bin-log日志存放目录

1
2
[mysqld] 
log-bin="/var/lib/mysql/binlog/atguigu-bin"

注意:新建的文件夹需要使用mysql用户,使用下面的命令即可。

1
chown -R -v mysql:mysql binlog

方式2:临时性方式

1
2
3
4
5
6
7
# global 级别 
mysql> set global sql_log_bin=0;
ERROR 1228 (HY000): Variable 'sql_log_bin' is a SESSION variable and can`t be used with SET GLOBAL

# session级别
mysql> SET sql_log_bin=0;
Query OK, 0 rows affected (0.01 秒)

4.3 查看日志

1
2
3
mysqlbinlog -v "/var/lib/mysql/binlog/atguigu-bin.000002"
# 不显示binlog格式的语句
mysqlbinlog -v --base64-output=DECODE-ROWS "/var/lib/mysql/binlog/atguigu-bin.000002"
1
2
3
4
5
6
7
8
# 可查看参数帮助 
mysqlbinlog --no-defaults --help

# 查看最后100行
mysqlbinlog --no-defaults --base64-output=decode-rows -vv atguigu-bin.000002 |tail -100

# 根据position查找
mysqlbinlog --no-defaults --base64-output=decode-rows -vv atguigu-bin.000002 |grep -A20 '4939002'

上面这种办法读取出binlog日志的全文内容比较多,不容易分辨查看到pos点信息,下面介绍一种更为方便的查询命令:

1
mysql> show binlog events [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count];
  • IN 'log_name':指定要查询的binlog文件名(不指定就是第一个binlog文件) 
  • FROM pos:指定从哪个pos起始点开始查起(不指定就是从整个文件首个pos点开始算)
  • LIMIT [offset]:偏移量(不指定就是0)
  • row_count:查询总条数(不指定就是所有行)
1
mysql> show binlog events in 'atguigu-bin.000002';

4.4 使用日志恢复数据

mysqlbinlog恢复数据的语法如下:

1
mysqlbinlog [option] filename|mysql –uuser -ppass;
  • filename:是日志文件名。
  • option:可选项,比较重要的两对option参数是–start-date、–stop-date 和 –start-position、– stop-position。
    • --start-date 和 --stop-date:可以指定恢复数据库的起始时间点和结束时间点。
    • --start-position和--stop-position:可以指定恢复数据的开始位置和结束位置。

注意:使用mysqlbinlog命令进行恢复操作时,必须是编号小的先恢复,例如atguigu-bin.000001必须在atguigu-bin.000002之前恢复。

4.5 删除二进制日志

1. PURGE MASTER LOGS:删除指定日志文件

1
2
PURGE {MASTER | BINARY} LOGS TO ‘指定日志文件名’ 
PURGE {MASTER | BINARY} LOGS BEFORE ‘指定日期’

5. 再谈二进制日志(binlog)

5.1 写入机制

binlog的写入时机也非常简单,事务执行过程中,先把日志写到binlog cache,事务提交的时候,再把binlog cache写到binlog文件中。因为一个事务的binlog不能被拆开,无论这个事务多大,也要确保一次性写入,所以系统会给每个线程分配一个块内存作为binlog cache。

image-20220405163025361

write和fsync的时机,可以由参数sync_binlog控制,默认是 0。为0的时候,表示每次提交事务都只write,由系统自行判断什么时候执行fsync。虽然性能得到提升,但是机器宕机,page cache里面的binglog 会丢失。如下图:

image-20220405163125180

为了安全起见,可以设置为1,表示每次提交事务都会执行fsync,就如同redo log 刷盘流程一样。最后还有一种折中方式,可以设置为N(N>1),表示每次提交事务都write,但累积N个事务后才fsync。

image-20220405163205364

在出现IO瓶颈的场景里,将sync_binlog设置成一个比较大的值,可以提升性能。同样的,如果机器宕机,会丢失最近N个事务的binlog日志。

5.2 binlog与redolog对比

  • redo log 它是物理日志,记录内容是“在某个数据页上做了什么修改”,属于 InnoDB 存储引擎层产生的。
  • 而 binlog 是逻辑日志,记录内容是语句的原始逻辑,类似于“给 ID=2 这一行的 c 字段加 1”,属于MySQL Server 层。
  • 虽然它们都属于持久化的保证,但是侧重点不同。
    • redo log 让InnoDB存储引擎拥有了崩溃恢复能力。
    • binlog保证了MySQL集群架构的数据一致性

5.3 两阶段提交

在执行更新语句过程,会记录redo log与binlog两块日志,以基本的事务为单位,redo log在事务执行过程中可以不断写入,而binlog只有在提交事务时才写入,所以redo log与binlog的写入时机不一样。

为了解决两份日志之间的逻辑一致问题,InnoDB存储引擎使用两阶段提交方案。

image-20220405163716222

使用两阶段提交后,写入binlog时发生异常也不会有影响

image-20220405163902977

另一个场景,redo log设置commit阶段发生异常,那会不会回滚事务呢?

image-20220405163927129

并不会回滚事务,它会执行上图框住的逻辑,虽然redo log是处于prepare阶段,但是能通过事务id找到对应的binlog日志,所以MySQL认为是完整的,就会提交事务恢复数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
+ 二进制日志
+ 变更日志
+ DDL和DML等更新操作,事件形式记录
+ 应用
+ 数据恢复
+ 数据复制
+ 查看默认情况
+ 存储函数
+ 重启一次创建一个文件
+ 参数设置
+ 单个文件大小
+ 查看日志
+ mysqlbinlog工具查看
+ show binlog events查看
+ binlog格式
+ 使用日志恢复数据
+ position
+ 起始时间
+ 删除
+ 删除指定
+ 全部删除
+ 其他场景
+ 写入机制
+ 流程
+ 先写入binlog cache
+ 再写入文件系统缓存page cache
+ 写入binlog文件中
+ 写入时机
+ write时机
+ fsync时机
+ 操作系统宕机风险
+ 达到n个事务一起提交
+ binlog与redolog
+ binlog、undolog
+ 逻辑日志,记录语句的逻辑
+ redolog
+ 物理日志
+ 记录具体物理修改
+ 两阶段提交
+ redolog的两阶段提交
+ 处于写binlog的前后
+ 如果提交时binlog未写入,则回滚

6. 中继日志(relay log)

6.1 介绍

中继日志只在主从服务器架构的从服务器上存在。从服务器为了与主服务器保持一致,要从主服务器读取二进制日志的内容,并且把读取到的信息写入本地的日志文件中,这个从服务器本地的日志文件就叫中继日志。然后,从服务器读取中继日志,并根据中继日志的内容对从服务器的数据进行更新,完成主从服务器的数据同步

6.2 恢复的典型错误

如果从服务器宕机,有的时候为了系统恢复,要重装操作系统,这样就可能会导致你的服务器名称与之前不同。而中继日志里是包含从服务器名的。在这种情况下,就可能导致你恢复从服务器的时候,无法从宕机前的中继日志里读取数据,以为是日志文件损坏了,其实是名称不对了。

解决的方法也很简单,把从服务器的名称改回之前的名称。

1
2
3
4
+ 中继日志
+ 从服务器上,保证数据同步
+ 从机读取主机二进制日志的保存的日志
+ 问题:恢复错误

主从复制

1. 主从复制概述

1.1 如何提升数据库并发能力

一般应用对数据库而言都是“读多写少”,也就说对数据库读取数据的压力比较大,有一个思路就是采用数据库集群的方案,做主从架构、进行读写分离,这样同样可以提升数据库的并发处理能力。但并不是所有的应用都需要对数据库进行主从架构的设置,毕竟设置架构本身是有成本的。

如果我们的目的在于提升数据库高并发访问的效率,那么首先考虑的是如何优化SQL和索引,这种方式简单有效;其次才是采用缓存的策略,比如使用 Redis将热点数据保存在内存数据库中,提升读取的效率;最后才是对数据库采用主从架构,进行读写分离。

1.2 主从复制的作用

第1个作用:读写分离。

第2个作用就是数据备份。

第3个作用是具有高可用性。

2. 主从复制的原理

2.1 原理剖析

三个线程

实际上主从同步的原理就是基于 binlog 进行数据同步的。在主从复制过程中,会基于3 个线程来操作,一个主库线程,两个从库线程。

image-20220405164559961

二进制日志转储线程(Binlog dump thread)是一个主库线程。当从库线程连接的时候, 主库可以将二进制日志发送给从库,当主库读取事件(Event)的时候,会在 Binlog 上加锁,读取完成之后,再将锁释放掉。

从库 I/O 线程会连接到主库,向主库发送请求更新 Binlog。这时从库的 I/O 线程就可以读取到主库的二进制日志转储线程发送的 Binlog 更新部分,并且拷贝到本地的中继日志 (Relay log)。

从库 SQL 线程会读取从库中的中继日志,并且执行日志中的事件,将从库中的数据与主库保持同步。

image-20220405164718627

复制三步骤

步骤1:Master将写操作记录到二进制日志(binlog)。

步骤2:SlaveMaster的binary log events拷贝到它的中继日志(relay log);

步骤3:Slave重做中继日志中的事件,将改变应用到自己的数据库中。 MySQL复制是异步的且串行化的,而且重启后从接入点开始复制。

复制的问题

复制的最大问题:延时

2.2 复制的基本原则

  • 每个Slave只有一个Master

  • 每个Slave只能有一个唯一的服务器ID

  • 每个Master可以有多个Slave

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
+ 数据库-缓存架构
+ 主从架构、读写分离
+ 提升数据库并发
+ 主从复制的作用
+ 读写分离
+ 分散压力
+ 减少锁表影响
+ 数据备份
+ 热备份机制
+ 高可用性
+ 冗余方式,高可用
+ 主从复制的原理
+ 三个线程
+ 二进制日志转储线程
+ 数据发出去
+ 从库IO线程
+ 写入中继日志
+ 从库SQL线程
+ 读取日志,执行事件
+ 一主一从主从架构
+ 搭建集群
+ 配置文件
+ 主机:创建账户并授权
+ 从机:配置需要复制的主机
+ 停止
+ binlog的三种模式
+ statement(基于SQL语句的复制)
+ 默认模式
+ 缺点
+ 不确定操作无法复制
+ row(基于行的复制)
+ 任何情况都可以被复制,最安全可靠的
+ 缺点
+ 文件大
+ MINED
+ 一般语句statement
+ 有函数row
+ 多主多从

3. 同步数据一致性问题

主从同步的要求:

  • 读库和写库的数据一致(最终一致);

  • 写数据必须写到写库;

  • 读数据必须到读库(不一定);

3.1 理解主从延迟问题

进行主从同步的内容是二进制日志,它是一个文件,在进行网络传输的过程中就一定会存在主从延迟(比如 500ms),这样就可能造成用户在从库上读取的数据不是最新的数据,也就是主从同步中的数据不一致性问题。

3.2 主从延迟问题原因

在网络正常的时候,日志从主库传给从库所需的时间是很短的,即T2-T1的值是非常小的。即,网络正常情况下,主备延迟的主要来源是备库接收完binlog和执行完这个事务之间的时间差。

主备延迟最直接的表现是,从库消费中继日志(relay log)的速度,比主库生产binlog的速度要慢。造成原因:

1、从库的机器性能比主库要差

2、从库的压力大

3、大事务的执行

3.3 如何减少主从延迟

若想要减少主从延迟的时间,可以采取下面的办法:

  1. 降低多线程大事务并发的概率,优化业务逻辑

  2. 优化SQL,避免慢SQL,减少批量操作,建议写脚本以update-sleep这样的形式完成。

  3. 提高从库机器的配置,减少主库写binlog和从库读binlog的效率差。

  4. 尽量采用短的链路,也就是主库和从库服务器的距离尽量要短,提升端口带宽,减少binlog传输的网络延时。

  5. 实时性要求的业务读强制走主库,从库只做灾备,备份。

3.4 如何解决一致性问题

读写分离情况下,解决主从同步中数据不一致的问题, 就是解决主从之间 数据复制方式 的问题,如果按照数据一致性 从弱到强 来进行划分,有以下 3 种复制方式。

方法 1:异步复制

image-20220405165455998

方法 2:半同步复制

image-20220405165513025

方法 3:组复制

首先我们将多个节点共同组成一个复制组,在执行读写(RW)事务的时候,需要通过一致性协议层(Consensus 层)的同意,也就是读写事务想要进行提交,必须要经过组里“大多数人”(对应 Node 节点)的同意,大多数指的是同意的节点数量需要大于 (N/2+1),这样才可以进行提交,而不是原发起方一个说了算。而针对只读(RO)事务则不需要经过组内同意,直接 COMMIT 即可。

image-20220405165650425

1
2
3
4
5
6
7
8
9
10
+ 主从同步
+ 解决一致性问题
+ 异步复制
+ 半同步复制
+ 有一个ack即可
+ 可以设置参数n个
+ 组复制
+ 过半的事务提交则同意提交
+ 数据库中间件
+ 主备切换问题

数据库备份与恢复

1. 物理备份与逻辑备份

物理备份:备份数据文件,转储数据库物理文件到某一目录。物理备份恢复速度比较快,但占用空间比较大,MySQL中可以用xtrabackup工具来进行物理备份。

逻辑备份:对数据库对象利用工具进行导出工作,汇总入备份文件内。逻辑备份恢复速度慢,但占用空间小,更灵活。MySQL 中常用的逻辑备份工具为mysqldump。逻辑备份就是备份sql语句,在恢复的时候执行备份的sql语句实现数据库数据的重现。

2. mysqldump实现逻辑备份

2.1 备份一个数据库

1
mysqldump –u 用户名称 –h 主机名称 –p密码 待备份的数据库名称[tbname, [tbname...]]> 备份文件名 称.sql
1
2
mysqldump -uroot -p atguigu>atguigu.sql #备份文件存储在当前目录下
mysqldump -uroot -p atguigudb1 > /var/lib/mysql/atguigu.sql

2.2 备份全部数据库

1
2
mysqldump -uroot -pxxxxxx --all-databases > all_database.sql 
mysqldump -uroot -pxxxxxx -A > all_database.sql

2.3 备份部分数据库

1
mysqldump –u user –h host –p --databases [数据库的名称1 [数据库的名称2...]] > 备份文件名 称.sql
1
2
mysqldump -uroot -p --databases atguigu atguigu12 >two_database.sql
mysqldump -uroot -p -B atguigu atguigu12 > two_database.sql

2.4 备份部分表

1
mysqldump –u user –h host –p 数据库的名称 [表名1 [表名2...]] > 备份文件名称.sql
1
2
3
mysqldump -uroot -p atguigu book> book.sql
#备份多张表
mysqldump -uroot -p atguigu book account > 2_tables_bak.sql

2.5 备份单表的部分数据

1
mysqldump -uroot -p atguigu student --where="id < 10 " > student_part_id10_low_bak.sql

2.6 排除某些表的备份

1
mysqldump -uroot -p atguigu --ignore-table=atguigu.student > no_stu_bak.sql

2.7 只备份结构或只备份数据

  • 只备份结构
1
mysqldump -uroot -p atguigu --no-data > atguigu_no_data_bak.sql
  • 只备份数据
1
mysqldump -uroot -p atguigu --no-create-info > atguigu_no_create_info_bak.sql

2.8 备份中包含存储过程、函数、事件

1
mysqldump -uroot -p -R -E --databases atguigu > fun_atguigu_bak.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
+ 物理备份与逻辑备份
+ 物理备份
+ 备份磁盘
+ 逻辑备份
+ 备份sql语句
+ mysqldump
+ mysqldump
+ 备份数据库
+ 备份全部数据库
+ 备份部分数据库
+ 备份部分表
+ 备份单表的部分数据
+ 排除某些表的备份
+ 只备份结构或只备份数据
+ 备份存储过程、函数、事件
+ 恢复演示
+ 全库提取单库,单库提取单表,单表提取数据
+ 数据恢复

3. mysql命令恢复数据

1
mysql –u root –p [dbname] < backup.sql

3.1 单库备份中恢复单库

1
2
3
4
#备份文件中包含了创建数据库的语句
mysql -uroot -p < atguigu.sql
#备份文件中不包含了创建数据库的语句
mysql -uroot -p atguigu4< atguigu.sql

3.2 全量备份恢复

1
mysql –u root –p < all.sql

3.3 从全量备份中恢复单库

1
2
sed -n '/^-- Current Database: `atguigu`/,/^-- Current Database: `/p' all_database.sql > atguigu.sql 
#分离完成后我们再导入atguigu.sql即可恢复单个库

3.4 从单库备份中恢复单表

1
2
3
4
5
6
7
8
9
10
cat atguigu.sql | sed -e '/./{H;$!d;}' -e 'x;/CREATE TABLE `class`/!d;q' > class_structure.sql 
cat atguigu.sql | grep --ignore-case 'insert into `class`' > class_data.sql
#用shell语法分离出创建表的语句及插入数据的语句后 再依次导出即可完成恢复

use atguigu;
mysql> source class_structure.sql;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> source class_data.sql;
Query OK, 1 row affected (0.01 sec)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
+ 物理备份
+ 备份myisam
+ 先停止服务或者锁住表

+ 物理恢复
+ 复制文件(允许访问)
+ 重启服务器
+ chown


+ 表的导入与导出
+ 表的导出
+ SELECT ... INTO OUTFILE
+ 文件地址
+ mysqldump
+ mysql命令
+ 表的导入
+ LOAD DATA INFILE
+ mysqlimport

4. 表的导出与导入

4.1 表的导出

1. 使用SELECT…INTO OUTFILE导出文本文件

1
2
SHOW GLOBAL VARIABLES LIKE '%secure%';
SELECT * FROM account INTO OUTFILE "/var/lib/mysql-files/account.txt";

2. 使用mysqldump命令导出文本文件

1
2
3
mysqldump -uroot -p -T "/var/lib/mysql-files/" atguigu account
#
mysqldump -uroot -p -T "/var/lib/mysql-files/" atguigu account --fields-terminated- by=',' --fields-optionally-enclosed-by='\"'

3. 使用mysql命令导出文本文件

1
mysql -uroot -p --execute="SELECT * FROM account;" atguigu> "/var/lib/mysql-files/account.txt"

4.2 表的导入

1. 使用LOAD DATA INFILE方式导入文本文件

1
2
3
LOAD DATA INFILE '/var/lib/mysql-files/account_0.txt' INTO TABLE atguigu.account;
# 或
LOAD DATA INFILE '/var/lib/mysql-files/account_1.txt' INTO TABLE atguigu.account FIELDS TERMINATED BY ',' ENCLOSED BY '\"';

2. 使用mysqlimport方式导入文本文件

1
mysqlimport -uroot -p atguigu '/var/lib/mysql-files/account.txt' --fields-terminated- by=',' --fields-optionally-enclosed-by='\"'

5. 数据库迁移

5.1 概述

数据迁移(data migration)是指选择、准备、提取和转换数据,并将数据从一个计算机存储系统永久地传输到另一个计算机存储系统的过程。此外, 验证迁移数据的完整性 和 退役原来旧的数据存储 ,也被认为是整个数据迁移过程的一部分。

数据库迁移的原因是多样的,包括服务器或存储设备更换、维护或升级,应用程序迁移,网站集成,灾难恢复和数据中心迁移。

根据不同的需求可能要采取不同的迁移方案,但总体来讲,MySQL 数据迁移方案大致可以分为 物理迁移 和 逻辑迁移 两类。通常以尽可能 自动化 的方式执行,从而将人力资源从繁琐的任务中解放出来。

5.2 迁移方案

1、相同版本的数据库之间迁移注意点

指的是在主版本号相同的MySQL数据库之间进行数据库移动。

方式1: 因为迁移前后MySQL数据库的 主版本号相同 ,所以可以通过复制数据库目录来实现数据库迁移,但是物理迁移方式只适用于MyISAM引擎的表。对于InnoDB表,不能用直接复制文件的方式备份数据库。

方式2: 最常见和最安全的方式是使用 mysqldump命令 导出数据,然后在目标数据库服务器中使用MySQL命令导入。

2. 不同版本的数据库之间迁移注意点

例如,原来很多服务器使用5.7版本的MySQL数据库,在8.0版本推出来以后,改进了5.7版本的很多缺陷,因此需要把数据库升级到8.0版本

旧版本与新版本的MySQL可能使用不同的默认字符集,例如有的旧版本中使用latin1作为默认字符集,而最新版本的MySQL默认字符集为utf8mb4。如果数据库中有中文数据,那么迁移过程中需要对 默认字符集 进行修改 ,不然可能无法正常显示数据。

高版本的MySQL数据库通常都会 兼容低版本 ,因此可以从低版本的MySQL数据库迁移到高版本的MySQL数据库。

3. 不同数据库之间迁移注意点

不同数据库之间迁移是指从其他类型的数据库迁移到MySQL数据库,或者从MySQL数据库迁移到其他类

型的数据库。这种迁移没有普适的解决方法。迁移之前,需要了解不同数据库的架构, 比较它们之间的差异 。不同数据库中定义相同类型的数据的 关 键字可能会不同 。例如,MySQL中日期字段分为DATE和TIME两种,而ORACLE日期字段只有DATE;SQL Server数据库中有ntext、Image等数据类型,MySQL数据库没有这些数据类型;MySQL支持的ENUM和SET类型,这些SQL Server数据库不支持。

另外,数据库厂商并没有完全按照SQL标准来设计数据库系统,导致不同的数据库系统的 SQL语句 有差别。例如,微软的SQL Server软件使用的是T-SQL语句,T-SQL中包含了非标准的SQL语句,不能和MySQL 的SQL语句兼容。

不同类型数据库之间的差异造成了互相 迁移的困难 ,这些差异其实是商业公司故意造成的技术壁垒。但是不同类型的数据库之间的迁移并 不是完全不可能 。例如,可以使用 MyODBC 实现MySQL和SQL Server之间的迁移。MySQL官方提供的工具 MySQL Migration Toolkit 也可以在不同数据之间进行数据迁移。MySQL迁移到Oracle时,需要使用mysqldump命令导出sql文件,然后, 手动更改 sql文件中的CREATE语句。

迁移小结

image-20220509231636251

1
2
3
4
5
6
7
8
9
10
11
12
13
+ 数据库迁移
+ 恢复到其他主机上
+ 数据备份和恢复的过程
+ 版本问题
+ 官方工具
+ 迁移小结
+ 删库了,能干啥?
+ 误删行
+ 数据恢复
+ 预防
+ 误删库、表
+ 预防误删
+ rm:误删mysql

6. 删库了不敢跑,能干点啥?

1、delete:误删行

  • 恢复数据比较安全的做法,是 恢复出一个备份 ,或者找一个从库作为 临时库 ,在这个临时库上执行这些操作,然后再将确认过的临时库的数据,恢复回主库。如果直接修改主库,可能导致对数据的 二次破坏 。

  • 当然,针对预防误删数据的问题,建议如下:

    • 把 sql_safe_updates 参数设置为 on 。这样一来,如果我们忘记在delete或者update语句中写where条件,或者where条件里面没有包含索引字段的话,这条语句的执行就会报错。

      • 如果确定要把一个小表的数据全部删掉,在设置了sql_safe_updates=on情况下,可以

        在delete语句中加上where条件,比如where id>=0。

    • 代码上线前,必须经过 SQL审计 。

2、truncate/drop :误删库/表

这种情况下,要想恢复数据,就需要使用 全量备份 ,加 增量日志 的方式了。这个方案要求线上有定期的全量备份,并且实时备份binlog。在这两个条件都具备的情况下,假如有人中午12点误删了一个库,恢复数据的流程如下:

1、取最近一次 全量备份 ,假设这个库是一天一备,上次备份是当天 凌晨2点 ;

2、用备份恢复出一个 临时库 ;

3、从日志备份里面,取出凌晨2点之后的日志;

4、把这些日志,除了误删除数据的语句外,全部应用到临时库。

3、延迟复制备库

如果有 非常核心 的业务,不允许太长的恢复时间,可以考虑搭建延迟复制的备库。一般的主备复制结构存在的问题是,如果主库上有个表被误删了,这个命令很快也会被发给所有从库,进而导致所有从库的数据表也都一起被误删了。

延迟复制的备库是一种特殊的备库,通过 CHANGE MASTER TO MASTER_DELAY = N 命令,可以指定这个备库持续保持跟主库有 N秒的延迟 。比如你把N设置为3600,这就代表了如果主库上有数据被误删了,并且在1小时内发现了这个误操作命令,这个命令就还没有在这个延迟复制的备库执行。这时候到这个备库上执行stop slave,再通过之前介绍的方法,跳过误操作命令,就可以恢复出需要的数据。

4、预防误删库表的方法

  • 账号分离 。这样做的目的是,避免写错命令。比如:
    • 只给业务开发同学DML权限,而不给truncate/drop权限。而如果业务开发人员有DDL需求的话,可以通过开发管理系统得到支持。
    • 即使是DBA团队成员,日常也都规定只使用 只读账号 ,必要的时候才使用有更新权限的账号。
  • 制定操作规范 。比如:
    • 在删除数据表之前,必须先 对表做改名 操作。然后,观察一段时间,确保对业务无影响以后再删除这张表。
    • 改表名的时候,要求给表名加固定的后缀(比如加 _to_be_deleted ),然后删除表的动作必须通过管理系统执行。并且,管理系统删除表的时候,只能删除固定后缀的表。

5、rm:误删MySQL实例

对于一个有高可用机制的MySQL集群来说,不用担心 rm删除数据 了。只是删掉了其中某一个节点的数据的话,HA系统就会开始工作,选出一个新的主库,从而保证整个集群的正常工作。我们要做的就是在这个节点上把数据恢复回来,再接入整个集群。