Акция Панель управления ispmanager для VDS — первый месяц бесплатно
до 31.07.2026 Подробнее
Выберите продукт

PostgreSQL tablespace: перенос таблиц и индексов, контроль диска и планирование обслуживания

Tablespace в PostgreSQL помогает вынести «тяжёлые» таблицы и индексы на отдельные диски, контролировать рост данных и снизить риск переполнения раздела. В статье — создание tablespace, перенос через ALTER TABLE/INDEX, оценка размеров и чек-лист обслуживания.
PostgreSQL tablespace: перенос таблиц и индексов, контроль диска и планирование обслуживания

Зачем вообще нужен tablespace в PostgreSQL

Tablespace в PostgreSQL — это логическое имя, привязанное к каталогу в файловой системе. В этом каталоге будут храниться файлы данных отдельных объектов: таблиц, индексов, materialized view и т. п. Практический смысл простой: вы управляете размещением «тяжёлых» объектов по разным дискам/томам, не поднимая отдельные кластеры.

Типовые сценарии, где tablespace реально помогает:

  • Разнести I/O: индексы на быстрый NVMe, таблицы на более ёмкий диск.
  • Упростить расширение хранилища: когда один раздел заканчивается, переносите крупные отношения в новый tablespace.
  • Контроль стоимости: горячие данные на SSD, архив на HDD.
  • Изоляция рисков: временные/ETL-объекты отдельно, чтобы они не «съели» место у продовых таблиц.

Tablespace не ускоряет PostgreSQL «магически». Он даёт контроль над размещением на уровне файловой системы. Прирост производительности появляется только если вы осознанно выбираете устройства хранения и нагрузка действительно упирается в I/O.

Какие tablespace есть по умолчанию

В каждом кластере PostgreSQL есть минимум два системных пространства:

  • pg_default — дефолтное место для большинства объектов.
  • pg_global — служебные глобальные объекты кластера (обычно его не трогают).

Пользовательские tablespace вы создаёте сами и выбираете, какие объекты туда отправлять: сразу при создании или позже — переносом.

Схема: отдельный том и каталоги для PostgreSQL tablespace

Подготовка: что проверить до создания tablespace

Файловая система, путь и права

Каталог tablespace должен существовать на сервере и быть доступен пользователю ОС, под которым работает PostgreSQL (чаще всего postgres). На практике лучше сразу воспринимать tablespace как «контракт» между БД и файловой системой: путь должен быть стабильным, а диск — предсказуемым по поведению.

  • Предпочтительно держать tablespace на отдельном смонтированном томе (LVM/RAID/отдельный диск), а не просто в подпапке того же раздела.
  • Убедитесь, что выбранная ФС и mount-опции подходят под БД (корректные барьеры записи, без экспериментальных опций).
  • Сразу продумайте резервное копирование и восстановление: tablespace физически лежит вне каталога данных, но логически является частью кластера.

Кто может создавать tablespace

Операции с tablespace обычно требуют прав суперпользователя PostgreSQL или роли, которой разрешено управление tablespace. В некоторых управляемых средах это ограничено политиками безопасности — лучше уточнить до начала работ, чтобы не упереться в ограничения во время окна обслуживания.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Создание tablespace: безопасный минимальный рецепт

Пример: хотим создать tablespace для индексов на отдельном диске.

sudo -u postgres mkdir -p /pgdata_ts/indexes
sudo -u postgres chmod 700 /pgdata_ts/indexes

Создаём tablespace в SQL:

CREATE TABLESPACE ts_indexes LOCATION '/pgdata_ts/indexes';

Проверяем список tablespace в psql:

\db

Если нужно ограничить доступ, назначьте владельца и дальше выдавайте права точечно:

ALTER TABLESPACE ts_indexes OWNER TO app_owner;

Полезная привычка: фиксируйте в документации, что хранится в tablespace и какой диск за ним стоит. Это упрощает инциденты «место заканчивается» и планирование расширения.

Перенос таблицы: ALTER TABLE SET TABLESPACE

Базовая команда переноса таблицы:

ALTER TABLE public.orders SET TABLESPACE ts_data;

Важные эксплуатационные моменты:

  • Это физическое перемещение (переписывание файлов). Нужны I/O и время.
  • Будут блокировки уровня таблицы. На активных системах перенос почти всегда планируют в maintenance window.
  • Индексы не обязаны «переехать» вместе с таблицей. Их tablespace задаётся отдельно, и часто таблица остаётся в одном месте, а индексы — в другом.

Как задать tablespace по умолчанию для новых объектов

Для базы данных можно задать tablespace по умолчанию (это влияет на будущие объекты, но не перемещает существующие):

ALTER DATABASE appdb SET TABLESPACE ts_data;

Если нужна именно «миграция всего», обычно делают план: сначала перенос самых больших индексов, затем таблиц волнами, затем выравнивание политики по схемам и ролям.

Перенос индекса: ALTER INDEX SET TABLESPACE

Индекс переносится отдельной командой:

ALTER INDEX public.orders_created_at_idx SET TABLESPACE ts_indexes;

На практике перенос индекса часто проще (и «дешевле» по времени), чем перенос большой таблицы, но блокировки и конкуренция за I/O всё равно будут. В высоконагруженных системах обычно переносят индексы пачками, с контролем длительности и откатом по необходимости.

Сгенерировать команды переноса для всех индексов схемы

Удобный приём — сгенерировать SQL из каталога и прогонять его по списку, логируя результаты:

SELECT format('ALTER INDEX %I.%I SET TABLESPACE ts_indexes;', n.nspname, c.relname)
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = 'i'
  AND n.nspname = 'public';

Если вы делаете это в проде, прогоняйте команды по одной, отслеживайте блокировки и время выполнения. Для отдельной темы про борьбу с раздуванием (когда перенос совмещают с переупаковкой) см. материал про уменьшение bloat и обслуживание pg_repack.

Как оценить размеры: pg_relation_size и pg_total_relation_size

Перед переносом полезно понять, кто именно «ест диск». Базовая функция pg_relation_size показывает размер самой relation (например, таблицы без индексов):

SELECT pg_size_pretty(pg_relation_size('public.orders'));

Чаще нужен полный размер таблицы вместе с индексами и TOAST — для этого используйте pg_total_relation_size:

SELECT pg_size_pretty(pg_total_relation_size('public.orders'));

Найти топ самых «тяжёлых» таблиц по полной занимаемой площади:

SELECT
  n.nspname AS schema,
  c.relname AS table,
  pg_size_pretty(pg_total_relation_size(c.oid)) AS total_size
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = 'r'
ORDER BY pg_total_relation_size(c.oid) DESC
LIMIT 20;

Эти запросы удобно держать как «оперативный набор» на случай инцидентов, когда нужно быстро принять решение: переносить, чистить, расширять диск или ограничивать рост.

Виртуальный хостинг FastFox
Виртуальный хостинг для сайтов
Универсальное решение для создания и размещения сайтов любой сложности в Интернете от 95₽ / мес

Мониторинг диска: что смотреть кроме df

df показывает занятость разделов, но для PostgreSQL важна связка «уровень ОС» и «уровень БД». Практично мыслить тремя слоями:

  • ОС: свободное место, inode, I/O wait, задержки диска.
  • Кластер PostgreSQL: рост каталогов, WAL, временных файлов, частота и длительность чекпоинтов.
  • Объекты: какие таблицы/индексы растут, где bloat, какие операции его провоцируют.

Быстрые команды на стороне ОС (частый старт при инциденте «заканчивается место»):

df -h
df -i
du -sh /var/lib/postgresql
du -sh /pgdata_ts

Дальше сопоставляйте это с топом по pg_total_relation_size и принимайте решение: что переносить, что обслуживать (REINDEX/VACUUM FULL/pg_repack), а где проблема вообще не в таблицах (например, в WAL или временных файлах).

Если вы храните бэкапы на отдельном хранилище, пригодится понятный, воспроизводимый процесс. В тему может быть полезна статья про бэкапы на объектное хранилище с restic/borg (подходы применимы и к PostgreSQL-дампам/бэкапам файлового уровня).

Мониторинг занятости диска для каталогов PostgreSQL и tablespace на Linux

Признаки bloat: когда tablespace помогает, а когда нет

Bloat — раздувание таблиц и индексов из-за MVCC, частых обновлений/удалений, неидеального autovacuum и т. п. Внешне это часто выглядит так: «данных не прибавилось, а диск улетает».

Типичные признаки в проде:

  • Размер таблицы/индекса растёт заметно быстрее, чем бизнес-данные.
  • Запросы замедляются, особенно по индексам (индекс больше, чтений больше).
  • VACUUM проходит, но «место не возвращается» на уровне файловой системы (оно остаётся внутри файла и будет переиспользовано позже).
  • Растёт I/O и время чекпоинтов на фоне той же нагрузки.

Перенос в tablespace не лечит bloat. Он может временно разгрузить переполненный том, но причина раздувания останется. Чтобы реально уменьшить размер на диске, нужны операции обслуживания: REINDEX, VACUUM FULL или переупаковка (например, через pg_repack) — в зависимости от допустимых блокировок и требований к доступности.

Планирование maintenance window: как переносить без сюрпризов

Почти любой серьёзный перенос (особенно таблиц) стоит планировать как работу, влияющую на доступность. С точки зрения эксплуатации критичны четыре вещи: блокировки, скорость копирования, запас места и понятный откат.

Чек-лист перед переносом

  • Оцените размеры через pg_total_relation_size и прикиньте длительность по реальной скорости диска.
  • Проверьте свободное место на целевом томе с запасом; учитывайте рост WAL во время интенсивной записи.
  • Согласуйте окно и предупредите пользователей: возможны задержки и блокировки.
  • Проверьте бэкап и процедуру восстановления до начала работ.

Стратегия «малых шагов»

  • Начните с самых больших индексов: обычно это быстро даёт выигрыш по месту и I/O.
  • Затем переносите крупные таблицы, но только после пробного переноса 1–2 объектов, чтобы понять реальную длительность и влияние.
  • После каждого этапа фиксируйте результат: размеры, latency, время чекпоинтов, жалобы приложений.

Проверка результата: где реально лежит объект

После операций убедитесь, что таблица/индекс действительно в нужном tablespace. Быстрая проверка по системным каталогам:

SELECT
  n.nspname AS schema,
  c.relname AS name,
  c.relkind,
  t.spcname AS tablespace
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
LEFT JOIN pg_tablespace t ON t.oid = c.reltablespace
WHERE n.nspname = 'public'
  AND c.relname IN ('orders', 'orders_created_at_idx');

Если поле tablespace вернулось NULL, это означает, что объект находится в pg_default (то есть использует значение по умолчанию).

Типовые ошибки и подводные камни

«Я перенёс таблицу, но диск почти не освободился»

Частая причина: основной объём занимали индексы, TOAST или другой крупный объект. Смотрите pg_total_relation_size и отдельно размеры индексов; переносите то, что реально большое.

«Операция идёт слишком долго»

Перенос упирается в I/O. На перегруженном диске или при конкурирующей нагрузке он может идти часами. На будущее: планируйте окно, снижайте параллельную активность, переносите в «тихие» часы.

«Сломались бэкапы или восстановление»

При файловых бэкапах и снимках томов tablespace на отдельном диске становится отдельным объектом, который тоже должен попадать в бэкап. Проверьте, что процесс резервного копирования охватывает все пути tablespace.

«Хотел вынести временные объекты»

Под временные данные иногда заводят отдельные tablespace, но часто эффективнее контролировать запросы, которые генерируют огромные сортировки/хэши, и мониторить временные файлы через метрики и настройки.

Мини-план внедрения tablespace в проде

  1. Соберите топ объектов по pg_total_relation_size и поймите, что именно давит на диск.
  2. Зафиксируйте политику размещения: например, «таблицы в ts_data, индексы в ts_indexes».
  3. Создайте tablespace на отдельном томе, проверьте права, бэкап и восстановление.
  4. Сделайте тестовый перенос 1–2 индексов, замерьте время и влияние.
  5. Запланируйте maintenance window и переносите основной объём волнами.
  6. Настройте регулярный мониторинг роста томов и топа размеров в БД.

Итоги

Tablespace в PostgreSQL — это про управляемость: куда растут таблицы и индексы, как быстро расширять хранилище и насколько предсказуемо переживать ситуации «диск заканчивается». Для большинства задач достаточно уверенно владеть ALTER TABLE ... SET TABLESPACE, ALTER INDEX ... SET TABLESPACE и регулярно смотреть размеры через pg_relation_size и pg_total_relation_size. А дальше всё решает дисциплина: мониторинг, работа с bloat и аккуратное планирование окна обслуживания.

Если вы размещаете PostgreSQL на выделенных ресурсах, проще контролировать диски и I/O на уровне виртуальной машины. Для таких задач обычно выбирают VDS, а tablespace используют как инструмент внутри БД для грамотного раскладывания «тяжёлых» объектов.

Поделиться статьей

Вам будет интересно

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину

Ошибка mount: wrong fs type, bad option, bad superblock в Debian/Ubuntu может означать и простую опечатку в имени раздела, и пробл ...
Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление

Если XFS-раздел внезапно стал доступен только для чтения, а сервер ушёл в emergency mode, главное — не спешить. Разберём безопасны ...
Debian/Ubuntu: как исправить Failed to fetch при apt update OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить Failed to fetch при apt update

Ошибка Failed to fetch при apt update в Debian и Ubuntu обычно связана не с самим APT, а с DNS, сетью, зеркалом, прокси, временем ...