Skip to content

Commit a6f0347

Browse files
adela-bytebasetianzhouCopilot
authored
docs: add pg rollback blog (#880)
* add pg rollback * Update content/blog/postgres-rollback.md Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Tianzhou <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent 4a26788 commit a6f0347

File tree

2 files changed

+151
-0
lines changed

2 files changed

+151
-0
lines changed

content/blog/postgres-rollback.md

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
---
2+
title: 'PostgreSQL Rollback'
3+
author: Adela
4+
updated_at: 2025/09/04 18:00
5+
feature_image: /content/blog/postgres-rollback/cover.webp
6+
tags: Explanation
7+
description: 'An engineering perspective to evaluate PostgreSQL rollback strategies'
8+
---
9+
10+
Database integrity and recovery mechanisms are critical for any production system. PostgreSQL provides multiple rollback strategies: built-in transaction rollback with SAVEPOINTs, Point-in-Time Recovery (PITR), and modern cross-transaction DML rollback solutions with tools. Each serves different use cases with distinct limitations.
11+
12+
## Built-in Transaction Rollback and SAVEPOINTs
13+
14+
PostgreSQL transactions allow rolling back all changes within a transaction block. For granular control, `SAVEPOINT`s create markers within transactions, enabling partial rollbacks without affecting earlier operations.
15+
16+
### Using SAVEPOINTs
17+
18+
Create a savepoint:
19+
```sql
20+
SAVEPOINT my_savepoint;
21+
```
22+
23+
Roll back to it:
24+
```sql
25+
ROLLBACK TO SAVEPOINT my_savepoint;
26+
```
27+
28+
**Practical pattern for risky operations:**
29+
```sql
30+
BEGIN;
31+
32+
-- Step 1: safe operations
33+
INSERT INTO employees (name, department) VALUES ('Alice', 'Engineering');
34+
35+
SAVEPOINT sp_batch;
36+
37+
-- Step 2: risky operations
38+
INSERT INTO employees (name, department) VALUES ('Bob', 'Marketing');
39+
-- Oops, Bob is actually in Sales
40+
41+
-- Roll back only the risky step
42+
ROLLBACK TO SAVEPOINT sp_batch;
43+
44+
-- Step 3: continue with corrected operation
45+
INSERT INTO employees (name, department) VALUES ('Bob', 'Sales');
46+
47+
COMMIT;
48+
```
49+
50+
The savepoint remains usable after rollback, but any savepoints created after it are destroyed and invalidated by the rollback (not just released).
51+
52+
### Limitations
53+
54+
- Some DDL statements (`CREATE DATABASE`, `DROP DATABASE`, `CREATE TABLESPACE`, `DROP TABLESPACE`) cannot run inside transactions
55+
- Only works for uncommitted transactions - once committed, `ROLLBACK` cannot undo changes
56+
57+
## Point-In-Time Recovery (PITR)
58+
59+
PITR restores databases to specific points in time using continuous WAL archiving. PostgreSQL's Write-Ahead Log records every database change. PITR combines base backups with archived WAL files to replay changes up to any desired moment.
60+
61+
### Cloud Provider Support
62+
Major cloud providers offer one-click PITR experiences:
63+
- **AWS RDS for PostgreSQL**: Restore to point in time via Console/CLI/API
64+
- **Google Cloud SQL**: PITR from console interface
65+
- **Azure Database for PostgreSQL**: Portal "Restore" to latest or chosen restore point
66+
67+
### Named Restore Points
68+
Create targeted recovery points for easier PITR:
69+
```sql
70+
-- Before risky migration
71+
SELECT pg_create_restore_point('pre_migration_2025_09_04');
72+
```
73+
74+
Later recover using `recovery_target_name = 'pre_migration_2025_09_04'` instead of guessing timestamps.
75+
76+
### Advantages
77+
- Handles any rollback scenario regardless of transaction commit status
78+
- Can recover from errors discovered hours or days later
79+
80+
### Limitations
81+
- Operates at cluster level - rolls back entire database, not individual tables or rows
82+
- Heavyweight operation unsuitable for small, isolated changes
83+
- Rolling back one incorrect `UPDATE` also undoes all subsequent valid changes
84+
85+
## Cross-Transaction DML Rollback (Compensating Changes)
86+
87+
After a bad `UPDATE`/`DELETE`/`INSERT` is committed, you need **compensating DML** that restores previous values - think "git revert" for data.
88+
89+
### Manual Compensating DML Example
90+
91+
Accidentally ran:
92+
```sql
93+
UPDATE accounts SET status = 'inactive' WHERE org_id = 42;
94+
```
95+
96+
Compensate using audit/history table:
97+
```sql
98+
-- Revert to last known status per row
99+
UPDATE accounts a
100+
SET status = h.old_status
101+
FROM account_status_history h
102+
WHERE a.id = h.account_id
103+
AND h.org_id = 42
104+
AND h.changed_at = (
105+
SELECT max(h2.changed_at)
106+
FROM account_status_history h2
107+
WHERE h2.account_id = a.id
108+
AND h2.changed_at < :mistake_time
109+
);
110+
```
111+
112+
Real systems must handle sequences, cascades, triggers, and side-effects.
113+
114+
### Bytebase Solution
115+
116+
Bytebase provides point-and-click rollback through [Prior Backup](https://docs.bytebase.com/change-database/rollback-data-changes) functionality:
117+
118+
1. **Prior Backup**: Automatically captures affected rows before DML execution
119+
2. **Change Execution**: Stores backup in dedicated `bbdataarchive` schema
120+
3. **1-Click Rollback**: Generates and executes rollback scripts automatically
121+
122+
### Workflow Benefits
123+
- Eliminates manual rollback script creation
124+
- Integrated review and approval process
125+
- Multi-task rollback across databases
126+
- Safe, controlled change management
127+
128+
## Choosing the Right Rollback Method
129+
130+
Now that you understand the three rollback approaches, here's how to choose the right one for your situation:
131+
132+
| Situation | Best Tool | Why |
133+
|-----------|-----------|-----|
134+
| Still in session, haven't committed | **Transaction rollback / SAVEPOINT** | Instant, lossless; keep good work, discard bad chunk |
135+
| Committed a small wrong UPDATE/DELETE | **Cross-transaction rollback (Bytebase)** | Surgical fix; no cluster restore |
136+
| Dropped table / mass data corruption | **PITR** | Ubiquitous, reliable; recovers to clean time point |
137+
| Need CREATE INDEX CONCURRENTLY | **Run outside explicit BEGIN** | PostgreSQL forbids it inside transaction block |
138+
| Need CREATE DATABASE | **Run autocommit / outside BEGIN** | Not allowed in transaction block |
139+
140+
## Caveats & Gotchas
141+
142+
- **Transaction abort state**: If a statement errors mid-transaction, the session is "aborted" until you `ROLLBACK`. Don't keep issuing statements hoping it heals.
143+
- **PITR blast radius**: It's cluster-level by design; plan to restore to a new server, verify state, then cut over or copy data back.
144+
- **Compensating DML complexity**: Manual rollback scripts are error-prone and must account for cascading effects, triggers, and referential integrity.
145+
146+
147+
## TL;DR
148+
149+
- **Use transactions + SAVEPOINT** to avoid mistakes in the first place
150+
- **Use PITR** when blast radius is unclear or damage is large - it's ubiquitous and cloud-friendly
151+
- **Use compensating DML (or Bytebase's rollback workflow)** for small, precise fixes after commit - without PITR's weight
25.6 KB
Loading

0 commit comments

Comments
 (0)