До мого питання є 2 частини.
- Чи є спосіб вказати початковий розмір бази даних в PostgreSQL?
- Якщо цього немає, як боротися з фрагментацією, коли база даних зростає з часом?
Нещодавно я перейшов з MSSQL на Postgres, і однією з речей, які ми робили у світі MSSQL при створенні бази даних, було вказати початковий розмір бази даних та журналу транзакцій. Це зменшило фрагментацію та підвищило продуктивність, особливо якщо заздалегідь відомий "нормальний" розмір бази даних.
У міру збільшення розміру продуктивність моєї бази даних падає. Наприклад, робоче навантаження, яке я переношу, зазвичай займає 10 хвилин. Зі збільшенням бази даних цей час збільшується. Здійснення VACUUM, VACUUM FULL та VACUUM FULL ANALYZE не вирішує проблему. Що вирішує проблему продуктивності - це зупинка бази даних, дефрагментація диска, а потім виконання ВАКУУМОВОГО АНАЛІЗУ приводить показники мого тесту до початкових 10 хвилин. Це змушує мене підозрювати, що фрагментація - це те, що заподіює мені біль.
Я не зміг знайти жодної посилання на резервування простору таблиць / простору бази даних у Postgres. Або я використовую неправильну термінологію і, таким чином, нічого не знаходжу, або є інший спосіб пом'якшення фрагментації файлової системи в Postgres.
Якісь покажчики?
Рішення
Надані відповіді допомогли підтвердити те, про що я почав підозрювати. PostgreSQL зберігає базу даних у декількох файлах, і саме це дозволяє базі даних рости, не турбуючись про фрагментацію. Поведінка за замовчуванням полягає в тому, щоб упакувати ці файли до крайок з даними таблиці, що добре для таблиць, які рідко змінюються, але погано для таблиць, які часто оновлюються.
PostgreSQL використовує MVCC для забезпечення одночасного доступу до даних таблиці. Відповідно до цієї схеми, кожне оновлення створює нову версію рядка, який був оновлений (це може бути через штамп часу або номер версії, хто знає?). Старі дані не відразу видаляються, але позначаються для видалення. Фактичне видалення відбувається при виконанні операції VACUUM.
Як це стосується коефіцієнта заповнення? Коефіцієнт заповнення таблиці за замовчуванням 100 повністю упаковує сторінки таблиці, що, в свою чергу, означає, що на сторінці таблиці немає місця для розміщення оновлених рядків, тобто оновлені рядки будуть розміщені на іншій сторінці таблиці від початкового рядка. Це погано для продуктивності, як показує мій досвід. Оскільки мої зведені таблиці оновлюються дуже часто (до 1500 рядків / сек), я вирішив встановити коефіцієнт заповнення 20, тобто 20% таблиці буде для вставлених даних рядків і 80% для даних оновлення. Хоча це може здатися надмірним, велика кількість місця, відведеного для оновлених рядків, означає, що оновлені рядки залишаються на тій самій сторінці, що і оригінал, і там сторінка таблиці не заповнена до моменту запуску демона автовакууму для видалення застарілих рядків.
Щоб "виправити" мою базу даних, я зробив наступне.
- Встановіть коефіцієнт заповнення моїх підсумкових таблиць на 20. Ви можете це зробити під час створення, передавши параметр CREATE TABLE або після факту через ALTER TABLE. Я видав таку команду plpgsql:
ALTER TABLE "my_summary_table" SET (fillfactor = 20);
- Випустив VACUUM FULL, оскільки він пише абсолютно нову версію файлу таблиці і, таким чином, за наслідками записує новий файл таблиці з новим коефіцієнтом заповнення .
Переглядаючи мої тести, я не бачу погіршення продуктивності, навіть коли база даних є такою великою, як мені потрібно, щоб вона мала багато мільйонів рядків.
TL; DR - Фрагментація файлів не була причиною, це фрагментація простору таблиці. Це пом'якшується шляхом підстроювання коефіцієнта заповнення таблиці відповідно до конкретного випадку використання.