Як ефективно копіювати мільйони рядків з однієї таблиці в іншу в Postgresql?


37

У мене є дві таблиці баз даних. Один містить сотні мільйонів записів. Давайте зателефонуємо тому history. Інший обчислюється щодня, і я хочу скопіювати всі його записи в historyодин.

Що я зробив, це бігати:

INSERT INTO history SELECT * FROM daily

І це робило трюк деякий час, але воно починало повільніше і повільніше, оскільки кількість записів постійно зростала. Тепер у мене є близько 2 мільйонів записів , які повинні бути скопійовані з dailyдо historyв одній операції , і це займає надто багато часу , щоб закінчити.

Чи існує інший, більш ефективний спосіб копіювання даних з однієї таблиці в іншу?

Відповіді:


10

Якщо ви плануєте зберігати історію протягом довгих періодів (багато місяців), пропоную ознайомитись з параметрами розділення - це може бути один розділ на кожен день або тиждень тощо. Це також залежить від шаблонів доступу до вашої таблиці історії (чи виконуєте ви запити, які отримують доступ до даних через дати? Ви робите багато агрегацій тощо). Погляньте на матеріалізовані подання для зберігання агрегатів / резюме. http://www.postgresql.org/docs/9.3/static/ddl-partitioning.html http://www.postgresql.org/docs/9.3/static/sql-creatematerializedview.html


Дякую за відповідь. Здається, це єдиний шлях. Мені потрібно було б розділити дані по місяцях і, таким чином, зробити реіндексінг (оскільки регенерація індексу тут була проблемою) набагато швидше.
Мілован Зогович

16

Скиньте таблицю у форматі CSV

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

використовуйте команду COPY, яка набагато ефективніша для великих обсягів даних.

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

Перевірте документи postgres на веб- сайті http://www.postgresql.org/docs/current/static/sql-copy.html для отримання додаткової інформації


1
Її все ще працюють дуже, дуже повільно ... Можливо, це має щось зробити, щоб відновити такий величезний індекс? У historyтаблиці 160 мільйонів рядків , а ми додаємо ще 3 мільйони рядків.
Мілован Зогович

2
З вас ви заповнюєте порожню таблицю або додаєте більше рядків, ніж уже існує, зазвичай ефективніше скидати некластеризовані індекси та відтворювати їх, коли передача завершена (якщо тільки в цей час не використовується активне використання таблиць (и). )
Девід Спіллетт

До речі, це одноразова операція чи це щось, що вам потрібно регулярно робити? Якщо це регулярно, я вважаю, що ви створюєте тригер, тому вам не доведеться щоразу проходити це випробування.
Фабріціо Маццоні

@FabrizioMazzoni - це повинно проводитися щодня в конкретний час (своєчасно робити знімки в часі).
Мілован Зогович

@DavidSpillett - справді! Видалення індексів робить імпорт дуже швидким (див. Мою відповідь вище), однак відтворення індексів займає години (оскільки у мене в базі даних 160М рядків).
Мілован Зогович,

14

Проблема була з індексами. historyТаблиця була 160M індексованих рядків. Запустивши або, COPY FROMабо INSERT INTO .. SELECTзнадобилося багато часу, щоб не вставити рядки, а оновити індекси. Коли я відключив індекси, він імпортував 3М рядків за 10 секунд. Тепер мені потрібно знайти швидший спосіб перевстановлення великої таблиці.


3
Вам навіть потрібні індекси на таблиці історії?
Шерлок

2
Додайте індекс за допомогою
СУЧАСНОГО

10

Ви можете використовувати інструмент psql , я можу бути ефективним, як показано нижче,

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"

Також ви можете написати сценарій оболонки.


Прекрасне рішення без проміжного файлу. Також дуже швидко я скопіював таблицю 950 мільйонів рядків за 1h20 (без індексів) між звичайним диском та мережевою файловою системою.
Le Droid

3

Звичайно, це не точна відповідь на ваше запитання, але якщо вам не потрібно отримувати доступ до historyтаблиці, ви також можете створити дамп SQL:

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

Тоді можна було б використовувати такий інструмент, як, gitщоб обчислити різницю та ефективно зберігати його.

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

Це корисно, оскільки більшість частин бази даних не змінюватимуться щодня. Замість того, щоб зберігати цілу копію на кожен день, можна зберігати різницю між двома днями.

Можна використовувати таку crontabроботу, що скидання обробляється щодня.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.