HAFTUNGSAUSSCHLUSS: Diese Frage ähnelt der Frage zum Stapelüberlauf hier , aber keine dieser Antworten funktioniert für mein Problem, wie ich später erläutern werde.
Ich versuche, eine große Tabelle (~ 40 Millionen Zeilen, mehr als 100 Spalten) in Postgres zu kopieren, in der viele Spalten indiziert sind. Derzeit verwende ich dieses SQL-Bit:
CREATE TABLE <tablename>_copy (LIKE <tablename> INCLUDING ALL);
INSERT INTO <tablename>_copy SELECT * FROM <tablename>;
Diese Methode hat zwei Probleme:
- Es fügt die Indizes vor der Datenaufnahme hinzu, sodass es viel länger dauert, als die Tabelle ohne Indizes zu erstellen und nach dem Kopieren aller Daten zu indizieren.
- Dadurch werden Spalten im SERIAL-Stil nicht ordnungsgemäß kopiert. Anstatt einen neuen 'Zähler' für die neue Tabelle einzurichten, wird der Standardwert der Spalte in der neuen Tabelle auf den Zähler der letzten Tabelle gesetzt, was bedeutet, dass er beim Hinzufügen von Zeilen nicht erhöht wird.
Die Tabellengröße macht die Indizierung zu einem Echtzeitproblem. Es macht es auch unmöglich, in eine Datei zu kopieren, um sie dann erneut aufzunehmen. Ich habe auch nicht den Vorteil einer Kommandozeile. Ich muss dies in SQL tun.
Was ich tun möchte, ist entweder direkt eine exakte Kopie mit einem Wunderbefehl zu erstellen oder, wenn dies nicht möglich ist, die Tabelle mit allen Einschränkungen, aber ohne Indizes, zu kopieren und sicherzustellen, dass es sich um die Einschränkungen "im Geiste" handelt (auch bekannt als) einen neuen Zähler für eine SERIAL-Spalte). Kopieren Sie dann alle Daten mit a SELECT *
und kopieren Sie dann alle Indizes.
Quellen
Frage zum Stapelüberlauf beim Kopieren von Datenbanken : Dies ist aus drei Gründen nicht das, wonach ich frage
- Es verwendet die Befehlszeilenoption
pg_dump -t x2 | sed 's/x2/x3/g' | psql
und in dieser Einstellung habe ich keinen Zugriff auf die Befehlszeile - Es werden die Indizes vor der Datenaufnahme erstellt, was langsam ist
- Es aktualisiert die seriellen Spalten nicht korrekt als Beweis von
default nextval('x1_id_seq'::regclass)
- Es verwendet die Befehlszeilenoption
Methode zum Zurücksetzen des Sequenzwerts für eine Postgres-Tabelle : Das ist großartig, aber leider sehr manuell.
pg_dump -t x2 | sed 's/x2/x3/g' | psql
die ich auch keinen Zugriff habe. Zweitens werden die Indizes erstellt, bevor die Daten hinzugefügt werden, die sehr langsam sind! Drittens verweist der Standardparameter der SERIAL immer noch auf die erste Tabelle.default nextval('x1_id_seq'::regclass).
Dies sind drei Fehler, auf die ich bereits in meiner Frage hingewiesen habe. Sie sagen mir, dass es für keines dieser Probleme eine Lösung gibt? @ PeterAntworten:
Nun, du musst leider einige dieser Sachen von Hand machen. Aber es kann alles von so etwas wie psql gemacht werden. Der erste Befehl ist einfach genug:
select * into newtable from oldtable
Dadurch wird eine Newtable mit den Daten von Oldtable erstellt, jedoch nicht mit Indizes. Dann müssen Sie die Indizes und Sequenzen usw. selbst erstellen. Mit dem folgenden Befehl können Sie eine Liste aller Indizes für eine Tabelle abrufen:
select indexdef from pg_indexes where tablename='oldtable';
Führen Sie dann psql -E aus, um auf Ihre Datenbank zuzugreifen, und verwenden Sie \ d, um die alte Tabelle anzuzeigen. Sie können diese beiden Abfragen dann entstellen, um Informationen zu den Sequenzen zu erhalten:
SELECT c.oid, n.nspname, c.relname FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relname ~ '^(oldtable)$' AND pg_catalog.pg_table_is_visible(c.oid) ORDER BY 2, 3; SELECT a.attname, pg_catalog.format_type(a.atttypid, a.atttypmod), (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128) FROM pg_catalog.pg_attrdef d WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef), a.attnotnull, a.attnum FROM pg_catalog.pg_attribute a WHERE a.attrelid = '74359' AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum;
Ersetzen Sie die obige 74359 durch die OID, die Sie aus der vorherigen Abfrage erhalten haben.
quelle
Die
create table as
Funktion in PostgreSQL könnte nun die Antwort sein, nach der das OP gesucht hat.https://www.postgresql.org/docs/9.5/static/sql-createtableas.html
create table my_table_copy as select * from my_table
Dadurch wird eine identische Tabelle mit den Daten erstellt.
Durch Hinzufügen
with no data
wird das Schema ohne die Daten kopiert.create table my_table_copy as select * from my_table with no data
Dadurch wird die Tabelle mit allen Daten erstellt, jedoch ohne Indizes und Trigger usw.
create table my_table_copy (like my_table including all)
Die Syntax zum Erstellen einer Tabelle enthält alle Trigger, Indizes, Einschränkungen usw., jedoch keine Daten.
quelle
(like my_table including all)
Möglicherweise befriedigt das OP nicht, das keine Indizes wollte, aber es ist perfekt für mich, wenn ich versuche, eine Tabelle mit allen Einschränkungen zu erhalten.Der nächste "Wunderbefehl" ist so etwas wie
Dies sorgt insbesondere dafür, dass die Indizes nach dem Laden der Tabellendaten erstellt werden.
Aber das setzt die Sequenzen nicht zurück; Sie müssen das selbst schreiben.
quelle
Verwenden Sie die folgende Anweisung, um eine Tabelle einschließlich Tabellenstruktur und Daten vollständig zu kopieren:
CREATE TABLE new_table AS TABLE existing_table;
Um eine Tabellenstruktur ohne Daten zu kopieren, fügen Sie der Anweisung CREATE TABLE die WITH NO DATA-Klausel wie folgt hinzu:
CREATE TABLE new_table AS TABLE existing_table WITH NO DATA;
Um eine Tabelle mit Teildaten aus einer vorhandenen Tabelle zu kopieren, verwenden Sie die folgende Anweisung:
CREATE TABLE new_table AS SELECT * FROM existing_table WHERE condition;
quelle
WARNUNG:
Alle Antworten, die pg_dump und jede Art von regulärem Ausdruck verwenden, um den Namen der Quelltabelle zu ersetzen, sind wirklich gefährlich. Was ist, wenn Ihre Daten den Teilstring enthalten, den Sie ersetzen möchten? Sie werden am Ende Ihre Daten ändern!
Ich schlage eine Zwei-Pass-Lösung vor:
Hier ist ein Beispiel in Ruby:
Oben versuche ich, die Tabelle "Mitglieder" in "Mitglieder_kopie_20130320" zu kopieren. Mein datenspezifischer regulärer Ausdruck ist /^\d+\t.*(?:t|f)$/
Die obige Art der Lösung funktioniert für mich. Vorbehalt Emptor ...
bearbeiten:
OK, hier ist eine andere Möglichkeit in der Pseudo-Shell-Syntax für die regexp-abgeneigten Personen:
psql -f mytable_copy_schema.sql mydb
pg_dump -a -t mytable mydb> mytable_data.sql
quelle
Anscheinend möchten Sie eine Tabelle "neu erstellen". Wenn Sie eine Tabelle nur neu erstellen und nicht kopieren möchten, sollten Sie stattdessen CLUSTER verwenden.
SELECT count(*) FROM table; -- make a seq scan to make sure the table is at least -- decently cached CLUSTER someindex ON table;
Sie können den Index auswählen und versuchen, einen auszuwählen, der Ihren Abfragen entspricht. Sie können den Primärschlüssel immer verwenden, wenn kein anderer Index geeignet ist.
Wenn Ihre Tabelle zu groß ist, um zwischengespeichert zu werden, kann CLUSTER jedoch langsam sein.
quelle
Tabelle erstellen newTableName (wie oldTableName einschließlich Indizes); In newTableName einfügen Wählen Sie * aus oldTableName
Das hat bei mir funktioniert 9.3
quelle