Qué vas a conseguir
Que la base de datos del ERP se pueda devolver a cualquier minuto de los últimos días, y que lo hayas comprobado antes de necesitarlo. En una empresa industrial con plantas en varios países el ERP no descansa: cuando en una sede es de noche, en otra se están cerrando pedidos, lanzando órdenes de fabricación o haciendo el cierre de mes. No hay ventana tranquila para copias largas ni margen para descubrir el día del problema que falta un log.
Antes de empezar
- El nombre de la base de datos del ERP y de sus bases auxiliares (en los ejemplos,
ERP_PRODensrv-sql-erp01). - Un servidor de pruebas (
srv-sql-test01) con espacio para restaurar la base entera; nunca se restaura encima de producción para investigar. - El RPO y el RTO acordados con negocio: cuánto dato se puede perder y cuánto puede tardar la vuelta.
- El contacto del consultor o partner del ERP: cualquier corrección de datos directa en tablas del ERP se hace con su visto bueno.
- La zona horaria del servidor SQL y la de cada planta. Las horas de
msdby deSTOPATson las del servidor.
1. El modelo de recuperación
| Modelo | Qué permite | Cuándo |
|---|---|---|
SIMPLE | Solo volver a la última completa o diferencial | Bases de pruebas, staging, informes que se regeneran |
FULL | Copias de log y restauración a un punto en el tiempo | El ERP de producción, siempre |
BULK_LOGGED | Como FULL, pero las cargas masivas van mínimamente registradas | Solo durante una carga puntual; no permite STOPAT dentro de ese log |
SELECT name, recovery_model_desc, log_reuse_wait_desc FROM sys.databases WHERE name LIKE 'ERP%';name recovery_model_desc log_reuse_wait_desc------------ ------------------- -------------------ERP_PROD FULL LOG_BACKUPERP_PROD_DOC SIMPLE NOTHINGALTER DATABASE [ERP_PROD_DOC] SET RECOVERY FULL;LOG_BACKUP es normal en una base FULL: el log espera a la siguiente copia de log. Si una base pasa a FULL, la cadena empieza con la siguiente copia completa; hasta entonces, las copias de log no sirven.
2. La pauta de copias y dónde se guardan
- Completa semanal, la noche del sábado de la sede del servidor, revisando antes que no coincide con el cierre de mes de ninguna planta.
- Diferencial diaria, para no tener que aplicar una semana de logs.
- Log cada 15 minutos (o menos si el RPO lo pide), 24x7.
- Siempre con
CHECKSUMyCOMPRESSION, y a un destino fuera del propio servidor: un recurso compartido de copias o una URL de almacenamiento de objetos.
# Completa, a un recurso compartido (la cuenta del servicio SQL necesita escritura)BACKUP DATABASE [ERP_PROD] TO DISK = N'\\srv-bkp01\sql$\ERP_PROD\ERP_PROD_FULL_20261024.bak' WITH CHECKSUM, COMPRESSION, STATS = 10;# Diferencial diariaBACKUP DATABASE [ERP_PROD] TO DISK = N'\\srv-bkp01\sql$\ERP_PROD\ERP_PROD_DIFF_20261026.bak' WITH DIFFERENTIAL, CHECKSUM, COMPRESSION;# Log cada 15 minutosBACKUP LOG [ERP_PROD] TO DISK = N'\\srv-bkp01\sql$\ERP_PROD\ERP_PROD_LOG_20261027_1045.trn' WITH CHECKSUM, COMPRESSION;# Alternativa: a una URL con una credencial SAS creada para ese contenedorBACKUP DATABASE [ERP_PROD] TO URL = N'https://contosobkp.blob.core.windows.net/sql/ERP_PROD_FULL_20261024.bak' WITH CHECKSUM, COMPRESSION;# Comprobar que el fichero se puede leer y que los checksums cuadranRESTORE VERIFYONLY FROM DISK = N'\\srv-bkp01\sql$\ERP_PROD\ERP_PROD_FULL_20261024.bak' WITH CHECKSUM;The backup set on file 1 is valid.- Un fichero por copia con fecha y hora en el nombre. Escribir siempre sobre el mismo
.bakconINITdeja una única copia y ningún historial. - Si otra herramienta (el agente de la plataforma de copias) hace también copias del ERP, una de las dos debe usar
COPY_ONLY; dos cadenas de diferenciales sobre la misma base terminan en una restauración que no encuentra su completa. VERIFYONLYcomprueba que la copia es legible, no que la base esté sana. Eso solo lo dice una restauración real y unDBCC CHECKDBsobre ella.
3. Retención
| Tipo | En el recurso compartido | Copia fuera de la sede |
|---|---|---|
| Completa | 5 semanas | Una por mes, 12 meses (o lo que pida auditoría) |
| Diferencial | 14 días | No |
| Log | 14 días | Mientras exista la completa de la que dependen |
La limpieza la hace un trabajo del SQL Server Agent o la plataforma de copias, nunca alguien borrando ficheros a mano: un log borrado rompe la cadena desde ese punto. Las copias de cierre de ejercicio se etiquetan y se guardan aparte, porque finanzas o auditoría las pedirán años después.
4. La cadena de restauración en el servidor de pruebas
Para volver a las 10:39 del martes, la cadena es: la última completa anterior, la última diferencial posterior a esa completa y anterior a las 10:39, y todos los logs desde esa diferencial hasta el que contiene las 10:39.
RESTORE DATABASE [ERP_PROD_1039] FROM DISK = N'\\srv-bkp01\sql$\ERP_PROD\ERP_PROD_FULL_20261024.bak' WITH MOVE N'ERP_PROD' TO N'E:\SQLData\ERP_PROD_1039.mdf', MOVE N'ERP_PROD_log' TO N'F:\SQLLog\ERP_PROD_1039.ldf', NORECOVERY, STATS = 10;RESTORE DATABASE [ERP_PROD_1039] FROM DISK = N'\\srv-bkp01\sql$\ERP_PROD\ERP_PROD_DIFF_20261026.bak' WITH NORECOVERY;RESTORE LOG [ERP_PROD_1039] FROM DISK = N'\\srv-bkp01\sql$\ERP_PROD\ERP_PROD_LOG_20261027_0015.trn' WITH NORECOVERY;# ... un RESTORE LOG por cada fichero, en orden ...RESTORE LOG [ERP_PROD_1039] FROM DISK = N'\\srv-bkp01\sql$\ERP_PROD\ERP_PROD_LOG_20261027_1045.trn' WITH STOPAT = N'2026-10-27T10:39:00', RECOVERY;RESTORE LOG successfully processed 1874 pages in 0.412 seconds (35.532 MB/sec).- Los nombres lógicos para
MOVEsalen deRESTORE FILELISTONLY FROM DISK = .... - Mientras la base está en
NORECOVERYse pueden seguir aplicando copias;RECOVERYla abre y cierra la cadena. Si no sabes el minuto exacto, restaura los logs conSTANDBY = N'F:\SQLLog\ERP_PROD_1039.tuf'en lugar deNORECOVERY: la base queda en solo lectura entre log y log y puedes consultarla para ir acercándote. - Anota cuánto ha tardado, con
DBCC CHECKDBal final: esa es tu cifra real de RTO para el ERP. Repite la prueba cada trimestre.
5. El historial de msdb
SELECT TOP (8) bs.type, bs.backup_start_date, bs.backup_finish_date, bs.has_backup_checksums, bs.is_copy_only, bmf.physical_device_name FROM msdb.dbo.backupset bs JOIN msdb.dbo.backupmediafamily bmf ON bs.media_set_id = bmf.media_set_id WHERE bs.database_name = N'ERP_PROD' ORDER BY bs.backup_finish_date DESC;type backup_start_date backup_finish_date has_backup_checksums is_copy_only physical_device_name---- ------------------- ------------------- -------------------- ------------ ----------------------------------------------L 2026-10-27 10:45:00 2026-10-27 10:45:04 1 0 \\srv-bkp01\sql$\ERP_PROD\ERP_PROD_LOG_20261027_1045.trnI 2026-10-26 23:00:00 2026-10-26 23:06:41 1 0 \\srv-bkp01\sql$\ERP_PROD\ERP_PROD_DIFF_20261026.bakD 2026-10-24 22:00:00 2026-10-24 23:12:18 1 0 \\srv-bkp01\sql$\ERP_PROD\ERP_PROD_FULL_20261024.bakD es completa, I diferencial y L log. Con esta consulta montas la lista de ficheros de la cadena sin buscar a ojo en el recurso compartido. msdb.dbo.restorehistory, en el servidor de pruebas, deja constancia de cada restauración que haces para la prueba trimestral.
6. El ticket: "alguien ha borrado filas en el ERP a las 10:40, ¿se pueden recuperar?"
Martes. Desde una planta de otro país avisan de que han desaparecido líneas de pedidos de compra de un proveedor. El ERP sigue en uso en todas las sedes.
- Qué hora es "las 10:40": la de la planta, no la del servidor. Si la planta va una hora por detrás, para el servidor son las 11:40. Confírmalo con el usuario y con el log de auditoría del ERP si lo tiene.
- No se restaura producción: volver todo el ERP atrás borraría el trabajo del resto de plantas desde entonces. Se restaura una copia aparte y se recuperan solo esas filas.
- Asegura el log: lanza una copia de log ya (sin
NORECOVERY, producción sigue abierta) para que el periodo del borrado esté en una copia y no dependa de la siguiente programada. - Restaura en
srv-sql-test01la cadena hasta un minuto antes del borrado (sección 4), con otro nombre de base. - Compara: las filas que están en la copia y no en producción, por la clave de la tabla, en una consulta con el consultor del ERP delante.
- Devuélvelas como diga el ERP: con su herramienta de importación, con un script revisado por el partner (cuidado con columnas
IDENTITY, triggers y tablas relacionadas) o volviéndolas a introducir si son pocas. Lo que no se hace es unINSERTdirecto sin que nadie del ERP lo valide. - Cierra con causa: quién borró, desde qué usuario y por qué pudo hacerlo. Muchas veces es un permiso de más en un perfil del ERP, no un fallo técnico.
Siguientes pasos
- La guía de PostgreSQL/MySQL/SQL Server del Nivel 3 cubre la administración diaria de las bases de datos.
- La de Veeam Backup explica cómo encaja la copia del servidor SQL con la de las máquinas virtuales.
- La de Backup y DR/BCP del Nivel 4 sitúa el ERP dentro del plan de continuidad.
¿Falta algo o en tu entorno es distinto? Escríbeme y lo corrijo.
Tech Career Lab · newsletter
¿Te ha servido? Cada dos semanas envío una idea práctica para perfiles IT: LinkedIn, proyectos, networking y procesos de selección.
Apúntate y llévate las 33 ideas →