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

У меня есть таблица postgres. Мне нужно удалить некоторые данные из него. Я собирался создать временную таблицу, скопировать данные в, воссоздать индексы и удалить нужные мне строки. Я не могу удалить данные из исходной таблицы, потому что эта исходная таблица является источником данных. В одном случае мне нужно получить некоторые результаты, которые зависят от удаления X, в другом случае мне нужно будет удалить Y. Поэтому мне нужно, чтобы все исходные данные всегда были вокруг и доступны.

Однако кажется немного глупо воссоздать таблицу и скопировать ее снова и воссоздать индексы. Есть ли в postgres, чтобы сказать "Мне нужна полная отдельная копия этой таблицы, включая структуру, данные и индексы"?

К сожалению, у PostgreSQL нет "CREATE TABLE.. LIKE X INCLUDING INDEXES"

Ответ 1

Новый 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)

Ответ 2

[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 имеет patch для исправления проблем табличного пространства, если используется второй метод

Ответ 3

У меня есть таблица postgres. мне нужно удалите из него некоторые данные.

Я предполагаю, что...

delete from yourtable
where <condition(s)>

... по какой-то причине работать не будет. (Позаботьтесь об этой причине?)

Я собирался создать временную таблицы, скопируйте данные, заново создайте индексы и удалить строки я необходимо.

Посмотрите на pg_dump и pg_restore. Использование pg_dump с некоторыми умными параметрами и, возможно, редактирование вывода до того, как pg_restoring может сделать трюк.


Поскольку вы делаете анализ "что, если" на данные, интересно, можете ли вы лучше использовать представления.

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

Представления хранятся в базе данных (в системном каталоге) в качестве их определяющего запроса. Каждый раз, когда вы запрашиваете представление, сервер базы данных просматривает базовый запрос, который определяет его, и выполняет его (ANDed с любыми другими условиями, которые вы использовали). Для этого подхода есть несколько преимуществ:

  • Вы никогда не дублируете какую-либо часть своих данных.
  • Если вы запрашиваете каждый просмотр/сценарий, будут использоваться индексы, которые уже используются для базовой таблицы (ваша исходная, "настоящая" таблица) (как видно, подходят оптимизатору запросов). Нет необходимости переопределять или копировать их.
  • Так как представление представляет собой "окно" (НЕ-шапшот) в "реальных" данных в базовой таблице, вы можете добавить/обновить/удалить в своей базовой таблице и просто повторно запросить сценарии просмотра, не требуя воссоздать что-либо по мере изменения данных со временем.

Конечно, есть компромисс. Поскольку представление представляет собой виртуальную таблицу, а не "реальную" (базовую) таблицу, вы выполняете (возможно, сложный) запрос каждый раз, когда вы обращаетесь к нему. Это может немного замедлить работу. Но это не так. Это зависит от многих проблем (размер и характер данных, качество статистики в системном каталоге, скорость аппаратного обеспечения, загрузка нагрузки и многое другое). Вы не узнаете, пока не попробуете. Если (и только если) вы действительно обнаружите, что производительность неприемлемо медленная, вы можете посмотреть другие параметры. (Материализованные представления, копии таблиц,... все, что торгует пространство для времени.)

Ответ 4

Создайте новую таблицу, используя команду select для захвата требуемых данных. Затем замените старый стол новым.

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

Ответ 5

Простой способ это включить все:

CREATE TABLE new_table (LIKE original_table INCLUDING ALL);