Оптимізація продуктивності оновлень в PostgreSQL


37

Використання PG 9.1 на Ubuntu 12.04.

Наразі для запуску великого набору операцій UPDATE на базі даних, які мають форму:

UPDATE table
SET field1 = constant1, field2 = constant2, ...
WHERE id = constid

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

У таблицях є декілька індексів, кожен та відсутність зовнішніх ключових обмежень. COMMIT не робиться до кінця.

Щоб імпортувати pg_dumpцілу БД, потрібно 2 години . Це здається базовим рівнем, на який ми мусимо розумно орієнтуватися.

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

Деякі ідеї:

  • скасування всіх індексів без ідентифікації та відновлення після цього?
  • збільшуючи контрольні_сегменти, але чи насправді це допомагає підтримувати довгострокову пропускну спроможність?
  • використовуючи згадані тут методи ? (Завантажте нові дані у вигляді таблиці, а потім "зробіть" старі дані, де ідентифікатор не знайдеться в нових даних)

В основному є маса речей, які слід спробувати, і ми не впевнені, що є найбільш ефективним або якщо ми не помічаємо інших речей. Ми проведемо наступні кілька днів на експерименти, але ми подумали, що запитаємо і тут.

У мене є одночасне навантаження на стіл, але це лише для читання.


У вашому питанні відсутня важлива інформація: Ваша версія Postgres? Звідки беруться значення? Звучить як файл поза базою даних, але уточнюйте, будь ласка. Чи є одночасне навантаження на цільову таблицю? Якщо так, то що саме? Або ти можеш собі дозволити скинути і відтворити? Немає сторонніх ключів, гаразд - але чи існують інші залежні об'єкти, такі як види? Будь-ласка, відредагуйте своє запитання з відсутністю інформації Не стискайте його в коментарі.
Erwin Brandstetter

@ErwinBrandstetter Спасибі, оновив моє запитання.
Ян

Я припускаю, що ви перевірили, explain analyzeщо він використовує індекс для пошуку?
rogerdpack

Відповіді:


45

Припущення

Оскільки в Q немає інформації, я припускаю:

  • Ваші дані надходять з файлу на сервері баз даних.
  • Дані відформатовані так само COPY вихідні дані, з унікальним для id кожного рядка відповідним цільовій таблиці.
    Якщо ні, то відформатуйте спочатку належним чином або скористайтеся COPYопціями, щоб мати справу з форматом.
  • Ви оновлюєте кожен рядок у цільовій таблиці або більшість із них.
  • Ви можете дозволити собі скинути та відтворити цільову таблицю.
    Це означає відсутність паралельного доступу. Ще розглянути цю відповідь:
  • Залежні об'єкти взагалі відсутні, крім індексів.

Рішення

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

Для створення тимчасової таблиці існує більш простий і швидкий спосіб:

CREATE TEMP TABLE tmp_tbl AS SELECT * FROM tbl LIMIT 0;

Єдиний великий UPDATEз тимчасового столу всередині бази даних буде швидше, ніж окремі оновлення за межами бази даних на кілька порядків.

У моделі MVCC PostgreSQL - UPDATEзасіб створити нову версію рядка та позначити стару як видалену. Це приблизно так само дорого, як INSERTіDELETE поєднанні. Плюс це залишає у вас багато мертвих кортежів. Оскільки ви все одно оновлюєте всю таблицю, було б загалом швидше просто створити нову таблицю і скинути стару.

Якщо у вас є достатня кількість оперативної пам’яті, встановітьtemp_buffers (лише для цього сеансу!) Досить високу, щоб утримувати таблицю темп в оперативній пам’яті - перш ніж робити щось інше.

Щоб отримати оцінку, скільки потрібно оперативної пам’яті, проведіть тест з невеликим зразком і використовуйте функції розміру об’єкта db :

SELECT pg_size_pretty(pg_relation_size('tmp_tbl'));  -- complete size of table
SELECT pg_column_size(t) FROM tmp_tbl t LIMIT 10;  -- size of sample rows

Повний сценарій

SET temp_buffers = '1GB';        -- example value

CREATE TEMP TABLE tmp_tbl AS SELECT * FROM tbl LIMIT 0;

COPY tmp_tbl FROM '/absolute/path/to/file';

CREATE TABLE tbl_new AS
SELECT t.col1, t.col2, u.field1, u.field2
FROM   tbl     t
JOIN   tmp_tbl u USING (id);

-- Create indexes like in original table
ALTER TABLE tbl_new ADD PRIMARY KEY ...;
CREATE INDEX ... ON tbl_new (...);
CREATE INDEX ... ON tbl_new (...);

-- exclusive lock on tbl for a very brief time window!
DROP TABLE tbl;
ALTER TABLE tbl_new RENAME TO tbl;

DROP TABLE tmp_tbl; -- will also be dropped at end of session automatically

Одночасне навантаження

Одночасні операції над таблицею (які я виключав у припущеннях на початку) зачекають, як тільки таблиця буде заблокована наприкінці, і завершиться невдачею, як тільки транзакція буде здійснена, тому що назва таблиці негайно вирішиться до її OID, але нова таблиця має інший OID. Таблиця залишається послідовною, але паралельні операції можуть отримати виняток і їх потрібно повторити. Деталі у цій відповіді:

ОНОВЛЕННЯ маршруту

Якщо ви (повинні) пройти UPDATEмаршрут, опустіть будь-який індекс, який не потрібен під час оновлення, і відтворіть його після цього. Набагато дешевше створити індекс в одній частині, ніж оновлювати його для кожного окремого рядка. Це також може призвести до гарячих оновлень .

Я окреслив аналогічну процедуру, використовуючи UPDATEв цій тісно пов'язаній з цим відповідь на ПЗ .

 


1
Я фактично лише оновлюю 20% рядків у цільовій таблиці - не всі, але досить велика частина, що злиття, ймовірно, краще, ніж прагне випадкове оновлення.
Ян

1
@AryehLeibTaurog: Це не повинно відбуватися, оскільки DROP TABLEвиймає Access Exclusive Lock. Так чи інакше, я вже вказав передумову у верхній частині своєї відповіді: You can afford to drop and recreate the target table.Це може допомогти заблокувати таблицю на початку транзакції. Я пропоную вам почати нове запитання з усіма релевантними деталями вашої ситуації, щоб ми могли дійти до цього.
Erwin Brandstetter

1
@ErwinBrandstetter Цікаво. Здається, це залежить від версії сервера. Я відтворив помилку 8.4 і 9.1 за допомогою адаптера psycopg2 та використання клієнта psql . На 9.3 помилки немає. Дивіться мої коментарі в першому сценарії. Я не впевнений, чи є тут питання, але можливо варто звернути якусь інформацію в один із списків postgresql.
Aryeh Leib Taurog

1
Я написав простий клас помічників у python для автоматизації процесу.
Aryeh Leib Taurog

3
Дуже корисна відповідь. Як незначна зміна, можна створити тимчасову таблицю з лише стовпцями, що підлягають оновленню, та стовпцями посилань, видалити стовпці для оновлення з вихідної таблиці, потім об'єднати таблиці, використовуючи CREATE TABLE tbl_new AS SELECT t.*, u.field1, u.field2 from tbl t NATURAL LEFT JOIN tmp_tbl u;, що LEFT JOINдозволяє зберігати рядки, для яких немає оновлення. Звичайно, їх NATURALможна змінити на будь-який дійсний USING()або ON.
Skippy le Grand Gourou

2

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


3
Що ви маєте на увазі під поняттям "злиття на цільовій таблиці"? Чому використання FDW краще, ніж COPYing, у тимчасовій таблиці (як це запропоновано в третій кулі в оригінальному запитанні)?
Ян

"Злиття", як у заяві MERGE sql. Використання FDW дозволяє зробити це без додаткового кроку копіювання даних у тимчасову таблицю. Я припускаю, що ви не замінюєте весь набір даних і що у файлі буде певна кількість даних, яка не відображатиме зміну від поточного набору даних - якщо значна кількість змінилася, то повна заміна столу може бути доречною.
Девід Олдрідж

1
@DavidAldridge: Хоча визначено у стандарті SQL: 2003, MERGEвін не реалізований у PostgreSQL (поки що). Реалізація в інших RDBMS досить різниться. Розглянемо інформацію про теги для MERGEта UPSERT.
Ервін Брандстеттер

@ErwinBrandstetter [glurk] О так, так. Ну Merge - це глазур на торті, справді я гадаю. Доступ до даних без кроку імпорту до тимчасової таблиці - це справді суть техніки FDW.
Девід Олдрідж
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.