web-dev-qa-db-fra.com

Comment copier efficacement des millions de lignes d'une table à une autre dans Postgresql?

J'ai deux tables de base de données. L'un contient des centaines de millions d'enregistrements. Permet d'appeler celui-là history. L'autre est calculé quotidiennement et je veux copier tous ses enregistrements dans celui de history.

Ce que j'ai fait, c'est de courir:

INSERT INTO history SELECT * FROM daily

Et cela a fait l'affaire pendant un certain temps, mais cela a commencé à devenir de plus en plus lent à mesure que le nombre de disques augmentait. Maintenant, j'ai environ 2 millions d'enregistrements qui doivent être copiés de daily vers history en une seule opération et cela prend trop de temps.

Existe-t-il un autre moyen plus efficace de copier des données d'une table à une autre?

38
Milovan Zogovic

Si vous prévoyez de conserver l'historique pendant de longues périodes (plusieurs mois), je vous suggère d'examiner les options de partitionnement - il peut s'agir d'une partition pour chaque jour ou semaine, etc. Cela dépend également des modèles d'accès de votre table d'historique (exécutez-vous des requêtes qui accèdent aux données à travers les dates? Faites-vous beaucoup d'agrégations, etc.). Jetez un œil aux vues matérialisées pour le stockage des agrégats/résumés. http://www.postgresql.org/docs/9.3/static/ddl-partitioning.htmlhttp://www.postgresql.org/docs/9.3/static/sql- creatematerializedview.html

10
Jayadevan

Vider la table au format csv

COPY table TO '/tmp/table.csv' DELIMITER ',';

utilisez la commande COPY qui est beaucoup plus efficace pour de grandes quantités de données.

COPY table FROM '/tmp/table.csv' DELIMITER ',';

Consultez les documents postgres sur http://www.postgresql.org/docs/current/static/sql-copy.html pour plus d'informations

16
Fabrizio Mazzoni

Le problème était avec les index. La table history avait 160 millions de lignes indexées. En exécutant soit COPY FROM ou INSERT INTO .. SELECT cela prenait beaucoup de temps non pas pour insérer des lignes, mais pour mettre à jour les index. Lorsque j'ai désactivé les index, il a importé des lignes 3M en 10 secondes. Maintenant, je dois trouver un moyen plus rapide de réindexer la grande table.

14
Milovan Zogovic

Vous pouvez utiliser l'outil psql , je pourrais être efficace, comme suit,

psql -h ${DAILY_Host_IP} -p ${PG_PORT} ${DB_NAME} ${USER_NAME} -c "copy daily to stdout " | psql -h ${HISTORY_Host_IP} -p ${PG_PORT} ${DB_NAME} ${USER_NAME}  -c "copy history from stdin"

Vous pouvez également écrire un script Shell.

11
francs

Ce n'est bien sûr pas une réponse exacte à votre question, mais si vous n'avez pas besoin d'accéder à la table history, vous pouvez également générer un vidage SQL:

pg_dump -h Host -p port -w -U user db > dump.sql

Ensuite, on pourrait utiliser un outil comme git pour calculer la différence et la stocker efficacement.

git add dump.sql
git commit -m "temp dump"
git gc --aggressive

Ceci est utile car la plupart des pièces d'une base de données ne changeront pas tous les jours. Au lieu de stocker une copie entière pour chaque jour, on peut stocker la différence entre deux jours.

Vous pouvez utiliser un travail crontab tel que le vidage soit traité tous les jours.

3
Willem Van Onsem