Bisher haben Sie gesehen, wie Daten mit Hilfe von INSERT in die Datenbank eingefügt werden können. Das ist denkbar ineffizient, da sehr viel Parsing Overhead entsteht. Um dieses Problem zu umgehen, kann COPY verwendet werden:
test=# \h COPY
Command: COPY
Description: copy data between a file and a table
Syntax:
COPY tablename [ ( column [, ...] ) ]
FROM { 'filename' | STDIN }
[ [ WITH ]
[ BINARY ]
[ OIDS ]
[ DELIMITER [ AS ] 'delimiter' ]
[ NULL [ AS ] 'null string' ]
[ CSV [ QUOTE [ AS ] 'quote' ]
[ ESCAPE [ AS ] 'escape' ]
[ FORCE NOT NULL column [, ...] ]
COPY tablename [ ( column [, ...] ) ]
TO { 'filename' | STDOUT }
[ [ WITH ]
[ BINARY ]
[ OIDS ]
[ DELIMITER [ AS ] 'delimiter' ]
[ NULL [ AS ] 'null string' ]
[ CSV [ QUOTE [ AS ] 'quote' ]
[ ESCAPE [ AS ] 'escape' ]
[ FORCE QUOTE column [, ...] ]
COPY verfügt über effiziente Methoden, Daten direkt und ohne große Umwege in das Storage System zu schreiben. Das spart bei größeren Datenmengen sehr viel Zeit. Obwohl COPY zahlreiche Möglichkeiten bietet, ist die Performance trotzdem einzigartig.
Im folgenden Beispiel versuchen wir einen Teil von /etc/passwd in eine Tabelle zu kopieren. Zuallererst extrahieren wir die ersten 10 Zeilen aus der Datei:
[hs@athlon tmp]$ head /etc/passwd > import.txt [hs@athlon tmp]$ cat import.txt root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt mail:x:8:12:mail:/var/spool/mail:/sbin/nologin news:x:9:13:news:/etc/news:
In weiterer Folge legen wir eine Tabelle an, die die einzelnen Spalten von /etc/passwd speichern kann:
test=# CREATE TABLE t_passwd ( account text, passwd text, uid int4, gid int4, gecos text, directory text, shell text); CREATE TABLE
Um unsere Datei zu importieren, können wir nun COPY aufrufen:
test=# COPY t_passwd FROM '/tmp/import.txt' DELIMITER AS ':'; COPY
Als Trennzeichen (Delimiter) verwenden wir einen Doppelpunkt. Sofern das COPY funktioniert, werden wir die folgende Tabelle wiederfinden:
test=# SELECT * FROM t_passwd; account | passwd | uid | gid | gecos | directory | shell ----------+--------+-----+-----+----------+-----------------+---------------- root | x | 0 | 0 | root | /root | /bin/bash bin | x | 1 | 1 | bin | /bin | /sbin/nologin daemon | x | 2 | 2 | daemon | /sbin | /sbin/nologin adm | x | 3 | 4 | adm | /var/adm | /sbin/nologin lp | x | 4 | 7 | lp | /var/spool/lpd | /sbin/nologin sync | x | 5 | 0 | sync | /sbin | /bin/sync shutdown | x | 6 | 0 | shutdown | /sbin | /sbin/shutdown halt | x | 7 | 0 | halt | /sbin | /sbin/halt mail | x | 8 | 12 | mail | /var/spool/mail | /sbin/nologin news | x | 9 | 13 | news | /etc/news | (10 rows)
Alle Werte werden fein säuberlich getrennt in Spalten ausgegeben. Wichtig zu wissen ist, dass der gesamte Datenbestand innerhalb einer Transaktion importiert wird - wenn COPY also abbricht, ist sichergestellt, dass kein Datenmüll in der Tabelle verbleibt. Man sagt, dass ein Import mit COPY um mindestens Faktor 6 schneller ist als mit INSERT. Klarerweise hängt das sehr stark von der Datenstruktur.
Wollen wir den Datenbestand anschließend wieder exportieren, können Sie wie folgt vorgehen:
test=# COPY t_passwd TO '/tmp/export' DELIMITER AS ':'; COPY
Wenn wir als Trennzeichen wieder einen Doppelpunkt verwenden, wird sich die Ergebnisdatei nicht vom Input unterscheiden:
[hs@athlon hs]$ diff /tmp/export /tmp/import.txt [hs@athlon hs]$