Skopiuj tabelę (w tym indeksy) do postgres

85

Mam stół postgres. Muszę usunąć z niego niektóre dane. Zamierzałem utworzyć tymczasową tabelę, skopiować dane, odtworzyć indeksy i usunąć potrzebne wiersze. Nie mogę usunąć danych z oryginalnej tabeli, ponieważ ta oryginalna tabela jest źródłem danych. W jednym przypadku muszę uzyskać wyniki, które zależą od usunięcia X, w innym przypadku będę musiał usunąć Y. Dlatego potrzebuję, aby wszystkie oryginalne dane były zawsze dostępne i zawsze dostępne.

Jednak ponowne utworzenie tabeli i skopiowanie jej i odtworzenie indeksów wydaje się trochę głupie. Czy w postgres jest napisane, że „chcę mieć kompletną oddzielną kopię tej tabeli, w tym strukturę, dane i indeksy”?

Niestety PostgreSQL nie posiada opcji „TWORZENIE TABELI .. TAK JAK X, WŁĄCZAJĄC INDEKSY”

Rory
źródło

Odpowiedzi:

108

Nowy PostgreSQL (od 8.3 według dokumentacji) może używać "INCLUDING INDEXES":

# 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)

Jak widać, testuję na 8.3.

Teraz stwórzmy tabelę:

# 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

I zobacz, jak to wygląda:

# \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)

Teraz możemy skopiować strukturę:

# 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

I sprawdź strukturę:

# \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)

Jeśli używasz PostgreSQL w wersji starszej niż 8.3, możesz po prostu użyć pg_dump z opcją "-t", aby określić 1 tabelę, zmienić nazwę tabeli w zrzucie i załadować ją ponownie:

=> 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

A teraz tabela jest:

# \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)

źródło
14
W ten sposób sekwencja klucza podstawowego (x1_id_seq) będzie współdzielona między dwiema tabelami!
Jauzsika
2
Ops, z pg9.X, sekwencja klucza podstawowego będzie współdzielona podczas używania „WŁĄCZANIA OGRANICZEŃ” (nie „WŁĄCZANIA INDEKSÓW”).
Peter Krauss
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]  

Oto przykład

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

Innym sposobem na utworzenie nowej tabeli z pierwszej jest użycie

    CREATE TABLE films_recent (LIKE films INCLUDING INDEXES);  

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

Zauważ, że Postgresql ma łatkę , która rozwiązuje problemy z obszarami tabel, jeśli używana jest druga metoda

WolfmanDragon
źródło
W postgres nie ma „WŁĄCZANIA INDEKSÓW”.
Rory
2
Jakiej wersji używasz? Przeczytaj najnowszy dokument, jest tam
WolfmanDragon,
6
z pg9.X, podczas używania "WŁĄCZANIA OGRANICZEŃ" (a nie "WŁĄCZANIA INDEKSÓW") sekwencja klucza podstawowego będzie współdzielona między dwiema tabelami (!).
Peter Krauss
Wygląda na to, że musi być CREATE TABLE my_table (LIKE...)zamiast CREATE TABLE my_table LIKE..., aby działał. Edytowana odpowiedź.
Jason Swett
@PeterKrauss, czy odkryłeś wspólną sekwencję klucza podstawowego? Próbuję skopiować kilka danych do nowej tabeli. Nie mogę usunąć starej tabeli i zmienić nazwy nowej, ponieważ pk z nowego wskazuje na stary.
yellottyellott
4

Mam stół postgres. Muszę usunąć z niego niektóre dane.

Zakładam, że ...

delete from yourtable
where <condition(s)>

... nie zadziała z jakiegoś powodu. (Chcesz podzielić się tym powodem?)

Zamierzałem utworzyć tymczasową tabelę, skopiować dane, odtworzyć indeksy i usunąć potrzebne wiersze.

Zajrzyj do pg_dump i pg_restore. Używanie pg_dump z kilkoma sprytnymi opcjami i być może edycja wyniku przed pg_restoring może załatwić sprawę.


Ponieważ wykonujesz analizę danych typu „a co, jeśli”, zastanawiam się, czy nie byłoby lepiej, gdybyś korzystał z widoków.

Możesz zdefiniować widok dla każdego scenariusza, który chcesz przetestować, na podstawie negacji tego, co chcesz wykluczyć. To znaczy zdefiniuj widok na podstawie tego, co chcesz uwzględnić. Na przykład, jeśli chcesz mieć „okno” na danych, w którym „usunąłeś” wiersze, w których X = Y, to utworzyłbyś widok jako wiersze, w których (X! = Y).

Widoki są przechowywane w bazie danych (w katalogu systemowym) jako ich definiujące zapytanie. Za każdym razem, gdy wysyłasz zapytanie do widoku, serwer bazy danych wyszukuje podstawowe zapytanie, które go definiuje i wykonuje to (połączone operatorem AND z innymi użytymi warunkami). Takie podejście ma kilka zalet:

  1. Nigdy nie kopiujesz żadnej części swoich danych.
  2. Indeksy, które są już używane dla tabeli bazowej (pierwotnej, „rzeczywistej” tabeli) zostaną użyte (zgodnie z optymalizatorem zapytań) podczas wykonywania zapytań do każdego widoku / scenariusza. Nie ma potrzeby ich redefiniowania ani kopiowania.
  3. Ponieważ widok jest „oknem” (NIE obrazem) „rzeczywistych” danych w tabeli bazowej, możesz dodawać / aktualizować / usuwać w tabeli podstawowej i po prostu ponownie sprawdzać scenariusze widoku bez konieczności ponownego tworzenia dane zmieniają się w czasie.

Oczywiście istnieje kompromis. Ponieważ widok jest tabelą wirtualną, a nie „prawdziwą” (podstawową) tabelą, w rzeczywistości wykonujesz (być może złożone) zapytanie za każdym razem, gdy uzyskujesz do niego dostęp. Może to trochę spowolnić. Ale może nie. Zależy to od wielu kwestii (rozmiar i charakter danych, jakość statystyk w katalogu systemowym, szybkość sprzętu, obciążenie użytkowe i wiele innych). Nie dowiesz się, dopóki tego nie spróbujesz. Jeśli (i tylko jeśli) rzeczywiście okaże się, że wydajność jest niedopuszczalnie wolna, możesz rozważyć inne opcje. (Zmaterializowane widoki, kopie tabel, ... wszystko, co zamienia przestrzeń na czas.)

Alan
źródło
Zaktualizowałem pytanie, aby wyjaśnić, dlaczego nie mogę po prostu usunąć z oryginalnej tabeli
Rory,
4

W sieci jest wiele odpowiedzi, jedną z nich można znaleźć tutaj .

W końcu zrobiłem coś takiego:

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

Spowoduje to skopiowanie schematu i danych, w tym indeksów, ale bez wyzwalaczy i ograniczeń. Zauważ, że indeksy są współdzielone z oryginalną tabelą, więc podczas dodawania nowego wiersza do którejkolwiek z tabel licznik będzie się zwiększał.

oshai
źródło
1

Utwórz nową tabelę, używając funkcji wyboru, aby pobrać żądane dane. Następnie zamień stary stół na nowy.

create table mynewone as select * from myoldone where ...
mess (re-create) with indexes after the table swap.
gsamaras
źródło
0

Prostym sposobem jest uwzględnienie wszystkich:

CREATE TABLE new_table (LIKE original_table INCLUDING ALL);
Ringtail
źródło