update,delete 忘加where 条件误操作恢复(模拟Oracle闪回功能)
--传统的做法: 利用最近的FULL 备份+ 增量 binlog 备份,恢复到误操作之前的状态,但是此方法虽好,如果TABLE DML 操作频繁,恢复起来很费力。
--
前提条件: 此方 对于 binlog 日志设置为 binlog_format=ROW 有效。 如果是STATEMENT 则无效。
实例:
(root@test) Mysql >show tables;
+----------------+
| Tables_in_test |
+----------------+
| tab_rm_test |
+----------------+
1 row in set (0.00 sec)
(root@test) Mysql >select * from tab_rm_test;
+---------------+-------------+-----------------+---------------------+--------------+------------+-------------+-----------------------------------+
| database_name | table_name | index_name | last_update | stat_name | stat_value | sample_size | stat_description |
+---------------+-------------+-----------------+---------------------+--------------+------------+-------------+-----------------------------------+
| test | tab_rm_test | GEN_CLUST_INDEX | 2016-08-19 08:54:47 |
n_diff_pfx01 | 0 | 1 | DB_ROW_ID |
| test | tab_rm_test | GEN_CLUST_INDEX | 2016-08-19 08:54:47 |
n_leaf_pages | 1 | NULL | Number of leaf pages in the index |
| test | tab_rm_test | GEN_CLUST_INDEX | 2016-08-19 08:54:47 |
size | 1 | NULL | Number of pages in the index |
| test | tab_rm_test | GEN_CLUST_INDEX | 2016-08-19 08:54:47 |
n_diff_pfx01 | 0 | 1 | DB_ROW_ID |
| test | tab_rm_test | GEN_CLUST_INDEX | 2016-08-19 08:54:47 |
n_leaf_pages | 1 | NULL | Number of leaf pages in the index |
| test | tab_rm_test | GEN_CLUST_INDEX | 2016-08-19 08:54:47 |
size | 1 | NULL | Number of pages in the index |
+---------------+-------------+-----------------+---------------------+--------------+------------+-------------+-----------------------------------+
6 rows in set (0.00 sec)
(root@test) Mysql >show variables like 'binlog%';
+-----------------------------------------+--------------+
| Variable_name | Value |
+-----------------------------------------+--------------+
| binlog_cache_size | 16777216 |
| binlog_checksum | CRC32 |
| binlog_direct_non_transactional_updates | OFF |
| binlog_format | MIXED |
| binlog_max_flush_queue_time | 0 |
| binlog_order_commits | ON |
| binlog_row_image | FULL |
| binlog_rows_query_log_events | OFF |
| binlog_stmt_cache_size | 32768 |
| binlogging_impossible_mode | IGNORE_ERROR |
+-----------------------------------------+--------------+
10 rows in set (0.00 sec)
--其实mixed 是可以的,这里为了试验需要,修改为ROW格式,对 bin-long
修改/etc/my.cnf ,binlog_format=row 重启数据库。
root@test) Mysql >update test.tab_rm_test set stat_name='dddddd_test';
Query OK, 6 rows affected (0.01 sec)
Rows matched: 6 Changed: 6 Warnings: 0
(root@test) Mysql >select * from tab_rm_test;
+---------------+-------------+-----------------+---------------------+-------------+------------+-------------+-----------------------------------+
| database_name | table_name | index_name | last_update | stat_name | stat_value | sample_size | stat_description |
+---------------+-------------+-----------------+---------------------+-------------+------------+-------------+-----------------------------------+
| test | tab_rm_test | GEN_CLUST_INDEX | 2016-08-20 04:05:15 |
dddddd_test | 0 | 1 | DB_ROW_ID |
| test | tab_rm_test | GEN_CLUST_INDEX | 2016-08-20 04:05:15 |
dddddd_test | 1 | NULL | Number of leaf pages in the index |
| test | tab_rm_test | GEN_CLUST_INDEX | 2016-08-20 04:05:15 |
dddddd_test | 1 | NULL | Number of pages in the index |
| test | tab_rm_test | GEN_CLUST_INDEX | 2016-08-20 04:05:15 |
dddddd_test | 0 | 1 | DB_ROW_ID |
| test | tab_rm_test | GEN_CLUST_INDEX | 2016-08-20 04:05:15 |
dddddd_test | 1 | NULL | Number of leaf pages in the index |
| test | tab_rm_test | GEN_CLUST_INDEX | 2016-08-20 04:05:15 |
dddddd_test | 1 | NULL | Number of pages in the index |
+---------------+-------------+-----------------+---------------------+-------------+------------+-------------+-----------------------------------+
6 rows in set (0.00 sec)
--这里之所以创建一个只读用户,是考虑到前端业务之前的用户可能 有修改权限,为了保持数据一致性,前端用户替换为此用户,只能以 read only 方式连接数据库,不影响读操作。
(root@test) Mysql >grant all privileges on test.* to 'recovery'@'%' identified by '123456';
Query OK, 0 rows affected (0.00 sec)
(root@test) Mysql >set global read_only=1;
Query OK, 0 rows affected (0.00 sec)
--找到当前修改 数据保存的bin-log 日志号。
(root@test) Mysql >show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
|
mysql-bin.000010 | 1566 | | mysql | |
+------------------+----------+--------------+------------------+-------------------+
------------------------------
/usr/local/mysql/bin/mysqlbinlog --no-defaults -v -v --base64-output=DECODE-ROWS mysql-bin.000010 | sed -n '/### DELETE FROM test.tt1/,/COMMIT/p' >/home/mysql/delete_test.txt
-- 这里是delete 时忘记加where 条件特许 恢复部分,其他都一样。不一一占用字节了。
------------------------------
--读取对应 bin-log 内容,找到部分数据。
[mysql@sfpay mysql]$
/usr/local/mysql/bin/mysqlbinlog
--no-defaults -v -v --base64-output=DECODE-ROWS
mysql-bin.000010
|grep -B 15 '
dddddd_test
'|more
### UPDATE `test`.`tab_rm_test`
### WHERE
### @1='test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @2='tab_rm_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @3='GEN_CLUST_INDEX' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @4=1471568087 /* TIMESTAMP(0) meta=0 nullable=0 is_null=0 */
### @5='n_diff_pfx01' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @6=0 /* LONGINT meta=0 nullable=0 is_null=0 */
### @7=1 /* LONGINT meta=0 nullable=1 is_null=0 */
### @8='DB_ROW_ID' /* VARSTRING(3072) meta=3072 nullable=0 is_null=0 */
### SET
### @1='test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @2='tab_rm_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @3='GEN_CLUST_INDEX' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @4=1471637115 /* TIMESTAMP(0) meta=0 nullable=0 is_null=0 */
### @5='dddddd_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
--
### UPDATE `test`.`tab_rm_test`
### WHERE
### @1='test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @2='tab_rm_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @3='GEN_CLUST_INDEX' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @4=1471568087 /* TIMESTAMP(0) meta=0 nullable=0 is_null=0 */
### @5='n_leaf_pages' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @6=1 /* LONGINT meta=0 nullable=0 is_null=0 */
### @7=NULL /* LONGINT meta=0 nullable=1 is_null=1 */
### @8='Number of leaf pages in the index' /* VARSTRING(3072) meta=3072 nullable=0 is_null=0 */
### SET
### @1='test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @2='tab_rm_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @3='GEN_CLUST_INDEX' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @4=1471637115 /* TIMESTAMP(0) meta=0 nullable=0 is_null=0 */
### @5='dddddd_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
--
### UPDATE `test`.`tab_rm_test`
### WHERE
### @1='test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @2='tab_rm_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @3='GEN_CLUST_INDEX' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @4=1471568087 /* TIMESTAMP(0) meta=0 nullable=0 is_null=0 */
### @5='size' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @6=1 /* LONGINT meta=0 nullable=0 is_null=0 */
### @7=NULL /* LONGINT meta=0 nullable=1 is_null=1 */
### @8='Number of pages in the index' /* VARSTRING(3072) meta=3072 nullable=0 is_null=0 */
### SET
### @1='test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @2='tab_rm_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @3='GEN_CLUST_INDEX' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @4=1471637115 /* TIMESTAMP(0) meta=0 nullable=0 is_null=0 */
### @5='dddddd_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
--
### UPDATE `test`.`tab_rm_test`
### WHERE
### @1='test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @2='tab_rm_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @3='GEN_CLUST_INDEX' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @4=1471568087 /* TIMESTAMP(0) meta=0 nullable=0 is_null=0 */
### @5='n_diff_pfx01' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @6=0 /* LONGINT meta=0 nullable=0 is_null=0 */
### @7=1 /* LONGINT meta=0 nullable=1 is_null=0 */
### @8='DB_ROW_ID' /* VARSTRING(3072) meta=3072 nullable=0 is_null=0 */
### SET
### @1='test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @2='tab_rm_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @3='GEN_CLUST_INDEX' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @4=1471637115 /* TIMESTAMP(0) meta=0 nullable=0 is_null=0 */
### @5='dddddd_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
--
### UPDATE `test`.`tab_rm_test`
### WHERE
### @1='test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @2='tab_rm_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @3='GEN_CLUST_INDEX' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @4=1471568087 /* TIMESTAMP(0) meta=0 nullable=0 is_null=0 */
### @5='n_leaf_pages' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @6=1 /* LONGINT meta=0 nullable=0 is_null=0 */
### @7=NULL /* LONGINT meta=0 nullable=1 is_null=1 */
### @8='Number of leaf pages in the index' /* VARSTRING(3072) meta=3072 nullable=0 is_null=0 */
### SET
### @1='test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @2='tab_rm_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @3='GEN_CLUST_INDEX' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @4=1471637115 /* TIMESTAMP(0) meta=0 nullable=0 is_null=0 */
### @5='dddddd_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
--
### UPDATE `test`.`tab_rm_test`
### WHERE
### @1='test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @2='tab_rm_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @3='GEN_CLUST_INDEX' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @4=1471568087 /* TIMESTAMP(0) meta=0 nullable=0 is_null=0 */
### @5='size' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @6=1 /* LONGINT meta=0 nullable=0 is_null=0 */
### @7=NULL /* LONGINT meta=0 nullable=1 is_null=1 */
### @8='Number of pages in the index' /* VARSTRING(3072) meta=3072 nullable=0 is_null=0 */
### SET
### @1='test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @2='tab_rm_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @3='GEN_CLUST_INDEX' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
### @4=1471637115 /* TIMESTAMP(0) meta=0 nullable=0 is_null=0 */
### @5='dddddd_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
@5='n_diff_pfx01' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
@5='dddddd_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
@5='n_leaf_pages' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
@5='dddddd_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
@5='size' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
@5='dddddd_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
@5='n_diff_pfx01' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
@5='dddddd_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
@5='n_leaf_pages' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
@5='dddddd_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
@5='size' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
@5='dddddd_test' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */
a, 在更新之前的数据 找回来了,把这些信息放入一个文本文件,因为比较规则,可以使用shell sed 区分一下, 我这里因数据比较小,直接贴出来。
b, 我这是测试表,也没有主键,唯一值,需要一条一条替换(通过
Navicat) 。
(root@test) Mysql >select * from tab_rm_test\G;
*************************** 1. row ***************************
database_name: test
table_name: tab_rm_test
index_name: GEN_CLUST_INDEX
last_update: 2016-08-20 04:45:43
stat_name: n_diff_pfx01
stat_value: 0
sample_size: 1
stat_description: DB_ROW_ID
*************************** 2. row ***************************
database_name: test
table_name: tab_rm_test
index_name: GEN_CLUST_INDEX
last_update: 2016-08-20 04:45:55
stat_name: n_leaf_pages
stat_value: 1
sample_size: NULL
stat_description: Number of leaf pages in the index
*************************** 3. row ***************************
database_name: test
table_name: tab_rm_test
index_name: GEN_CLUST_INDEX
last_update: 2016-08-20 04:46:05
stat_name: size
stat_value: 1
sample_size: NULL
stat_description: Number of pages in the index
*************************** 4. row ***************************
database_name: test
table_name: tab_rm_test
index_name: GEN_CLUST_INDEX
last_update: 2016-08-20 04:46:12
stat_name: n_diff_pfx01
stat_value: 0
sample_size: 1
stat_description: DB_ROW_ID
*************************** 5. row ***************************
database_name: test
table_name: tab_rm_test
index_name: GEN_CLUST_INDEX
last_update: 2016-08-20 04:46:18
stat_name: n_leaf_pages
stat_value: 1
sample_size: NULL
stat_description: Number of leaf pages in the index
*************************** 6. row ***************************
database_name: test
table_name: tab_rm_test
index_name: GEN_CLUST_INDEX
last_update: 2016-08-20 04:48:29
stat_name: size
stat_value: 1
sample_size: NULL
stat_description: Number of pages in the index
6 rows in set (0.00 sec)
------ THE END -------