Скопіюйте таблицю (включаючи індекси) у postgres


85

У мене є таблиця postgres. Мені потрібно видалити з нього деякі дані. Я збирався створити тимчасову таблицю, скопіювати дані, відтворити індекси та видалити потрібні мені рядки. Я не можу видалити дані з вихідної таблиці, оскільки ця оригінальна таблиця є джерелом даних. В одному випадку мені потрібно отримати деякі результати, які залежать від видалення X, в іншому випадку мені потрібно буде видалити Y. Тож мені потрібні всі оригінальні дані, щоб завжди бути поряд і бути доступними.

Однак здається трохи безглуздо відтворювати таблицю та копіювати її знову та відтворювати індекси. Чи є в Postgres спосіб сказати: "Я хочу отримати повну окрему копію цієї таблиці, включаючи структуру, дані та індекси"?

На жаль, PostgreSQL не має "СТВОРИТИ ТАБЛИЦЮ .. ЯК X, Включаючи індекси"

Відповіді:


108

Новий PostgreSQL (з 8.3 згідно з документами) може використовувати "ВКЛЮЧАЮЧІ ІНДЕКСИ":

# select version();
                                             version
-------------------------------------------------------------------------------------------------
 PostgreSQL 8.3.7 on x86_64-pc-linux-gnu, compiled by GCC cc (GCC) 4.2.4 (Ubuntu 4.2.4-1ubuntu3)
(1 row)

Як бачите, я тестую на 8.3.

Тепер давайте створимо таблицю:

# create table x1 (id serial primary key, x text unique);
NOTICE:  CREATE TABLE will create implicit sequence "x1_id_seq" for serial column "x1.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "x1_pkey" for table "x1"
NOTICE:  CREATE TABLE / UNIQUE will create implicit index "x1_x_key" for table "x1"
CREATE TABLE

І подивіться, як це виглядає:

# \d x1
                         Table "public.x1"
 Column |  Type   |                    Modifiers
--------+---------+-------------------------------------------------
 id     | integer | not null default nextval('x1_id_seq'::regclass)
 x      | text    |
Indexes:
    "x1_pkey" PRIMARY KEY, btree (id)
    "x1_x_key" UNIQUE, btree (x)

Тепер ми можемо скопіювати структуру:

# create table x2 ( like x1 INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING INDEXES );
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "x2_pkey" for table "x2"
NOTICE:  CREATE TABLE / UNIQUE will create implicit index "x2_x_key" for table "x2"
CREATE TABLE

І перевірте структуру:

# \d x2
                         Table "public.x2"
 Column |  Type   |                    Modifiers
--------+---------+-------------------------------------------------
 id     | integer | not null default nextval('x1_id_seq'::regclass)
 x      | text    |
Indexes:
    "x2_pkey" PRIMARY KEY, btree (id)
    "x2_x_key" UNIQUE, btree (x)

Якщо ви використовуєте PostgreSQL pre-8.3, ви можете просто використовувати pg_dump з опцією "-t", щоб вказати 1 таблицю, змінити назву таблиці в дампі і завантажити її знову:

=> pg_dump -t x2 | sed 's/x2/x3/g' | psql
SET
SET
SET
SET
SET
SET
SET
SET
CREATE TABLE
ALTER TABLE
ALTER TABLE
ALTER TABLE

А тепер таблиця така:

# \d x3
                         Table "public.x3"
 Column |  Type   |                    Modifiers
--------+---------+-------------------------------------------------
 id     | integer | not null default nextval('x1_id_seq'::regclass)
 x      | text    |
Indexes:
    "x3_pkey" PRIMARY KEY, btree (id)
    "x3_x_key" UNIQUE, btree (x)

14
Таким чином послідовність первинного ключа (x1_id_seq) буде розподілена між двома таблицями!
Jauzsika

2
Опс, з pg9.X, послідовність первинного ключа буде спільною при використанні "ВКЛЮЧЮЧИХ ОБМЕЖЕНЬ" (а не "ВКЛЮЧАЮЧИ ІНДЕКСИ").
Пітер Краус

44
[CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE table_name
    [ (column_name [, ...] ) ]
    [ WITH ( storage_parameter [= value] [, ... ] ) | WITH OIDS | WITHOUT OIDS ]
    [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
    [ TABLESPACE tablespace ]
    AS query][1]  

Ось приклад

CREATE TABLE films_recent AS
  SELECT * FROM films WHERE date_prod >= '2002-01-01';

Інший спосіб створити нову таблицю з першої - використовувати

    CREATE TABLE films_recent (LIKE films INCLUDING INDEXES);  

    INSERT INTO films_recent
         SELECT *
           FROM books
          WHERE date_prod >= '2002-01-01';  

Зверніть увагу, що Postgresql має виправлення для виправлення проблем табличного простору, якщо використовується другий метод


У postgres немає "ВКЛЮЧАЮЧИ ІНДЕКСИ".
Рорі

2
Яку версію ви використовуєте? Прочитайте останній документ, він там
WolfmanDragon

6
з pg9.X, коли використовується "ВКЛЮЧАЮЧІ ОБМЕЖЕННЯ" (а не "ВКЛЮЧАЮЧІ ІНДЕКСИ"), послідовність первинного ключа буде розподілена між двома таблицями (!).
Пітер Краус

Схоже, що це може знадобитися CREATE TABLE my_table (LIKE...)замість CREATE TABLE my_table LIKE...того, щоб працювати. Відредагована відповідь.
Джейсон Світт,

@PeterKrauss ти з'ясував спільну послідовність первинного ключа? Я намагаюся КОПІЮВАТИ купу даних у нову таблицю. Я не можу скинути стару таблицю і перейменувати нову, оскільки pk з нової вказує на стару.
yellottyellott

4

У мене є таблиця postgres. Мені потрібно видалити з нього деякі дані.

Я припускаю, що ...

delete from yourtable
where <condition(s)>

... з якихось причин не спрацює. (Хочете поділитися цією причиною?)

Я збирався створити тимчасову таблицю, скопіювати дані, відтворити індекси та видалити потрібні мені рядки.

Перегляньте pg_dump та pg_restore. Використання pg_dump з деякими розумними опціями та, можливо, редагування результату перед pg_restoring може зробити трюк.


Оскільки ви проводите аналіз даних типу "що якщо", цікаво, чи не краще вам буде використовувати представлення даних.

Ви можете визначити подання для кожного сценарію, який ви хочете протестувати, виходячи із заперечення того, що ви хочете виключити. Тобто, визначте подання на основі того, що ви хочете Включити. Наприклад, якщо вам потрібне "вікно" з даними, де ви "видалили" рядки, де X = Y, тоді ви створили б вигляд у вигляді рядків де (X! = Y).

Представлення зберігаються у базі даних (у системному каталозі) як визначальний запит. Щоразу, коли ви запитуєте подання, сервер бази даних шукає базовий запит, який його визначає, і виконує його (ANDed з будь-якими іншими умовами, які ви використовували). Цей підхід має кілька переваг:

  1. Ви ніколи не дублюєте будь-яку частину своїх даних.
  2. Індекси, які вже використовуються для базової таблиці (ваша оригінальна, "справжня" таблиця), будуть використовуватися (як вважає оптимізатор запитів) під час запиту кожного подання / сценарію. Не потрібно їх перевизначати чи копіювати.
  3. Оскільки подання є "вікном" (НЕ знімком) для "реальних" даних базової таблиці, ви можете додавати / оновлювати / видаляти свою базову таблицю і просто робити повторний запит сценаріїв перегляду без необхідності відтворювати щось як дані змінюються з часом.

Звичайно, є компроміс. Оскільки подання є віртуальною таблицею, а не "реальною" (базовою) таблицею, ви фактично виконуєте (можливо, складний) запит кожного разу, коли отримуєте до нього доступ. Це може трохи уповільнити ситуацію. Але може і не бути. Це залежить від багатьох питань (розмір і характер даних, якість статистики в системному каталозі, швидкість обладнання, навантаження на використання та багато іншого). Ви не дізнаєтесь, поки не спробуєте. Якщо (і лише якщо) ви виявите, що продуктивність є неприпустимо повільною, ви можете розглянути інші варіанти. (Матеріалізовані подання, копії таблиць, ... все, що торгує простір для часу.)


Я оновив запитання, щоб пояснити, чому я не можу просто видалити з оригінальної таблиці
Рорі

4

В Інтернеті є багато відповідей, одну з них можна знайти тут .

У підсумку я зробив щось подібне:

create table NEW ( like ORIGINAL including all);
insert into NEW select * from ORIGINAL

Це скопіює схему та дані, включаючи індекси, але не включаючи тригери та обмеження. Зверніть увагу, що індекси спільно використовуються з вихідною таблицею, тому при додаванні нового рядка до будь-якої таблиці лічильник буде збільшуватися.


1

Створіть нову таблицю, використовуючи селектор, щоб отримати потрібні дані. Потім поміняйте стару таблицю на нову.

create table mynewone as select * from myoldone where ...
mess (re-create) with indexes after the table swap.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.