Preskočiť na obsah
Návod

Obnova databázy k bodu v čase (point-in-time restore)

Ako obnoviť databázu k presnému času pred chybou (zmazané dáta, zlý UPDATE): predpoklady, tail-log backup, nájdenie záloh, obnova pod iným menom, STOPAT, NORECOVERY vs. RECOVERY, STANDBY a presun dát späť. Poznámky k TDE a Always On.

4 min čítania 9 krokov SQL Server 2016+
Niekto zmazal dáta, spustil `UPDATE` bez `WHERE` alebo nasadenie poškodilo tabuľku – a treba sa vrátiť do stavu „o 14:31, tesne pred tým“. Obnova k bodu v čase funguje len s neprerušenou reťazou log záloh.

> [!CAUTION]
> Neobnovuj **cez produkčnú databázu**, kým nemáš istotu. Obnov ju **vedľa pod iným menom**, over dáta a späť prenes len to, čo treba. Obnova cez produkciu zahodí všetko, čo sa stalo po zvolenom čase.

## 1. Predpoklady

- Databáza je vo **FULL** recovery modeli (pri BULK_LOGGED sa nedá zastaviť uprostred log zálohy s bulk operáciou).
- Existuje FULL záloha dokončená **pred** cieľovým časom a **všetky** LOG zálohy od nej po cieľový čas (prípadne DIFF, ktorý časť logov nahradí).
- Poznáš cieľový čas v **lokálnom čase servera** (msdb aj `STOPAT` pracujú s ním).

## 2. Zastav ďalšie škody a zachráň koniec logu

1. Ak chyba stále prebieha (job, aplikácia), zastav ju.
2. Ak cieľový čas je **po** poslednej log zálohe, urob hneď log backup (alebo nechaj dobehnúť plánovaný). Pri obnove pod iným menom produkcia beží ďalej – stačí bežný log backup.
3. Ak by si obnovoval na mieste pôvodnej databázy, urob **tail-log backup** `WITH NORECOVERY` – databáza prejde do stavu RESTORING a ďalšie zmeny nevzniknú:

```sql
BACKUP LOG MojaDB TO DISK = N'<cesta>/MojaDB_tail.trn' WITH NORECOVERY;
```

## 3. Nájdi zálohy

1. [História záloh](script.php?id=31&s=historia-zaloh-typ-velkost-kompresia-subor) – prehľad, čo v msdb je a kde ležia súbory.
2. [Generátor RESTORE príkazov](script.php?id=50&s=generator-restore-prikazov-z-historie-zaloh) – zadaj `DatabaseName`, `StopAt` a `TargetName` (napr. `MojaDB_obnova`). Skript poskladá FULL → DIFF → LOG s `STOPAT` a upozorní na **dieru v reťazi**.
3. Ak sú zálohy na inom serveri alebo msdb nemáš, poskladaj poradie z `RESTORE HEADERONLY` nad súbormi.

## 4. Obnov vedľa produkcie

```sql
RESTORE DATABASE MojaDB_obnova FROM DISK = N'<full>.bak'
    WITH NORECOVERY, STATS = 10,
         MOVE N'MojaDB'     TO N'<data>/MojaDB_obnova.mdf',
         MOVE N'MojaDB_log' TO N'<log>/MojaDB_obnova_log.ldf';
RESTORE DATABASE MojaDB_obnova FROM DISK = N'<diff>.bak' WITH NORECOVERY;
RESTORE LOG MojaDB_obnova FROM DISK = N'<log1>.trn' WITH NORECOVERY, STOPAT = N'2026-11-07T14:31:00';
RESTORE LOG MojaDB_obnova FROM DISK = N'<log2>.trn' WITH NORECOVERY, STOPAT = N'2026-11-07T14:31:00';
RESTORE DATABASE MojaDB_obnova WITH RECOVERY;
```

- Všetky `RESTORE LOG` v sekvencii majú **rovnaký** `STOPAT`. Obnoví sa posledný commit k tomuto času.
- `NORECOVERY` = databáza čaká na ďalšie zálohy. `RECOVERY` = koniec, databáza sa otvorí a nedokončené transakcie sa vrátia. Po `RECOVERY` už ďalší log nepridáš – ak si sa zmýlil v čase, začínaš od FULL.
- Priebeh sleduj v [Priebeh BACKUP / RESTORE / DBCC](script.php?id=21&s=priebeh-backup-restore-dbcc).

> [!TIP]
> Nepoznáš presný čas? Obnovuj logy `WITH STANDBY = N'<cesta>/undo.dat'` namiesto `NORECOVERY`. Databáza je medzi krokmi **len na čítanie** – pozrieš dáta, a ak ešte nie sú zlé, pokračuješ ďalším logom (alebo menším krokom so `STOPAT`). Pri chybe s označenou transakciou (`BEGIN TRAN … WITH MARK`) použi `STOPBEFOREMARK`.

## 5. Over výsledok a prenes dáta späť

1. Porovnaj počty riadkov a kľúčové záznamy medzi `MojaDB_obnova` a produkciou.
2. Späť prenes len dotknuté riadky (`INSERT … SELECT` / `MERGE` cez tri časti mena) – v transakcii a s kontrolou cudzích kľúčov a triggrov. Pri veľkom objeme zváž SSIS alebo BCP.
3. Obnovenú kópiu po dohode zmaž – zaberá miesto a mätie používateľov.

## 6. Pasce

- **TDE:** cieľový server musí mať **certifikát s privátnym kľúčom**, ktorým je databáza šifrovaná – over v [Certifikáty a TDE](script.php?id=54&s=certifikaty-a-tde-expiracia-a-zalohy-klucov). Bez neho RESTORE zlyhá.
- **Always On:** obnovuješ **mimo AG** (pod iným menom alebo na inom serveri). Zálohy urobené na sekundárnej replike sú v **msdb tej repliky** – generátor na primárke ich neuvidí.
- **COPY_ONLY** zálohy reťaz neprerušia, ale generátor ich zámerne nepoužíva. Zmena na SIMPLE recovery a späť reťaz **preruší** – od toho bodu potrebuješ nový FULL / DIFF.
- Po obnove na iný server rieš [Orphaned users](script.php?id=37&s=orphaned-users-pouzivatelia-bez-loginu).
- RESTORE vyžaduje `CREATE DATABASE` (nová DB) alebo `sysadmin` / `dbcreator`; `db_owner` nestačí.

## Zdroje

- [Restore a database to a point in time (full recovery model)](https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/restore-a-sql-server-database-to-a-point-in-time-full-recovery-model)
- [Tail-log backups](https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/tail-log-backups-sql-server)
- [backupset (msdb)](https://learn.microsoft.com/en-us/sql/relational-databases/system-tables/backupset-transact-sql)
- [Transparent data encryption (TDE)](https://learn.microsoft.com/en-us/sql/relational-databases/security/encryption/transparent-data-encryption)