jueves, 27 de noviembre de 2014

Recuperar los datos de MySQL se pierden con mysqlbinlog ejemplo de punto en el tiempo de recuperación

Original post: http://anothermysqldba.blogspot.com/2014/11/recover-lost-mysql-data-with.html

Copia de seguridad de copia de seguridad ... ... Copia de seguridad ... pero claro .. también hay que controlar y probar esas copias de seguridad a menudo de lo contrario podrían ser inútil. Tener sus MySQL binlogs habilitado sin duda puede ayudar en momentos de una emergencia también. Los binlogs MySQL a menudo se hace referencia en lo que respecta a la replicación de MySQL, por una buena razón, almacenan todas las consultas o eventos que alteren los datos ( basado en la fila es un poco diferente, pero este ejemplo). Los binlogs tienen un impacto mínimo en el rendimiento del servidor al considerar las opciones de recuperación que proporcionan. 


[anothermysqldba]> show variables like 'log_bin%'; 
+---------------------------------+--------------------------------------------+ 
| Variable_name | Value | 
+---------------------------------+--------------------------------------------+ 
| log_bin | ON | 
| log_bin_basename | /var/lib/mysql/binlogs/mysql-binlogs | 
| log_bin_index | /var/lib/mysql/binlogs/mysql-binlogs.index | 

show variables like 'binlog_format%'; 
+---------------+-------+ 
| Variable_name | Value | 
+---------------+-------+ 
| binlog_format | MIXED | 
+---------------+-------+ 


Así que esto es sólo un ejemplo sencillo utilizando mysqlbinlog para recuperar datos de un binlog y aplicarlo de nuevo a la base de datos. 

En primer lugar tenemos algo que perder. Si algo iba a pasar a nuestra base de datos tenemos que ser capaces de recuperar los datos o tal vez es sólo una manera de recuperarse de someones error. 


CREATE TABLE `table_w_rdata` ( 
`id` int(11) NOT NULL AUTO_INCREMENT, 
`somedata` varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, 
`moredata` varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, 
PRIMARY KEY (`id`) 
) ENGINE=InnoDB; 

Podemos fingir aquí y asumir que tenemos desarrolladores / administradores de bases que no se comunican muy bien y / o almacenamiento de copias de su código. 


delimiter // 
CREATE PROCEDURE populate_dummydata( IN rowsofdata INT ) 
BEGIN 

SET @A = 3; 
SET @B = 15 - @A; 
SET @C = 16; 
SET @D = 25 - @C; 

WHILE rowsofdata > 0 DO 
INSERT INTO table_w_rdata 
SELECT NULL, SUBSTR(md5(''),FLOOR( @A + (RAND() * @B ))) as somedata, SUBSTR(md5(''),FLOOR( @C + (RAND() * @D ))) AS moredata ; 
SET rowsofdata = rowsofdata - 1; 
END WHILE; 
END// 
delimiter ; 
call populate_dummydata(50); 

> SELECT NOW() \G 
*************************** 1. row *************************** 
NOW(): 2014-11-27 17:32:25 
1 row in set (0.00 sec) 

> SELECT * from table_w_rdata WHERE id > 45; 
+----+----------------------------+------------------+ 
| id | somedata | moredata | 
+----+----------------------------+------------------+ 
| 46 | b204e9800998ecf8427e | 0998ecf8427e | 
| 47 | d98f00b204e9800998ecf8427e | 8ecf8427e | 
| 48 | b204e9800998ecf8427e | 800998ecf8427e | 
| 49 | 98f00b204e9800998ecf8427e | e9800998ecf8427e | 
| 50 | 98f00b204e9800998ecf8427e | 998ecf8427e | 
+----+----------------------------+------------------+ 

Mientras se crea un procedimiento más tarde se escribe sobre otra persona incorrecta. 

DROP PROCEDURE IF EXISTS populate_dummydata ; 
delimiter // 
CREATE PROCEDURE populate_dummydata( IN rowsofdata INT ) 
BEGIN 

SET @A = 3; 
SET @B = 15 - @A; 
SET @C = 16; 
SET @D = 25 - @C; 

WHILE rowsofdata > 0 DO 
INSERT INTO table_w_rdata 
SELECT NULL, SUBSTR(md5(''),FLOOR( @C + (RAND() * @A ))) as somedata, SUBSTR(md5(''),FLOOR( @B + (RAND() * @D ))) AS moredata ; 
SET rowsofdata = rowsofdata - 1; 
END WHILE; 
END// 
delimiter ; 

call populate_dummydata(50); 
> SELECT NOW(); SELECT * from table_w_rdata WHERE id > 95; 
+---------------------+ 
| NOW() | 
+---------------------+ 
| 2014-11-27 17:36:28 | 
+---------------------+ 
1 row in set (0.00 sec) 

+-----+-------------------+---------------------+ 
| id | somedata | moredata | 
+-----+-------------------+---------------------+ 
| 96 | 4e9800998ecf8427e | 00998ecf8427e | 
| 97 | 9800998ecf8427e | 800998ecf8427e | 
| 98 | e9800998ecf8427e | 204e9800998ecf8427e | 
| 99 | e9800998ecf8427e | 4e9800998ecf8427e | 
| 100 | 9800998ecf8427e | 04e9800998ecf8427e | 
+-----+-------------------+---------------------+ 


La versión sustituida del procedimiento no genera valores aleatorios como el equipo quería. El creador original del procedimiento acaba de dejar de frustración. Entonces, ¿qué hacer? Un poco de tiempo ha pasado desde que fue creado también. Hacemos saber el nombre de base de datos, nombre de la rutina y el marco general de tiempo cuando se creó el procedimiento incorrecto y por suerte para nosotros los registros bin todavía están alrededor, para que podamos ir a buscarlo. 

Tenemos que echar un vistazo general en todo ya que sólo queremos un punto en el tiempo de recuperación de esta procedure.We suceda a encontrar el procedimiento y la posición en el binlog antes y después de ella. 


NOW(): 2014-11-27 19:46:17 
# mysqlbinlog --start-datetime=20141127173200 --stop-datetime=20141127173628 --database=anothermysqldba mysql-binlogs.000001 | more 

at 253053 
at 253564 

# mysql anothermysqldba --login-path =local -e "DROP PROCEDURE populate_dummydata"; 
# mysqlbinlog --start-position=253053 --stop-position=253564 --database=anothermysqldba mysql-binlogs.000001 | mysql --login-path =local anothermysqldba 


> SHOW CREATE PROCEDURE populate_dummydata\G 
*************************** 1. row *************************** 
Procedure: populate_dummydata 
sql_mode: NO_AUTO_VALUE_ON_ZERO,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION 
Create Procedure: CREATE DEFINER=`root`@`localhost` PROCEDURE `populate_dummydata`( IN rowsofdata INT ) 
BEGIN 

SET @A = 3; 
SET @B = 15 - @A; 
SET @C = 16; 
SET @D = 25 - @C; 

WHILE rowsofdata > 0 DO 
INSERT INTO table_w_rdata 
SELECT NULL, SUBSTR(md5(''),FLOOR( @A + (RAND() * @B ))) as somedata, SUBSTR(md5(''),FLOOR( @C + (RAND() * @D ))) AS moredata ; 
SET rowsofdata = rowsofdata - 1; 
END WHILE; 
END 
character_set_client: utf8 
collation_connection: utf8_general_ci 
Database Collation: latin1_swedish_ci 
1 row in set (0.00 sec) 

NOW(): 2014-11-27 19:51:03 
> call populate_dummydata(50); 
> SELECT * from table_w_rdata WHERE id > 145; 
+-----+-----------------------------+------------------+ 
| id | somedata | moredata | 
+-----+-----------------------------+------------------+ 
| 146 | 98f00b204e9800998ecf8427e | 800998ecf8427e | 
| 147 | cd98f00b204e9800998ecf8427e | 800998ecf8427e | 
| 148 | 204e9800998ecf8427e | 98ecf8427e | 
| 149 | d98f00b204e9800998ecf8427e | e9800998ecf8427e | 
| 150 | 204e9800998ecf8427e | 9800998ecf8427e | 
+-----+-----------------------------+------------------+ 


Recuperamos nuestro procedimiento del registro binario a través de un punto en el tiempo de recuperación . 
Este es un ejemplo simple, pero es un ejemplo de las herramientas que puede utilizar en movimiento hacia adelante. 

Es por esto que los binlogs son tan valiosos. 

URL útil: