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?
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
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
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.
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.
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.