How can I safely rename a sequence in PostgreSQL, ideally without downtime?
-
28-02-2021 - |
Frage
We want to rename some sequences in our production database for certain reasons.
Is there a way to do this safely in production without having to first close all connections to the database?
It's fine if we get gaps in the ID sequence (e.g. it jumps from ID 123 to ID 200 or whatever) but we obviously don't want long locks causing delays/errors, don't want any risk of duplicate IDs and similar.
We're on PostgreSQL 9.5.21 on Heroku.
We've looked at the docs but are still uncertain about the consequences of running
ALTER SEQUENCE old_id_seq RENAME TO new_id_seq;
ALTER TABLE mytable ALTER COLUMN id SET DEFAULT nextval('new_id_seq');
in production. I guess one risk would be if stuff happens in mytable
between those two commands. But what if we did something like this:
-- Starting at a much higher value than the currently highest ID.
CREATE SEQUENCE new_id_seq START 200;
ALTER TABLE mytable ALTER COLUMN id SET DEFAULT nextval('new_id_seq');
DROP SEQUENCE old_id_seq;
What are the risks of doing it that way?
Lösung
If the sequence is used in the
DEFAULT
clause of the table column, it is enough to rename the sequence.That is because the
DEFAULT
clause is not stored as string, but as parsed expression tree (columnadbin
in catalogpg_attrdef
). That expression tree does not contain the name of the sequence, but its object ID, which is unchanged by renaming the sequence. Tools likepsql
's\d
re-construct a string from the parsed expression, so theDEFAULT
clause will appear to reflect the renaming.If the sequence name is used elsewhere, like in your client code or in a PostgreSQL function, you would have to change the name in that code. PostgreSQL functions are stored as strings (column
prosrc
in catalogpg_proc
), so renaming a sequence can make a function that uses the sequence fail.In this case, you would have to suspend activity until you have changed the code and renamed the sequence if you want to avoid errors.
Andere Tipps
I don't think the mentioned method is going to solve your problem. In both cases, PostgreSQL is going to acquire a lock on the table, and the application has to wait for the ALTER command to be finished.
ALTER SEQUENCE <sequence name> RENAME TO <new sequence name>
Above command should be fast and you don't need following
ALTER TABLE ALTER COLUMN SET DEFAULT nextval('new_id_seq');
After renaming the sequence. PostgreSQL internally knows the name has been changed.