Created
March 29, 2016 21:13
-
-
Save eddking/8a5aaa7808946f8890477ad577434fd2 to your computer and use it in GitHub Desktop.
Re-create a table within postgres without downtime
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- This is a general process for recreating tables in postgres without downtime | |
-- it can help you recover from data corruption bugs like one seen in Postgres 9.3 | |
-- The table in question should have no foreign key contraints | |
-- in this example I migrate a table called bibliography_entries to a table called bib_entries | |
-- create the new table | |
CREATE TABLE bib_entries (LIKE bibliography_entries INCLUDING ALL); | |
-- create a temporary table to hold the changes while the bulk of the table is migrated | |
CREATE TABLE bib_entries_tmp (LIKE bibliography_entries INCLUDING ALL); | |
-- create trigger to insert into the temporary table | |
CREATE OR REPLACE FUNCTION copy_to_bib_entries_tmp() RETURNS trigger | |
AS $body$ | |
BEGIN | |
IF (TG_OP = 'UPDATE') THEN | |
DELETE FROM bib_entries_tmp WHERE bib_entries_tmp.id = NEW.id; -- deleting is ok because there arent FK constraints | |
INSERT INTO bib_entries_tmp VALUES(NEW.*); | |
ELSIF (TG_OP = 'INSERT') THEN | |
INSERT INTO bib_entries_tmp VALUES(NEW.*); | |
END IF; | |
-- Always return the row | |
RETURN NEW; | |
END $body$ | |
LANGUAGE plpgsql | |
SECURITY DEFINER; | |
CREATE TRIGGER copy_to_bib_entries_tmp AFTER INSERT OR UPDATE ON "bibliography_entries" | |
FOR EACH ROW EXECUTE PROCEDURE copy_to_bib_entries_tmp(); | |
-- create trigger to check for duplicate primary keys | |
CREATE OR REPLACE FUNCTION bib_entries_insert() RETURNS trigger | |
AS $body$ | |
BEGIN | |
BEGIN | |
INSERT INTO bib_entries VALUES(NEW.*); | |
EXCEPTION WHEN unique_violation THEN | |
END; | |
--ignore and return null | |
RETURN NULL; | |
END $body$ | |
LANGUAGE plpgsql | |
SECURITY DEFINER; | |
CREATE TRIGGER bib_entries_insert BEFORE INSERT ON "bib_entries" | |
FOR EACH ROW | |
WHEN (pg_trigger_depth() = 0) -- otherwise we have infinite recursion | |
EXECUTE PROCEDURE bib_entries_insert(); | |
-- binary dump of table | |
COPY bibliography_entries TO '/mnt/backup/bibliography_entries/dump' WITH (FORMAT binary); | |
-- load binary dump into new table | |
COPY bib_entries FROM '/mnt/backup/bibliography_entries/dump' WITH (FORMAT binary); | |
-- remove trigger that prevents inserts from failing | |
DROP TRIGGER bib_entries_insert ON bib_entries; | |
DROP FUNCTION bib_entries_insert(); | |
-- create a trigger to copy data inserts / updates | |
CREATE OR REPLACE FUNCTION copy_to_bib_entries() RETURNS trigger | |
AS $body$ | |
BEGIN | |
IF (TG_OP = 'UPDATE') THEN | |
DELETE FROM bib_entries WHERE bib_entries.id = NEW.id; -- deleting is ok because there arent FK constraints | |
INSERT INTO bib_entries VALUES(NEW.*); | |
ELSIF (TG_OP = 'INSERT') THEN | |
INSERT INTO bib_entries VALUES(NEW.*); | |
END IF; | |
-- Always return the row | |
RETURN NEW; | |
END $body$ | |
LANGUAGE plpgsql | |
SECURITY DEFINER; | |
CREATE TRIGGER copy_to_bib_entries AFTER INSERT OR UPDATE ON "bibliography_entries" | |
FOR EACH ROW | |
WHEN (pg_trigger_depth() = 0) | |
EXECUTE PROCEDURE copy_to_bib_entries(); | |
-- remove temporary trigger | |
DROP TRIGGER copy_to_bib_entries_tmp ON bibliography_entries; | |
DROP FUNCTION copy_to_bib_entries_tmp(); | |
-- Copy rows from the temporary table that dont exist in the new table | |
DELETE FROM bib_entries_tmp WHERE EXISTS (SELECT id FROM bib_entries WHERE id = bib_entries_tmp.id); | |
INSERT INTO bib_entries SELECT * FROM bib_entries_tmp WHERE NOT EXISTS (SELECT id FROM bib_entries WHERE id = bib_entries_tmp.id); | |
-- switch over app to use new table, then drop the trigger duplicating writes | |
DROP TRIGGER copy_to_bib_entries ON bibliography_entries; | |
DROP FUNCTION copy_to_bib_entries(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment