2010-06-04 33 views
9

Chciałbym przenieść niektóre dane z jednej tabeli do drugiej (z możliwym innym schematem). Proste rozwiązanie, które przychodzi do głowy to -przenoszenie danych z jednej tabeli do drugiej, edycja postgresql

start a transaction with serializable isolation level; 
INSERT INTO dest_table SELECT data FROM orig_table,other-tables WHERE <condition>; 
DELETE FROM orig_table USING other-tables WHERE <condition>; 
COMMIT; 

Teraz co, jeśli ilość danych jest dość duży, a <condition> jest drogie, aby obliczyć? W PostgreSQL, reguła lub procedura składowana może być używana do usuwania danych w locie, oceniając warunek tylko raz. Które rozwiązanie jest lepsze? Czy są inne opcje?

Odpowiedz

0

Można zrzucić dane z tabeli do pliku, a następnie włóż go do innej tabeli za pomocą COPYCOPY Zazwyczaj jest szybsza niż INSERT.

+1

Zrobiłem kilka testów przetwarzanie duże ilości danych za pomocą wyzwalaczy, wiersz po wierszu i za pomocą procedury składowanej z pojedynczej transakcji. Podejście do procedury przechowywanej było szybsze. – pcent

+0

Powinieneś również dostroić swój serwer PostgreSQL, aby zwiększyć wydajność. Przeczytaj: http://wiki.postgresql.org/wiki/Performance_Optimization – pcent

+0

yah, myślę, że wytyczne powinny kwalifikować się do stwierdzenia, że ​​jedna kopia jest szybsza niż zestaw instrukcji INSERT, po jednym w wierszu. INSERT ... SELECT do kopiowania danych w okolicy byłoby optymalne, ponieważ dane nie są przekazywane poza executorem. – araqnid

7

Jeśli warunek jest tak skomplikowany, że nie chcesz go wykonywać dwukrotnie (co brzmi nieprawdopodobnie, ale i tak), jedną z możliwości może być ALTER TABLE ... ADD COLUMN w oryginalnej tabeli, aby dodać pole boolowskie i uruchomić UPDATE na stole, aby ustawić to pole na prawdziwe WHERE <condition>. Następnie twoje polecenia INSERT i DELETE mogą po prostu sprawdzić tę kolumnę pod kątem ich klauzul WHERE.

Nie zapomnij również usunąć kolumny z tabel źródłowych i docelowych!

Hmm, jeszcze mniej uciążliwe byłoby stworzenie nowego tymczasowego stołu, którego jedynym celem jest zawarcie PK rekordów, które chcesz uwzględnić. Najpierw INSERT do tej tabeli, aby "zdefiniować" zestaw wierszy do działania, a następnie połączyć się z tą tabelą dla kopiowania tabel INSERT i DELETE. Te połączenia będą szybkie, ponieważ indeksy tabeli PKs są indeksowane.


[EDIT] sugestia Scott Bailey w komentarzach jest oczywiście właściwy sposób to zrobić, szkoda, że ​​nie myślał o tym sam! Zakładając, że wszystkie tabele PK oryginalnego stołu będą obecne w tabeli docelowej, , nie ma potrzeby stosowania tymczasowej tabeli - wystarczy użyć złożonych warunków WHERE, aby wstawić do miejsca docelowego, a następnie DELETE z oryginalnej tabeli, dołączając do tej tabeli. Czuję się głupio, że sugeruję teraz osobny stolik! :)

+0

Stół tymczasowy dostaje mój głos. Aktualizowanie wierszy i ich usuwanie oznacza tworzenie wielu śmieci w stercie, a także wymuszanie dotykania schematu stołu (co nie ma znaczenia) – araqnid

+0

+1 dla tabeli tymczasowej dla PK. – rfusca

+4

Nie będziesz potrzebował tabeli tymczasowej ani kosztownej dwukrotnej kalkulacji. Wykonaj obliczenia raz podczas wstawiania do nowej tabeli. Następnie usuń ze starej tabeli, gdzie rekord znajduje się w nowej tabeli. –

24

[Rozszerzając dvv's answer]

można przenieść do istniejącego tabela w następujący sposób. W przypadku niedopasowanego schematu należy określić kolumny.

WITH moved_rows AS (
    DELETE FROM <original_table> a 
    USING <other_table> b 
    WHERE <condition> 
    RETURNING a.* -- or specify columns 
) 
INSERT INTO <existing_table> --specify columns if necessary 
SELECT [DISTINCT] * FROM moved_rows; 

Ale chcesz przenieść dane do nowego stole (nie istniejący), składnia jest inna zewnętrzna:

CREATE TABLE <new_table> AS 
WITH moved_rows AS (
    DELETE FROM <original_table> a 
    USING <other_table> b 
    WHERE <condition> 
    RETURNING a.* -- or specify columns 
) 
SELECT [DISTINCT] * FROM moved_rows; 
Powiązane problemy