2010-06-04 19 views
9

Mi piacerebbe spostare alcuni dati da una tabella a un'altra (con uno schema forse diverso). soluzione semplice che viene in mente è -sposta i dati da una tabella a un'altra, edizione 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; 

Ora, cosa succede se la quantità di dati è piuttosto grande, e la <condition> è costoso per calcolare? In PostgreSQL, è possibile utilizzare una regola o una stored procedure per eliminare i dati al volo, valutando le condizioni una sola volta. Quale soluzione è migliore? Ci sono altre opzioni?

risposta

0

Potreste scaricare i dati della tabella in un file, quindi inserirla in un'altra tabella utilizzando COPY solito COPY è più veloce di INSERT.

+1

Ho fatto un po 'di elaborazione test grandi quantità di dati utilizzando i trigger, riga per riga e utilizzando una stored procedure con una singola transazione. L'approccio alla stored procedure era più veloce. – pcent

+0

Dovresti anche ottimizzare il tuo server PostgreSQL per migliorare le prestazioni. Leggi: http://wiki.postgresql.org/wiki/Performance_Optimization – pcent

+0

yah, penso che le linee guida dovrebbero essere qualificate per affermare che una COPIA è più veloce di un insieme di istruzioni INSERT, una per riga. INSERISCI ... SELEZIONA per copiare i dati in giro penso che sia ottimale dato che i dati non vengono passati all'esterno dell'esecutore. – araqnid

7

Se la condizione è così complicata che non si desidera eseguirla due volte (cosa che a BTW sembra improbabile, ma comunque), una possibilità sarebbe quella di ALTER TABLE ... ADD COLUMN nella tabella originale per aggiungere un campo booleano ed eseguire un UPDATE sulla tabella per impostare il campo su true WHERE <condition>. Quindi i tuoi comandi INSERT e DELETE possono semplicemente controllare questa colonna per le loro clausole WHERE.

Non dimenticare di eliminare la colonna dalle tabelle di origine e di destinazione in seguito!

Hmm, ancora meno invadente sarebbe creare una nuova tabella temporanea il cui unico scopo è contenere i PK di record che si desidera includere. Innanzitutto INSERT a questa tabella per "definire" l'insieme di righe su cui operare, quindi unire questa tabella per copiare la tabella INSERT e DELETE. Questi join saranno veloci poiché i PK della tabella sono indicizzati.


[EDIT] suggerimento di Scott Bailey nei commenti è, ovviamente, il modo giusto per fare questo, desiderio che avevo pensato io! Supponendo che tutti i campi PK della tabella originale siano presenti nella tabella di destinazione, non è necessaria una tabella temporanea: è sufficiente utilizzare le complesse condizioni WHERE da inserire nella destinazione, quindi DELETE dalla tabella originale unendosi a questa tabella. Mi sento stupido per aver suggerito un tavolo separato ora! :)

+0

Il tavolo temporaneo ottiene il mio voto. Aggiornare le righe e cancellarle significa creare molta spazzatura nell'heap, oltre a richiedere il contatto con lo schema della tabella (non quello che conta davvero) – araqnid

+0

+1 per la tabella temporanea per PK. – rfusca

+4

Non avrai bisogno della tabella temporanea o di fare due volte un calcolo costoso. Esegui il calcolo una volta mentre inserisci una nuova tabella. Quindi fai una cancellazione dalla vecchia tabella in cui il record è nella nuova tabella. –

24

[Ampliando dvv's answer]

È possibile passare a una esistente tabella come segue. Per uno schema senza corrispondenza, è necessario specificare le colonne.

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; 

Ma si desidera spostare i dati in una nuova tavolo (non uno già esistente) , la sintassi esterna è diversa:

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; 
Problemi correlati