Безопасно и чисто переименовывать таблицы, использующие последовательные первичные ключи столбцов в Postgres?

Я знаю, что таблицы PostgreSQL, которые используют первичный ключ SERIAL, в конечном итоге создают неявный индекс, последовательность и ограничение, создаваемые PostgreSQL. Вопрос в том, как переименовать эти неявные объекты при переименовании таблицы. Ниже моя попытка выяснить это с конкретными вопросами в конце.

Учитывая таблицу, такую ​​как

CREATE TABLE foo (
    pkey SERIAL PRIMARY KEY,
    value INTEGER
);

Выводы Postgres

NOTICE:  CREATE TABLE will create implicit sequence "foo_pkey_seq" for serial column "foo.pkey"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for table "foo"
Query returned successfully with no result in 52 ms.

PgAdmin III показывает следующее как DDL для таблицы

CREATE TABLE foo
(
  pkey serial NOT NULL,
  value integer,
  CONSTRAINT foo_pkey PRIMARY KEY (pkey )
)
WITH (
  OIDS=FALSE
);
ALTER TABLE foo
  OWNER TO postgres;

Теперь переименуйте таблицу

ALTER table foo RENAME TO bar;

Выход Postgres

Query returned successfully with no result in 17 ms.

PgAdmin III SQL панель для таблицы

CREATE TABLE bar
(
  pkey integer NOT NULL DEFAULT nextval('foo_pkey_seq'::regclass),
  value integer,
  CONSTRAINT foo_pkey PRIMARY KEY (pkey )
)
WITH (
  OIDS=FALSE
);
ALTER TABLE bar
  OWNER TO postgres;

Обратите внимание на дополнительные DEFAULT nextval('foo_pkey_seq'::regclass), это означает, что переименование таблицы не переименовывает последовательность для первичных ключей, но теперь у нас есть это явное nextval(),

Теперь переименуйте последовательность

Я хочу, чтобы имена баз данных соответствовали друг другу, поэтому я попытался

ALTER SEQUENCE foo_pkey_seq RENAME TO bar_pkey_seq;
Query returned successfully with no result in 17 ms.

Глядя на панель SQL в pgAdmin III я вижу

CREATE TABLE bar
(
  pkey serial NOT NULL,
  value integer,
  CONSTRAINT foo_pkey PRIMARY KEY (pkey )
)
WITH (
  OIDS=FALSE
);
ALTER TABLE bar
  OWNER TO postgres;

DEFAULT nextval('foo_pkey_seq'::regclass), ушел

ВОПРОСЫ

  1. Почему DEFAULT nextval('foo_pkey_seq'::regclass) Выражение появляется и исчезает?
  2. Есть ли способ переименовать таблицу и одновременно переименовать последовательность первичных ключей?
  3. Безопасно ли переименовывать таблицу, затем последовательность, пока клиенты подключены к базе данных, есть ли проблемы с параллелизмом?
  4. Как postgres знает, какую последовательность использовать? Есть ли триггер базы данных для внутреннего использования? Есть ли что-нибудь еще, чтобы переименовать, кроме таблицы и последовательности?
  5. Как насчет неявного индекса, созданного первичным ключом? Это должно быть переименовано? Если так, как это можно сделать?
  6. Как насчет имени ограничения выше? Это все еще foo_pkey, Как ограничение переименовано?

1 ответ

Решение

serial не фактический тип данных. В руководстве четко говорится:

Типы данных smallserial, serial и bigserial - это не настоящие типы, а просто удобство записи для создания столбцов уникальных идентификаторов.

Псевдо-тип данных разрешается, делая все это:

  • Создайте последовательность с именем tablename_colname_seq

  • Создать столбец с типом integer (или же int2 / int8 соответственно для smallserial / bigserial)

  • Сделать колонку NOT NULL DEFAULT nextval('tablename_colname_seq')

  • Сделайте так, чтобы столбец принадлежал последовательности, чтобы он автоматически удалялся вместе с ним.

Система не знает, делали ли вы все это вручную или с помощью псевдо-типа данных. serial, pgAdmin проверяет перечисленные функции и, если все они выполнены, обратный инженерный сценарий DDL упрощается с соответствующим серийным типом. Если одна из особенностей не соблюдается, это упрощение не происходит. Это то, что делает pgAdmin. Для базовых каталоговых таблиц все одинаково. Здесь нет serial типа как таковой.

Я вполне уверен, что нет способа автоматически переименовать собственные последовательности. Вы можете запустить

ALTER SEQUENCE ... RENAME TO ...

как ты. Сама система не заботится об имени. Колонка DEFAULT хранит OID ('foo_pkey_seq'::regclass), вы можете изменить имя последовательности, не нарушая ее - OID остается прежним. То же самое касается внешних ключей и аналогичных ссылок внутри базы данных.

Неявный индекс для первичного ключа связан с именем ограничения PK, которое не изменится, если вы измените имя таблицы. В Postgres 9.2 или более поздней версии вы можете использовать

ALTER TABLE ... RENAME CONSTRAINT ..

чтобы исправить это тоже.

Также могут быть индексы, названные по имени таблицы. Аналогичная процедура:

ALTER INDEX .. RENAME TO  ..

Вы можете иметь все виды неофициальных ссылок на имя таблицы. Система не может принудительно переименовать объекты, которые могут быть названы как угодно. И это не волнует.

Конечно, вы не хотите аннулировать код SQL, который ссылается на эти имена. Очевидно, что вы не хотите менять имена, пока логика приложения ссылается на них. Обычно это не будет проблемой для имен индексов, последовательностей или ограничений, поскольку на них обычно не ссылаются по имени.

Postgres также получает блокировку объектов перед переименованием. Так что если есть открытые параллельные транзакции, которые имеют какую-либо блокировку рассматриваемых объектов, ваш RENAME операция останавливается до тех пор, пока эти транзакции не завершатся или не откатятся

Системные каталоги и OID

Схема базы данных хранится в таблицах системного каталога в схеме системы. pg_catalog, Все подробности в руководстве здесь. Если вы точно не знаете, что делаете, вам не следует возиться с этими таблицами. Один неверный ход, и вы можете сломать базу данных. Используйте команды DDL, которые предоставляет Postgres.

Для некоторых наиболее важных таблиц Postgres предоставляет типы идентификаторов объектов и приведение типов, чтобы быстро получить имя для OID и наоборот. Подобно:

SELECT 'foo_pkey_seq'::regclass

Если имя схемы находится в search_path и имя таблицы уникально, что дает вам то же, что и:

SELECT oid FROM pg_class WHERE relname = 'foo_pkey_seq';

Первичный ключ большинства каталожных таблиц oid и внутри, большинство ссылок используют OID.

Другие вопросы по тегам