I have a project that uses PostgreSQL as its database. The project has been running for a long time, and the production database has accumulated a large amount of historical data.
The development database was originally synchronized with the production database. However, the existing data in the development environment is no longer needed.
Therefore, I need to clear all existing data from the development database while preserving the database schema, reset identity columns, and migrate the latest production data into the development environment.
1. Trucate Dev Business Tables
Truncate all tables in the public schema while preserving the database schema and restarting identity columns.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
DO $$ DECLARE sql_text text; BEGIN SELECT 'TRUNCATE TABLE '|| string_agg(format('%I.%I', schemaname, tablename), ', ') || ' RESTART IDENTITY' INTO sql_text FROM pg_tables WHERE schemaname ='public';
IF sql_text ISNOT NULLTHEN EXECUTE sql_text; END IF; END $$;
This removes all data from the tables while keeping the table definitions intact. RESTART IDENTITY resets sequences owned by the truncated tables.
2. Backup Dev Database
Before performing any data migration or deletion, it is important to back up the development database to prevent accidental data loss.
$env:PGPASSWORD = "your_password_here"# Replace with your actual password
$SourceHost = "aws-1-ap-southeast-2.xxx.xxx.com"# Replace with your actual host $SourcePort = "5432"# Replace with your actual port $SourceDatabase = "postgres"# Replace with your actual database name $SourceUser = "postgres.xxxx"# Replace with your actual username
$BackupFile = "D:\freelance\backup\xxxx.dump"# Replace with your desired backup file path
The -F c option creates a PostgreSQL custom-format backup, which can later be restored using pg_restore.
3. Backup Data from Production Database
Export only the data from the production database. Because the development database already contains the required schema, there is no need to export the production schema.
$env:PGPASSWORD = "your_password_here"# Replace with your actual password
$SourceHost = "aws-1-ap-southeast-2.xxx.xxx.com"# Replace with your actual host $SourcePort = "5432"# Replace with your actual port $SourceDatabase = "postgres"# Replace with your actual database name $SourceUser = "postgres.xxxx"# Replace with your actual username
$BackupFile = "D:\freelance\backup\yyy.dump"# Replace with your desired backup file path
$env:PGPASSWORD = "your_password_here"# Replace with your actual password
$SourceHost = "aws-1-ap-southeast-2.xxx.xxx.com"# Replace with your actual host $SourcePort = "5432"# Replace with your actual port $SourceDatabase = "postgres"# Replace with your actual database name $SourceUser = "postgres.xxxx"# Replace with your actual username
$BackupFile = "D:\freelance\backup\zzz-fk-constraints.sql"# Replace with your desired backup file path
Write-Host"Starting PostgreSQL backup..."
psql ` -h$SourceHost ` -p$SourcePort ` -U$SourceUser ` -d$SourceDatabase ` -At ` -c"SELECT format('ALTER TABLE %I.%I ADD CONSTRAINT %I %s;', n.nspname, t.relname, c.conname, pg_get_constraintdef(c.oid)) FROM pg_constraint c JOIN pg_class t ON t.oid = c.conrelid JOIN pg_namespace n ON n.oid = t.relnamespace WHERE c.contype = 'f' AND n.nspname = 'public';" ` | Out-File-Encoding utf8 $BackupFile
5. Remove the Foreign Key Constraints from the Development Database
Foreign key constraints may cause problems during data restoration because tables may be restored in an order that temporarily violates referential integrity. First, generate a SQL script to drop all foreign key constraints, and then execute the script.
$env:PGPASSWORD = "your_password_here"# Replace with your actual password
$SourceHost = "aws-1-ap-southeast-2.xxx.xxx.com"# Replace with your actual host $SourcePort = "5432"# Replace with your actual port $SourceDatabase = "postgres"# Replace with your actual database name $SourceUser = "postgres.xxxx"# Replace with your actual username
$BackupFile = "D:\freelance\backup\zzz-fk-constraints-drop.sql"# Replace with your desired backup file path
Write-Host"Starting PostgreSQL drop fk script backup..."
psql ` -h$SourceHost ` -p$SourcePort ` -U$SourceUser ` -d$SourceDatabase ` -At ` -c"SELECT format('ALTER TABLE %I.%I DROP CONSTRAINT %I;', n.nspname, t.relname, c.conname) FROM pg_constraint c JOIN pg_class t ON t.oid = c.conrelid JOIN pg_namespace n ON n.oid = t.relnamespace WHERE c.contype = 'f' AND n.nspname = 'public';" ` | Out-File-Encoding utf8 $BackupFile
$env:PGPASSWORD = "your_password_here"# Replace with your actual password
$SourceHost = "aws-1-ap-southeast-2.xxx.xxx.com"# Replace with your actual host $SourcePort = "5432"# Replace with your actual port $SourceDatabase = "postgres"# Replace with your actual database name $SourceUser = "postgres.xxxx"# Replace with your actual username
$BackupFile = "D:\freelance\backup\yyy.dump"# Replace with your desired backup file path
$env:PGPASSWORD = "your_password_here"# Replace with your actual password
$SourceHost = "aws-1-ap-southeast-2.xxx.xxx.com"# Replace with your actual host $SourcePort = "5432"# Replace with your actual port $SourceDatabase = "postgres"# Replace with your actual database name $SourceUser = "postgres.xxxx"# Replace with your actual username
$BackupFile = "D:\freelance\backup\zzz-fk-constraints.sql"# Replace with your desired backup file path
If this step fails, it may indicate that the restored data contains invalid references, such as a foreign key value that does not have a corresponding row in the referenced table.
8. Verify Data Migration
After completing the data migration, it’s essential to verify that the data has been successfully restored in the development database. You can run queries to check the data integrity and ensure that the foreign key constraints are intact.
-- Check the number of rows in each table SELECT schemaname, relname AS table_name, n_live_tup AS estimated_rows FROM pg_stat_user_tables WHERE schemaname ='public' ORDERBY relname;
-- Check foreign key constraints SELECT tc.table_name, tc.constraint_name, kcu.column_name, ccu.table_name AS referenced_table, ccu.column_name AS referenced_column FROM information_schema.table_constraints tc JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name AND tc.constraint_schema = kcu.constraint_schema JOIN information_schema.constraint_column_usage ccu ON ccu.constraint_name = tc.constraint_name AND ccu.constraint_schema = tc.constraint_schema WHERE tc.constraint_type ='FOREIGN KEY' AND tc.constraint_schema ='public' ORDERBY tc.table_name;
-- Check indexes SELECT schemaname, tablename, indexname, indexdef FROM pg_indexes WHERE schemaname ='public' ORDERBY tablename, indexname;