Un backup che non hai mai testato non è un backup. È un file. Potrebbe essere un buon backup, potrebbe essere corrotto, potrebbe star facendo il backup del database sbagliato — non lo saprai finché non arriva il giorno in cui provi a ripristinarlo. Quel giorno è sempre un sabato, è sempre quando il telefono sta per scaricarsi, ed è sempre quando il CEO è in copia nell’email.
Questa lezione parla di costruire una strategia di backup di cui ti fidi davvero. Tipi di backup, recovery model, l’esercitazione di restore che dovresti fare ogni trimestre, e la complicazione specifica per l’UE che è la regolamentazione sulla data residency.
I tre tipi di backup
Backup FULL
Una copia completa del database in un dato momento. Contiene ogni pagina di dati e abbastanza log da rendere il backup internamente consistente.
BACKUP DATABASE Runehold
TO DISK = N'D:\Backups\Runehold_FULL_20260315.bak'
WITH FORMAT, INIT, COMPRESSION, CHECKSUM, STATS = 10;
FORMAT, INIT— sovrascrivi il file se esiste. Sicurezza: vogliamo quasi sempre un backup fresco, non in append.COMPRESSION— file molto più piccolo. SQL Server Enterprise moderno include la compression gratis; Standard dal 2022.CHECKSUM— verifica le pagine mentre vengono salvate; cattura la corruzione prima.STATS = 10— stampa il progresso ogni 10%.
Pianificazione tipica di Runehold: un backup FULL notturno intorno alle 02:00 UTC. Impiega circa 25 minuti.
Backup DIFFERENTIAL
Tutto ciò che è cambiato dall’ultimo FULL. Più piccolo e veloce di un FULL, ma dipende dalla disponibilità del FULL.
BACKUP DATABASE Runehold
TO DISK = N'D:\Backups\Runehold_DIFF_20260315_12.bak'
WITH DIFFERENTIAL, FORMAT, INIT, COMPRESSION, CHECKSUM;
Pattern comune: FULL notturno, DIFF ogni 6 ore. Il restore coinvolge FULL + l’ultimo DIFF — due file invece di tanti.
Backup LOG
Tutti i record di log dall’ultimo backup del log. Essenziale per il point-in-time recovery e per evitare che il log file cresca senza limiti nel recovery model FULL.
BACKUP LOG Runehold
TO DISK = N'D:\Backups\Runehold_LOG_20260315_1245.trn'
WITH FORMAT, INIT, COMPRESSION, CHECKSUM;
Pianificazione tipica: ogni 15 minuti durante l’orario lavorativo. Significa che se il database va giù, perdi al massimo 15 minuti di cambiamenti (RPO — Recovery Point Objective = 15 min).
Recovery model, di nuovo
Dalla lezione 30:
- SIMPLE — niente backup del log possibili. RPO = ultimo FULL o DIFF.
- FULL — backup del log richiesti; point-in-time recovery; il log resta piccolo tra i backup.
- BULK_LOGGED — di nicchia.
Regola: ogni database di produzione che contiene dati di cui piangeresti la perdita dovrebbe essere in recovery FULL con backup del log regolari. Tutto il resto — DW di reporting, dev, test, scratch del data lake — può essere SIMPLE.
Restore: l’esercitazione vera
Non puoi dire di avere backup se non hai fatto un restore. Ecco l’esercitazione che ogni team dovrebbe fare almeno trimestralmente.
Step 1: ripristina l’ultimo FULL
RESTORE DATABASE Runehold_Recovery
FROM DISK = N'D:\Backups\Runehold_FULL_20260315.bak'
WITH
MOVE N'Runehold' TO N'E:\RestoreTest\Runehold.mdf',
MOVE N'Runehold_log' TO N'E:\RestoreTest\Runehold_log.ldf',
NORECOVERY,
REPLACE,
STATS = 5;
MOVE— perché stai ripristinando in una posizione diversa (o macchina diversa) con path diversi. SenzaMOVE, SQL Server prova a mettere i file dove erano originalmente, il che fallisce se il path non esiste.NORECOVERY— lascia il database in stato “restoring”; pronto ad applicare altri backup.REPLACE— sovrascrivi se esiste un database con lo stesso nome (raro, ma utile).
Step 2: applica l’ultimo DIFF
RESTORE DATABASE Runehold_Recovery
FROM DISK = N'D:\Backups\Runehold_DIFF_20260315_12.bak'
WITH NORECOVERY;
Step 3: applica i backup del log fino al punto temporale desiderato
RESTORE LOG Runehold_Recovery
FROM DISK = N'D:\Backups\Runehold_LOG_20260315_1215.trn'
WITH NORECOVERY;
RESTORE LOG Runehold_Recovery
FROM DISK = N'D:\Backups\Runehold_LOG_20260315_1230.trn'
WITH NORECOVERY;
-- Fermati a un momento specifico
RESTORE LOG Runehold_Recovery
FROM DISK = N'D:\Backups\Runehold_LOG_20260315_1245.trn'
WITH STOPAT = N'2026-03-15 12:38:42', NORECOVERY;
Step 4: porta il database online
RESTORE DATABASE Runehold_Recovery WITH RECOVERY;
Step 5: verifica
Connettiti. Esegui query. Confronta i conteggi delle righe con quello che ti aspettavi. Prendi una manciata di tabelle e verifica che righe campione sembrino giuste.
Step 6: documenta cosa hai fatto e quanto è durato
L’RTO — Recovery Time Objective — è il downtime massimo accettabile. Se la tua esercitazione di restore ha impiegato 45 minuti, il tuo RTO è 45 minuti. Se la dirigenza si aspetta 15 minuti, hai un gap e devi lavorarci sopra.
Fai questa esercitazione ogni trimestre. Ruota chi la guida così più persone conoscono i passi.
Trovare e applicare la giusta catena di log
Quando il disastro colpisce, devi sapere ogni backup nella catena. Script veloce:
-- Storico FULL + DIFF + LOG per un database
WITH history AS (
SELECT bs.database_name,
bs.type,
bs.backup_start_date,
bs.backup_finish_date,
bmf.physical_device_name
FROM msdb.dbo.backupset AS bs
JOIN msdb.dbo.backupmediafamily AS bmf ON bmf.media_set_id = bs.media_set_id
WHERE bs.database_name = 'Runehold'
AND bs.backup_start_date >= DATEADD(DAY, -7, GETDATE())
)
SELECT * FROM history ORDER BY backup_start_date;
Mostra ogni backup che SQL Server Agent ha registrato. Comodo durante un disastro.
Verificare i backup prima del disastro
RESTORE VERIFYONLY controlla un file di backup per corruzione di base senza ripristinarlo davvero:
RESTORE VERIFYONLY FROM DISK = N'D:\Backups\Runehold_FULL_20260315.bak';
Veloce, economico, sicuro. Ogni job di backup dovrebbe eseguire RESTORE VERIFYONLY immediatamente dopo il completamento del backup. Cattura backup corrotti prima che ti servano.
Inoltre: periodicamente fai un test completo di restore (l’esercitazione qui sopra) per catturare problemi che VERIFYONLY non vede. Ogni qualche mese.
Backup su Azure Blob o S3
SQL Server moderno può fare backup direttamente su Azure Blob Storage (e con qualche tooling, su S3). Copie off-site senza alcuno scripting di copia file.
BACKUP DATABASE Runehold
TO URL = N'https://runehold.blob.core.windows.net/backups/Runehold_20260315.bak'
WITH CREDENTIAL = N'AzureStorageCredential',
COMPRESSION, CHECKSUM, FORMAT, INIT;
La CREDENTIAL è un oggetto SQL Server che contiene il SAS token Azure. Si configura una volta, si usa per sempre.
Per le aziende UE come Runehold, i backup off-site tipicamente vivono in una regione Azure solo-UE o in un bucket S3 solo-UE. La conformità sulla data residency conta.
GDPR, backup, e il “diritto all’oblio”
Una questione scomoda. Quando un cliente esercita il suo diritto GDPR alla cancellazione, devi eliminare i suoi dati. Facile nelle tabelle live. Non facile nei backup — un backup fatto ieri contiene la riga che dovresti cancellare oggi.
Approccio standard alla compliance: documenta nella tua privacy policy che i backup sono conservati per un periodo definito (spesso 30-90 giorni), e la cancellazione si applica ai dati live immediatamente più nei backup man mano che i vecchi backup escono dalla finestra di retention. Non modifichi i vecchi backup; li ruoti via.
Un’analisi legale completa è fuori scopo qui. Discuti con chi gestisce la funzione di DPO (Data Protection Officer) della tua azienda. Sii solo consapevole che l’intersezione tra backup e GDPR ha risposte documentate; non inventartene di tue.
Esegui questo sulla tua macchina
USE master;
GO
-- 1. Fai un backup completo sul tuo disco
BACKUP DATABASE Runehold
TO DISK = N'C:\Temp\Runehold_FULL.bak'
WITH FORMAT, INIT, COMPRESSION, CHECKSUM, STATS = 10;
-- 2. Verificalo
RESTORE VERIFYONLY FROM DISK = N'C:\Temp\Runehold_FULL.bak';
-- 3. Fai backup del log (richiede recovery FULL)
ALTER DATABASE Runehold SET RECOVERY FULL;
BACKUP DATABASE Runehold TO DISK = N'C:\Temp\Runehold_FULL.bak' WITH FORMAT, INIT;
BACKUP LOG Runehold TO DISK = N'C:\Temp\Runehold_LOG.trn' WITH FORMAT, INIT;
-- 4. Ripristina con un nuovo nome (l'esercitazione)
RESTORE DATABASE Runehold_Recovery
FROM DISK = N'C:\Temp\Runehold_FULL.bak'
WITH
MOVE N'Runehold' TO N'C:\Temp\Runehold_R.mdf',
MOVE N'Runehold_log' TO N'C:\Temp\Runehold_R.ldf',
NORECOVERY, REPLACE;
RESTORE LOG Runehold_Recovery
FROM DISK = N'C:\Temp\Runehold_LOG.trn'
WITH RECOVERY;
-- 5. Verifica il database ripristinato
SELECT COUNT(*) FROM Runehold_Recovery.Sales.Customer;
SELECT COUNT(*) FROM Runehold.Sales.Customer;
-- Dovrebbero coincidere.
-- 6. Elimina il restore di test
DROP DATABASE Runehold_Recovery;
Eseguilo da capo a coda una volta. Fanne memoria muscolare. Il giorno in cui dovrai farlo in produzione non sarà una bella giornata, ma sarà una giornata veloce.
Prossimo: SQL Server Agent — come schedulare i backup di cui sopra, più tutta l’altra roba ripetibile che un DBA automatizza.