F.42. pg_partman#
F.42. pg_partman #
- F.42.1. О pg_partman
- F.42.2. Установка
- F.42.3. Обновление
- F.42.4. Примеры
- F.42.5. Расширение для управления секциями PostgreSQL
(
pg_partman
) - F.42.6. Пример руководства по настройке нативного секционирования
- F.42.7. Миграция существующего набора секций в PG Partition Manager
- F.42.8. Миграция с триггерного разбиения на нативное декларативное разбиение
- F.42.9. Руководство по обновлению до pg_partman 5.0.1
pg_partman является расширением для создания и управления наборами таблиц с секционированием по времени и числам. Начиная с версии 5.0.1, поддерживается только встроенное декларативное разделение, а старые методы на основе триггеров устарели.
Встроенное декларативное секционирование в Tantor SE предоставляет команды для создания секционированной таблицы и ее дочерних элементов. pg_partman использует встроенные декларативные функции, которые предоставляет Tantor SE, и дополняет их дополнительными функциями и улучшениями, чтобы упростить управление секциями. Один из ключевых способов, которым pg_partman расширяет секционирование в Postgres, заключается в предоставлении средств для автоматизации обслуживания дочерних таблиц со временем (например, добавление новых дочерних таблиц, удаление старых на основе политики хранения). pg_partman также имеет функции для преобразования существующей таблицы в секционированную таблицу или наоборот.
В большинстве случаев фоновый рабочий процесс (BGW) автоматически выполняется для обслуживания секций без необходимости внешнего планировщика (cron и т.д.).
F.42.2. Установка #
Рекомендуется:
pg_jobmon (>=v1.4.0). PG Job Monitor будет автоматически использоваться, если он установлен и настроен должным образом.
Фоновый рабочий процесс должен быть загружен при запуске базы данных путем добавления
библиотеки в shared_preload_libraries
в postgresql.conf
:
shared_preload_libraries = 'pg_partman_bgw' # (change requires restart)
Вы также можете установить другие управляющие переменные для BGW в
postgresql.conf
. dbname
требуется как минимум для
выполнения обслуживания на указанной базе данных (базах данных). Эти параметры могут быть
добавлены/изменены в любое время с помощью простого перезагрузки. См. документацию для получения более подробной информации. Пример с некоторыми из них:
pg_partman_bgw.interval = 3600 pg_partman_bgw.role = 'keith' pg_partman_bgw.dbname = 'keith'
Войдите в Tantor SE и выполните следующие команды. Схема является
необязательной (но рекомендуется) и может быть любой, какой вы пожелаете, но она
не может быть изменена после установки. Если вы используете BGW,
кластер базы данных можно безопасно запустить без предварительного создания
расширения в настроенной базе данных. Вы можете
создать расширение в любое время, и BGW автоматически обнаружит его существование без перезапуска кластера (при условии, что
shared_preload_libraries
было установлено) и начнет выполнять
обслуживание в соответствии с настройками.
CREATE SCHEMA partman; CREATE EXTENSION pg_partman SCHEMA partman;
pg_partman не требует прав суперпользователя для работы, но в настоящее время
все еще требует их для установки. Если не используется суперпользователь,
рекомендуется создать выделенную роль для выполнения
функций pg_partman и быть владельцем всех наборов секций,
которые поддерживает pg_partman. Как минимум, эта роль должна иметь
следующие привилегии (предполагая, что pg_partman установлен в схему
partman
и что выделенная роль называется
partman_user
):
CREATE ROLE partman_user WITH LOGIN; GRANT ALL ON SCHEMA partman TO partman_user; GRANT ALL ON ALL TABLES IN SCHEMA partman TO partman_user; GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA partman TO partman_user; GRANT EXECUTE ON ALL PROCEDURES IN SCHEMA partman TO partman_user; GRANT ALL ON SCHEMA my_partition_schema TO partman_user; GRANT TEMPORARY ON DATABASE mydb to partman_user; -- allow creation of temp tables to move data out of default
Если вам нужно, чтобы роль также могла создавать схемы, вам потребуется предоставить права на создание в базе данных. В общем, это не должно требоваться, если вы предоставите указанной роли права на создание в любых существующих схемах, которые будут содержать наборы секций.
GRANT CREATE ON DATABASE mydb TO partman_user;
F.42.3. Обновление #
Выполните make install
так же, как выше, или обновите соответствующие
пакеты, чтобы разместить новые файлы скриптов и библиотеки. Затем
выполните следующее в самом Tantor SE:
ALTER EXTENSION pg_partman UPDATE TO '<latest version>';
Если вы выполняете
pg_dump
/pg_restore
и
вы обновили pg_partman на месте с предыдущих версий, рекомендуется использовать опцию --column-inserts
при дампе и/или восстановлении конфигурационных таблиц pg_partman.
Это связано с тем, что порядок конфигурационных столбцов может
быть разным (обновления просто добавляют столбцы в конец,
тогда как по умолчанию при новой установке он может быть другим).
Если вы обновляетесь между любыми основными версиями pg_partman (4.x -> 5.x и т.д.), пожалуйста, внимательно прочитайте все промежуточные заметки о версиях в CHANGELOG, особенно те, которые касаются основной версии. Часто есть дополнительные инструкции и другие важные соображения для обновлений. Особые соображения необходимы, если вы обновляетесь до версии 5+ с любой версии ниже 5.0.0. Пожалуйста, смотрите Раздел F.42.9.
Предупреждение
Некоторые обновления pg_partman должны удалить и воссоздать собственные объекты базы данных. Если вы отзываете привилегии PUBLIC у функций/процедур, они могут быть добавлены обратно к объектам, которые воссоздаются в рамках обновления. Если желательны ограничения на использование PUBLIC для pg_partman, рекомендуется установить его в собственную схему, как показано выше, и отозвать нежелательный доступ к этой схеме. В противном случае вам, возможно, придется добавить дополнительный шаг к процедурам обновления расширения, чтобы снова отозвать доступ PUBLIC.
F.42.4. Примеры #
Для настройки секционирования с помощью pg_partman на совершенно новой таблице или для миграции существующей обычной таблицы на секционированную, см. главу Раздел F.42.6.
Для миграции таблицы с секционированием на основе триггеров к декларативному секционированию с использованием pg_partman, см. Раздел F.42.8. Обратите внимание, что если вы планируете миграцию на pg_partman, вам сначала нужно будет мигрировать на декларативную таблицу с секционированием, прежде чем она сможет управляться pg_partman.
См. Раздел F.42.5 для получения полной информации обо всех командах и параметрах pg_partman.
F.42.5. Расширение для управления секциями PostgreSQL
(pg_partman
) #
F.42.5.1. О продукте #
PostgreSQL Partition Manager - это расширение, которое помогает упростить управление секционированием таблиц на основе времени или чисел/идентификаторов. Оно имеет множество опций, но обычно требуется только несколько из них, поэтому его гораздо проще использовать, чем может показаться на первый взгляд (и определенно проще, чем реализовывать это самостоятельно).
Начиная с версии 5.0.1, минимальная версия Tantor SE, необходимая - 14, и триггерное разделение больше не поддерживается. Все разделение выполняется с использованием встроенного декларативного секционирования. В настоящее время поддерживается только диапазонное разделение для временных и числовых интервалов. Версия 4.x pg_partman, которая все еще поддерживает триггерное разделение, больше не находится в активной разработке и будет получать только критические исправления ошибок в течение ограниченного времени. Если разделение является критической частью вашей инфраструктуры, пожалуйста, планируйте обновление в ближайшем будущем.
Автоматически создается секция по умолчанию для обработки данных, выходящих за пределы существующих дочерних границ, для всех наборов секций. Функция check_default()
обеспечивает мониторинг любых данных, вставляемых в таблицу по умолчанию, и набор функций partition_data_
* может легко разделить эти данные для вас, если это допустимые данные. Это гораздо проще, чем автоматически создавать новые дочерние таблицы по требованию и очищать потенциально сотни или тысячи ненужных секций. И также лучше, чем выдавать ошибку и терять данные!
Обратите внимание, что создание будущих дочерних таблиц основано на данных,
которые в настоящее время находятся в наборе секций и, по умолчанию, игнорирует данные в
секции по умолчанию. Рекомендуется установить значение
premake
достаточно высоким, чтобы охватить ожидаемый диапазон данных, которые будут вставлены. См. ниже для дальнейших
объяснений этих значений конфигурации.
Если у вас есть существующий набор секций, и вы хотите перенести его в pg_partman, пожалуйста, смотрите Раздел F.42.5.
F.42.5.1.1. Наследование свойств дочерней таблицы #
Для этого расширения большинство атрибутов дочерних секций получены от родительской таблицы. С декларативным разбиением, некоторые функции не могут быть унаследованы от родителя в зависимости от версии Tantor SE. Поэтому pg_partman использует таблицу-шаблон вместо этого. Следующая матрица таблицы показывает, как определенные наследования свойств управляются с помощью pg_partman. Указанное число - это версия Tantor SE. Если свойство не указано здесь, то предполагается, что оно управляется через родителя.
Функция | Наследование родителя | Наследование шаблона |
---|---|---|
несекционный столбец первичного ключа | 14+ | |
уникальный индекс для несекционного столбца | 14+ | |
несекционный столбец уникального индекса табличного пространства таблиц | 14+ | |
незарегистрированная таблица state* | 14+ | |
неуникальные индексы | 14+ | |
привилегии/владение | 14+ |
Если свойство управляется через шаблонную таблицу, оно, скорее всего, не будет автоматически применяться ко всем существующим дочерним таблицам при изменении этого свойства. Оно будет применяться к любым новым созданным дочерним таблицам, но должно быть применено вручную к любым существующим дочерним таблицам.
Привилегии и владение НЕ наследуются по умолчанию. Если
включено pg_partman, обратите внимание, что это наследование происходит только при
создании дочерней таблицы и не применяется автоматически ретроактивно при
изменении (см. reapply_privileges()
). Если вам не нужен прямой доступ к дочерним таблицам, это не должно быть
необходимо. Вы можете установить опцию inherit_privileges
, если это необходимо (см. информацию о таблице конфигурации ниже).
Если вы используете функцию IDENTITY для последовательностей, автоматическая генерация новых значений последовательности с использованием этой функции поддерживается только при вставке данных через родительскую таблицу, а не напрямую в дочерние таблицы.
Предостережение
Функция шаблонной таблицы является лишь временным решением для ускорения принятия декларативного разбиения. По мере того как эти задачи будут лучше решаться в ядре, использование шаблонной таблицы будет быстро прекращено в pg_partman. Если функция, управляемая шаблоном, будет поддерживаться в ядре в будущем, она в конечном итоге будет удалена из управления шаблонами в pg_partman, поэтому, пожалуйста, планируйте это при обновлении до основной версии, если это относится к вам.
Статус UNLOGGED управляется через шаблон pg_partman из-за несоответствия в способе обработки этого свойства при включении или отключении UNLOGGED на родительской таблице набора секций. Это свойство фактически не изменяется на родительской таблице, когда команда ALTER записывается, поэтому новые дочерние таблицы будут продолжать использовать свойство, которое существовало ранее. Таким образом, если вы хотите изменить набор секций с UNLOGGED на LOGGED для всех будущих дочерних таблиц, это не сработает. Теперь, когда свойство управляется на таблице-шаблоне, его изменение там позволит распространить изменение на вновь создаваемые дочерние таблицы. Существующие дочерние таблицы придется изменять вручную, но так было всегда. См. сообщенную ошибку на https://www.postgresql.org/message-id/flat/15954-b61523bed4b110c4%40postgresql.org
F.42.5.1.2. Часовые пояса #
Важно убедиться, что часовые пояса всех систем, на которых будут выполняться операции по обслуживанию pg_partman, согласованы, особенно при выполнении секционирования по времени. Вызовы функций pg_partman будут использовать часовой пояс, установленный клиентом на момент вызова функций. Это согласуется с общим принципом работы клиентов libpq.
В общем, настоятельно рекомендуется всегда запускать вашу систему баз данных во времени UTC. Это значительно упрощает обработку любых вопросов, связанных со временем, и особенно помогает преодолеть проблемы, которые в настоящее время невозможно решить из-за изменений летнего времени (DST). В дополнение к этому, также убедитесь, что клиент, который будет создавать наборы секций и выполнять вызовы обслуживания, также настроен на UTC. Например, попытка разделить по часам либо нарушится при изменении времени, либо пропустит создание дочерней таблицы.
F.42.5.1.3. Разделение на подсекции #
Подразделение с несколькими уровнями поддерживается, но имеет очень ограниченное применение в Tantor SE и практически не ПРЕДОСТАВЛЯЕТ ПРЕИМУЩЕСТВ В ПРОИЗВОДИТЕЛЬНОСТИ за исключением случаев с чрезвычайно большими данными в одном наборе секций (сотни терабайт, петабайты). Если вы ищете преимущества в производительности, настройте интервал секционирования перед тем, как рассматривать возможность разделения на подсекции. Его основное применение — организация данных и управление их хранением.
Вы можете делать time->time, id->id, time->id и id->time. Нет установленного ограничения на уровень
секционирования на подсекции, который вы можете сделать, но будьте разумны и помните
о производительности при управлении множеством таблиц в одном
наборе наследования. Также, если количество таблиц в одном
наборе секций становится очень большим, вам, возможно, придется настроить
параметр max_locks_per_transaction
в postgresql.conf
выше значения по умолчанию 64. В противном случае вы можете столкнуться с
проблемами общей памяти или даже вызвать сбой кластера. Если у вас
возникают проблемы с конкуренцией при вызове run_maintenance()
для
общего обслуживания всех наборов секций, вы можете
установить столбец
automatic_maintenance
в таблице
part_config
в значение false, если вы не хотите, чтобы этот общий вызов управлял
вашим набором подсекций. Но тогда вы должны вызывать
run_maintenance(parent_table)
напрямую и достаточно часто, чтобы
создавать будущие секции. Вы можете использовать процедуру run_maintenance_proc() вместо базовой
функции, чтобы уменьшить проблемы с конкуренцией, так как она
автоматически фиксирует после обслуживания каждого набора секций.
ПУБЛИКАЦИЯ/ПОДПИСКА для логической репликации НЕ поддерживается с субпартиционированием.
См. функции create_sub_parent()
и
run_maintenance()
ниже для получения
дополнительной информации.
F.42.5.1.4. Удержание #
Если вам не нужно сохранять данные в старых секциях, доступна система удержания, которая автоматически удаляет ненужные дочерние секции. По умолчанию они только открепляются/отсоединяются, а не удаляются, но это можно настроить, если это необходимо. Также доступен метод для выгрузки таблиц, если они больше не нужны в базе данных, но все еще должны быть сохранены. Чтобы установить политику удержания, введите либо интервал, либо целочисленное значение в столбец retention таблицы part_config. Для секционирования на основе времени значение интервала установит, что будут удалены секции, содержащие только данные, старше указанного значения (включая безопасную обработку случаев, когда интервал удержания не кратен размеру секции). Для секционирования по id целочисленное значение установит, что все секции с id меньше текущего максимального значения id минус значение удержания, будут удалены. Например, если текущий максимальный id равен 100, а значение удержания равно 30, все секции с id меньше 70 будут удалены. Текущее максимальное значение id в момент выполнения функции удаления всегда используется. Имейте в виду, что для наборов подсекций, когда у родительской таблицы удаляется дочерний элемент, если эта дочерняя таблица в свою очередь секционирована, удаление происходит КАСКАДНО и ВСЕ дочерние таблицы по всему дереву наследования будут удалены. Также обратите внимание, что набор секций, управляемый pg_partman, всегда должен иметь хотя бы одного наследника, поэтому удержание не удаляет последнюю дочернюю таблицу в наборе.
F.42.5.1.5. Исключение по ограничению #
Одним из больших преимуществ разбиения является функция, называемая
исключение ограничений (см.
документацию для объяснения функциональности и примеров
Раздел 5.11.5).
Проблема большинства настроек секционирования, однако, заключается в том,
что это будет использоваться только для управляющего столбца разбиения. Если
вы используете условие WHERE для любого другого столбца в наборе разбиения,
будет происходить сканирование всех дочерних таблиц, если только
на этих столбцах также нет ограничений. А предсказать, какими будут значения
столбца для предварительного создания ограничений, может быть очень
сложно или невозможно. pg_partman
имеет
функцию для применения ограничений к старым таблицам в наборе разбиения,
которые больше не редактируются (“старые” определяется как старше
значения конфигурации optimize_constraint
). Он
проверяет текущие минимальные/максимальные значения в указанных столбцах и
затем применяет ограничение к этой дочерней таблице. Это может позволить
функции исключения ограничений потенциально исключить
сканирование старых дочерних таблиц, когда другие столбцы используются в
условиях WHERE. Имейте в виду, что это ограничивает возможность редактирования
этих столбцов, но в ситуациях, где это применимо,
это может значительно повлиять на производительность запросов для очень
больших наборов разбиения. Так что если вы только вставляете новые данные,
это может быть очень полезно, но если данные регулярно вставляются/обновляются
по всему набору разбиения, это имеет ограниченное применение. Функции для легкого
воссоздания ограничений также доступны, если данные все же придется редактировать в
этих старых секциях. Обратите внимание, что ограничения, управляемые PG
Partman, НЕ ДОЛЖНЫ быть переименованы, чтобы расширение могло
правильно управлять ими для вас. Для лучшего примера того,
как это работает, пожалуйста, смотрите этот блог пост:
http://www.keithf4.com/managing-constraint-exclusion-in-table-partitioning
Добавление этих ограничений может потенциально вызвать конфликт с данными, содержащимися в этих таблицах, а также сделать обслуживание pg_partman длительным. В таблице part_config(_sub) есть столбец “constraint_valid”, чтобы установить, должны ли эти ограничения быть установлены как NOT VALID при создании. Хотя это может сделать создание ограничения(ий) почти мгновенным, исключение ограничений не может быть использовано до тех пор, пока оно не будет проверено. Вот почему ограничения по умолчанию добавляются как действительные.
NOTE: Это может не работать с субпартиционированием. Это будет работать на первом уровне партиционирования, но не гарантируется правильная работа на дальнейших наборах субпартиций в зависимости от комбинаций интервалов и значения optimize_constraint. Например: Еженедельно -> Ежедневно с ежедневным optimize_constraint, равным 7, не будет работать как ожидалось. Еженедельные ограничения будут созданы, но ежедневные субпартиционные, вероятно, не будут.
F.42.5.1.6. Соображения по интервалу времени #
Самый маленький поддерживаемый временной интервал составляет 1 секунду, а верхний предел ограничен минимальными и максимальными значениями временных меток, которые поддерживает Tantor SE Раздел 8.5.
При первом запуске create_parent()
для создания набора секций, интервалы, меньшие чем сутки, округляются вниз при определении первого создаваемой секции. Интервалы, меньшие чем 24 часа, но больше 1 минуты, округляются до ближайшего часа вниз. Интервалы, меньшие чем 1 минута, округляются до ближайшей минуты вниз. Однако, будет создано достаточно секций, чтобы поддерживать текущее реальное время. Это означает, что при запуске create_parent()
может быть создано больше предыдущих секций, чем ожидалось, и все будущие секции могут не быть созданы. Первый запуск run_maintenance()
исправит отсутствующие будущие секции. Это происходит из-за возможности поддержки пользовательских временных интервалов. Любые интервалы, большие или равные 24 часам, должны настроить все, как ожидается.
Имейте в виду, что для интервалов, равных или превышающих 100 лет, расширение будет использовать реальное начало века или тысячелетия для определения имени секции и правил ограничения. Например, 21-й век и 3-е тысячелетие начались 1 января 2001 года (а не 2000). Это также означает, что года “0” не существует.
Для еженедельных секций, обратите внимание, что по умолчанию “начало” недели будет основано на дне недели, когда вы запускаете create_parent()
. Например, если вы запустили его во вторник или пятницу, временные границы дочерних таблиц будут начинаться с этих соответствующих дней, а не с ожидаемого начала недели в понедельник или воскресенье. Самый простой способ справиться с этим — использовать функцию date_trunc()
для начала недель с понедельника, используя параметр p_start_partition
для create_parent()
. Начало с воскресенья также возможно, но сложнее и выходит за рамки данной документации.
SELECT partman.create_parent('public.time_table', 'col3', '1 week', p_start_partition := to_char(date_trunc('week',CURRENT_TIMESTAMP), 'YYYY-MM-DD HH24:MI:SS'));
F.42.5.1.7. Ограничения на длину имен #
Tantor SE имеет ограничение на длину имен объектов в 63 байта (НЕ символов). Если вы попытаетесь создать объект с более длинным именем, оно будет обрезано до этого предела. Это может вызвать очевидные проблемы с именами секций, которые зависят от конкретного суффикса. PG Partman автоматически обрабатывает это для всех имен дочерних таблиц. Он обрежет существующее имя родительской таблицы, чтобы соответствовать требуемому суффиксу. Имейте в виду, что если у вас есть таблицы с очень длинными, похожими именами, вы можете столкнуться с конфликтами имен, если они являются частью отдельных наборов секций. При секционировании на основе чисел, имейте в виду, что со временем имя таблицы будет все больше и больше обрезаться, чтобы соответствовать более длинному суффиксу секции. Поэтому, хотя расширение и пытается справиться с этим краевым случаем за вас, рекомендуется держать имена таблиц, которые будут секционированы, как можно короче.
F.42.5.1.8. Ограничения уникальности #
Наследование таблиц в Tantor SE не позволяет применять первичный ключ или
уникальный индекс/ограничение родителя ко всем дочерним
таблицам. Ограничение применяется к каждой отдельной таблице, но
не ко всему набору секций в целом. Например, это
означает, что небрежное приложение может привести к дублированию значения первичного ключа в наборе секций. В то же время, вместе с pg_partman
поставляется скрипт на python,
который может обеспечить мониторинг, чтобы помочь гарантировать, что отсутствие этой функции не приведет
к долгосрочному ущербу. См.
check_unique_constraint.py
в разделе Скрипты.
F.42.5.1.9. Ведение журнала/Мониторинг #
Расширение PG Jobmon
(https://github.com/omniti-labs/pg_jobmon) является необязательным и
позволяет проводить аудит и мониторинг обслуживания секций. Если
jobmon установлен и правильно настроен, он будет
автоматически использоваться partman без дополнительной настройки.
Jobmon также можно включать или выключать индивидуально для
каждого набора секций, используя столбец jobmon
в таблице
part_config
или с опцией create_parent()
во время начальной настройки. Обратите внимание, что если вы попытаетесь секционировать
таблицы pg_jobmon
, вы
ДОЛЖНЫ установить опцию jobmon
в create_parent()
в значение false, иначе это
приведет к постоянному ожиданию блокировки, так как
pg_jobmon
будет пытаться записать в
таблицу, которую он пытается секционировать. По умолчанию любая функция, которая
не удается выполнить успешно 3 раза подряд, вызовет
оповещение jobmon. Именно поэтому значение pre-make по умолчанию установлено на 4, чтобы оповещение было вызвано вовремя для
вмешательства без дополнительной настройки jobmon.
Конечно, вы можете настроить jobmon для оповещения до (или
позже) 3 неудач, если это необходимо. Если вы запускаете partman в
производственной среде, настоятельно рекомендуется установить
jobmon и настроить какое-либо стороннее мониторинг
с ним для оповещения при сбоях секционирования (Nagios,
Circonus и т.д.).
F.42.5.2. Фоновые рабочие процессы #
pg_partman
’s BGW в основном представляет собой
планировщик, который запускает функцию run_maintenance()
для вас, чтобы вам не нужно было использовать внешний
планировщик (cron и т.д.). В настоящее время он не делает ничего
отличного от вызова run_maintenance()
напрямую, но это может измениться в будущем. См. главу Раздел F.42.2
для получения инструкций по установке. Если вам нужно вызвать
run_maintenance()
напрямую для каких-либо конкретных
наборов секций, вам все равно придется делать это вручную с использованием
внешнего планировщика. Это поддерживает только те наборы секций, у которых
automatic_maintenance
в
**part_config**
установлено на true. Сообщения LOG
выводятся в обычный файл журнала Tantor SE, чтобы указать, когда
BGW запускается. Дополнительные сообщения журнала доступны, если
log_min_messages установлено на “DEBUG1”.
Предостережение
В ваших библиотеках shared_preload_libraries
должна находиться pg_partman_bgw
(требуется перезагрузка).
Следующие параметры конфигурации доступны для добавления в файл postgresql.conf для управления процессом BGW:
pg_partman_bgw.dbname
Требуется. База данных(ы), на которой будет выполняться функция
run_maintenance()
. Если их несколько, используйте список, разделенный запятыми. Если не задано, BGW ничего не будет делать.
pg_partman_bgw.interval
Количество секунд между вызовами функции
run_maintenance()
. По умолчанию - 3600 (1 час).См. дополнительную документацию ниже о рекомендуемых значениях для этого на основе типов секций и используемых интервалов.
pg_partman_bgw.role
Роль, под которой будет выполняться
run_maintenance()
. По умолчанию - “postgres”. Разрешено только одно имя роли.
pg_partman_bgw.analyze
Та же цель, что и у аргумента p_analyze для
run_maintenance()
. См. ниже для более подробной информации. Установите значение ‘on’ для TRUE. Установите значение ‘off’ для FALSE (По умолчанию ‘off’).
pg_partman_bgw.jobmon
Та же цель, что и у аргумента p_jobmon в
run_maintenance()
. См. ниже для более подробной информации. Установите значение ‘on’ для TRUE. Установите значение ‘off’ для FALSE. По умолчанию установлено значение ‘on’.
Если по какой-либо причине основной процесс фонового рабочего процесса завершается аварийно, он будет пытаться перезапуститься каждые 10 минут. Проверьте журналы postgres на наличие проблем, если фоновый рабочий процесс не запускается.
F.42.5.3. Расширяемые объекты #
Требование суперпользователя для использования pg_partman является полностью необязательным. Для работы без суперпользователя, роль(и), которые выполняют функции и обслуживание pg_partman, должны владеть всеми наборами секций, которые они управляют, и иметь разрешения на создание объектов в любой схеме, которая будет содержать наборы секций, которыми он управляет. Для удобства использования и управления привилегиями рекомендуется создать роль, посвященную управлению секциями. Пожалуйста, смотрите главу Раздел F.42.2 для инструкций по настройке ролей и привилегий.
Как примечание для тех, кто не знал, вы можете называть аргументы
в вызовах функций, чтобы упростить их вызов и избежать
путаницы, когда есть много возможных аргументов. Если значение имеет
указанный по умолчанию, не требуется передавать значение для этого
аргумента. Например:
SELECT create_parent('schema.table', 'col1', '1 day', p_start_partition := '2023-03-20');
F.42.5.3.1. Функции создания #
create_parent( p_parent_table text , p_control text , p_interval text , p_type text DEFAULT 'range' , p_epoch text DEFAULT 'none' , p_premake int DEFAULT 4 , p_start_partition text DEFAULT NULL , p_default_table boolean DEFAULT true , p_automatic_maintenance text DEFAULT 'on' , p_constraint_cols text[] DEFAULT NULL , p_template_table text DEFAULT NULL , p_jobmon boolean DEFAULT true , p_date_trunc_interval text DEFAULT NULL ) RETURNS boolean
Основная функция для создания набора секций с одной родительской таблицей и унаследованными дочерними таблицами. Родительская таблица должна уже существовать и быть объявлена как секционированная перед вызовом этой функции. Все параметры, переданные этой функции, должны соответствовать этому определению. Пожалуйста, примените все значения по умолчанию, индексы, ограничения, привилегии и владение к родительской таблице, чтобы они распространялись на дочерние таблицы. См. примечания выше о обработке уникальных индексов и других свойств таблицы.
Во время выполнения этой функции на родительскую таблицу накладывается блокировка ACCESS EXCLUSIVE. во время выполнения этой функции. При выполнении этой функции данные не перемещаются при выполнении этой функции данные не перемещаются, поэтому блокировка должна быть кратковременной.
Раздел по умолчанию и шаблонная таблица создаются по умолчанию, если не указано иное
p_parent_table
- существующая родительская таблица. ДОЛЖНА быть указана с учетом схемы, даже если находится в публичной схемеp_control
- столбец, на основе которого будет выполняться партиционирование. Должен быть основан на времени или целочисленный столбецp_interval
- временной или целочисленный диапазон интервала для каждой партиции. Независимо от типа партиционирования, значение должно быть указано в виде текста.interval
- Любое допустимое значение для типа данных interval. Не приводите значение параметра к другому типу, просто оставьте его как текст.integer
- Для секций на основе ID, диапазон значений целого числа ID, который должен быть установлен для каждой секции. Введите это как целое число в текстовом формате (‘100’, а не 100). В настоящее время должно быть больше или равно 2.
p_type
- тип разбиения, которое будет выполнено. В настоящее время поддерживается только range.p_epoch
- указываетpg_partman
, что управляющий столбец является целочисленным типом, но фактически представляет значение времени эпохи. Допустимые значения для этого параметра:seconds
,milliseconds
,nanoseconds
иnone
. Значение по умолчанию -none
. Все имена таблиц будут основаны на времени. В дополнение к обычному индексу на управляющем столбце, обязательно создайте функциональный, основанный на времени индекс на управляющем столбце (to_timestamp(controlcolumn)), чтобы это работало эффективно.p_premake
- это сколько дополнительных секций всегда должно быть впереди текущего раздела. Значение по умолчанию - 4. Это будет поддерживать минимум 5 созданных секций, включая текущий. Например, если сегодня 6 сентября, иpremake
установлен на 4 для ежедневного раздела, то секции будут созданы для 6-го, а также 7-го, 8-го, 9-го и 10-го. Обратите внимание, что некоторые интервалы могут иногда вызывать создание дополнительного раздела или пропуск одного из-за високосных лет, различной длины месяцев и т.д. Обычно это не причиняет вреда и должно самоисправляться (см. раздел О, касающийся часовых поясов и не-UTC). Если разделение когда-либо отстанет от значенияpremake
, нормальная работаrun_maintenance()
и вставка данных должны автоматически наверстать упущенное.p_start_partition
- позволяет указать первый раздел набора вместо его автоматического определения. Должно быть допустимое значение временной метки (для основанных на времени) или положительное целое число (для основанных на идентификаторах). Однако имейте в виду, что фактический тип данных параметра - текст. Для основанного на времени разбиения будут созданы все секции, начиная с указанной временной метки и до CURRENT_TIMESTAMP (плюсpremake
). Для разбиения на основе идентификаторов будет создан только раздел, начинающийся с указанного значения (плюсpremake
). Обратите внимание, что для субразбиения это применяется только во время начальной настройки и не во время текущего обслуживания.p_default_table
- логический флаг для определения, создается ли таблица по умолчанию. По умолчанию true.p_automatic_maintenance
- параметр для установки автоматического управления обслуживанием, когдаrun_maintenance()
вызывается без параметра таблицы или фоновым рабочим процессом. Текущие допустимые значения:on
иoff
. По умолчаниюon
. Когда установлено значение off,run_maintenance()
все еще может быть вызвана для отдельного набора секций, передав его в качестве параметра функции. См. run_maintenance в разделе Функции обслуживания ниже для получения дополнительной информации.p_constraint_cols
- необязательный массив параметров для установки столбцов, которым будут установлены дополнительные ограничения. См. раздел Описание выше для получения дополнительной информации о том, как это работает, и функцию apply_constraints() для понимания, как это используется.p_template_table
- Если вы не передадите значение здесь, шаблонная таблица будет автоматически создана для вас в той же схеме, в которую был установлен pg_partman. Если вы предварительно создадите шаблонную таблицу и передадите ее имя здесь, то начальные дочерние таблицы немедленно получат эти свойства, обсуждаемые в разделе About.p_jobmon
- позволяетp_jobmon
использовать расширениеpg_jobmon
для контроля правильности работы секционирования. По умолчанию TRUE.p_date_trunc_interval
- По умолчанию временное секционирование pg_partman будет усекать начальные значения дочерней таблицы, чтобы они соответствовали началу типичных границ (полночь для ежедневного, 1-й день для ежемесячного, 1 января для ежегодного и т. д.). Если требуется пользовательский временной интервал, не совпадающий с этими границами, может потребоваться использование этой опции для обеспечения ожидаемых границ дочерней таблицы (особенно если вы также устанавливаете p_start_partition). Допустимые значения, разрешенные для этого параметра, - это значения интервала, принимаемые встроенной функцией date_trunc() (день, неделя, месяц и т. д.). Например, если вы установите интервал в 9 недель, по умолчанию pg_partman будет усекать таблицы по месяцам (поскольку интервал больше одного месяца, но меньше 1 года) и неожиданно начинать с первого числа месяца в некоторых случаях. Установите это значение на неделю, чтобы начальные значения дочерней таблицы правильно усекались еженедельно, чтобы соответствовать 9-недельному интервалу. Если вы используете пользовательский временной интервал, пожалуйста, экспериментируйте с этой опцией, чтобы получить ожидаемый набор дочерних таблиц, который вам нужен, или используйте более типичный интервал секционирования, чтобы упростить управление секциями.
create_sub_parent( p_top_parent text , p_declarative_check text DEFAULT NULL , p_control text , p_interval text , p_type text DEFAULT 'range' , p_epoch text DEFAULT 'none' , p_premake int DEFAULT 4 , p_start_partition text DEFAULT NULL , p_default_table boolean DEFAULT true , p_constraint_cols text[] DEFAULT NULL , p_jobmon boolean DEFAULT true , p_date_trunc_interval text DEFAULT NULL ) RETURNS boolean
Создайте набор подсекций уже существующего секционированного набора. См. важные примечания о разделении на подсекции в разделе О.
p_top_parent
- Этот параметр является родительской таблицей уже существующего набора секций. Он указываетpg_partman
превратить все дочерние таблицы данного набора секций в их собственные родительские таблицы собственных наборов секций, используя остальные параметры для этой функции.p_declarative_check
- Превращение существующего набора секций в набор с подсекциями является разрушающим процессом. Таблица должна быть объявлена секционированной при создании и не может быть изменена позже. Поэтому существующие дочерние таблицы должны быть удалены и воссозданы как родительские таблицы с секциями. Этот флаг здесь для того, чтобы гарантировать, что эта функция не будет запущена без предварительного согласия на то, что все данные в наборе секций будут уничтожены в процессе создания. Он должен быть установлен в “yes”, чтобы продолжить с разделением на подсекции.Все остальные параметры этой функции имеют точно такую же цель, как и у
create_parent()
, но вместо этого они используются для указанияpg_partman
, как каждая дочерняя таблица будет сама разделена.Например, если у вас уже есть набор секций по годам, и нужно разделить каждый из секций по годам по дням, вы должны использовать эту функцию.
Рекомендуется использовать короткие имена таблиц для наборов подсекций, если вы планируете полагаться на имена таблиц для организации. Суффикс, добавляемый в конец имени таблицы, всегда гарантированно присутствует для любого типа раздела, активного для этого набора. Более длинные имена таблиц могут привести к усечению оригинальных имен родительских таблиц и, возможно, к обрезанию суффикса верхнего уровня секционирования. Это невозможно контролировать и гарантирует, что суффикс самого нижнего уровня секционирования сохранится.
Обратите внимание, что для первого уровня разделения на подсекции аргумент
p_parent_table
, который вы изначально передали вcreate_parent()
, будет точно таким же значением, которое вы передаете вcreate_sub_parent()
. Если вам нужно дальнейшее разделение на подсекции, вы должны начать передаватьcreate_sub_parent()
другое значение (дочерние таблицы набора секций верхнего уровня).Шаблонная таблица, которая уже установлена для данного p_top_parent, будет использоваться автоматически.
partition_data_time( p_parent_table text , p_batch_count int DEFAULT 1 , p_batch_interval interval DEFAULT NULL , p_lock_wait numeric DEFAULT 0 , p_order text DEFAULT 'ASC' , p_analyze boolean DEFAULT true , p_source_table text DEFAULT NULL , p_ignored_columns text[] DEFAULT NULL ) RETURNS bigint
Эта функция используется для секционирования данных, которые могли существовать до настройки родительской таблицы как набора временных секций. Она также исправляет данные, которые вставляются в таблицу по умолчанию.
Если требуемая секция не существует, он будет автоматически создан. Если требуемая секция уже существует, данные будут перемещены туда.
Если вы пытаетесь автоматически разделить большой объем данных, рекомендуется использовать процедуру
partition_data_proc
для фиксации данных небольшими партиями. Это значительно уменьшит проблемы, вызванные длительными транзакциями и конфликтами данных.Для наборов подсекций вы должны начинать секционирование данных с самого высокого уровня и двигаться вниз по каждому уровню. Это означает, что вы должны сначала запустить эту функцию перед запуском create_sub_parent() для создания дополнительных уровней секционирования. Затем продолжайте запускать эту функцию снова для каждой новой родительской подсекции после их создания. См. главу Раздел F.42.6 для полного примера.
Предостережение
Будьте ОЧЕНЬ осторожны с наборами подсекций и использованием этой функции, так как разделение на подсекции может быть разрушительной операцией. См. create_sub_parent().
p_parent_table
- существующая родительская таблица. ДОЛЖНА быть указана с учетом схемы, даже если находится в публичной схеме.p_batch_count
- необязательный аргумент, сколько раз выполнитьbatch_interval
в одном вызове этой функции. Значение по умолчанию - 1. В настоящее время устанавливает, сколько дочерних таблиц будет обработано за один запуск, но когда p_batch_interval снова заработает, будет явно указывать, сколько пакетов запускать.p_batch_interval
- необязательный аргумент, задает интервал данных, которые будут перемещаться в каждой партии. По умолчанию используется настроенный интервал секционирования, если не указан или если вы указываете интервал, превышающий интервал секционирования.Предостережение
Это не может быть установлено меньше, чем интервал секционирования, если данные перемещаются из таблицы по умолчанию. Ведутся работы, чтобы это стало возможным, но с некоторыми ограничениями. Если вы перемещаете данные из исходной таблицы, которая не является таблицей по умолчанию набора секций, вы можете установить этот интервал меньше, чем интервал секционирования, чтобы избежать перемещения большого объема данных в долго выполняющихся транзакциях.
p_lock_wait
- необязательный аргумент, устанавливает, как долго в секундах ждать разблокировки строки перед истечением времени ожидания. По умолчанию ожидание продолжается бесконечно.p_order
- необязательный аргумент, по умолчанию данные мигрируются в порядке возрастания (ASC). Позволяет изменить на порядок убывания (DESC).p_analyze
- необязательный аргумент, по умолчанию при создании новой дочерней таблицы выполняется анализ родительской таблицы набора секций для обеспечения исключения ограничений. Этот анализ можно пропустить, установив значение false, что поможет увеличить скорость перемещения больших объемов данных. Если это установлено в false, настоятельно рекомендуется вручную выполнить анализ набора секций после завершения, чтобы обновить статистику.p_source_table
- Этот параметр можно использовать, когда необходимо переместить данные в секционированную таблицу. Передайте имя таблицы с указанием схемы в этот параметр, и любые данные в этой таблице будут ПЕРЕМЕЩЕНЫ в набор секций, указанный p_parent_table, создавая любые дочерние таблицы по мере необходимости.p_ignored_columns
- Этот параметр позволяет исключать определенные столбцы при перемещении данных из таблицы по умолчанию/источника в целевую дочернюю таблицу(ы). Это обычно требуется только при использовании столбцов с значением GENERATED ALWAYS, так как прямая вставка значения приведет к ошибке при перемещении данных. Значение представляет собой текстовый массив имен столбцов.Возвращает количество строк, которые были перемещены из родительской таблицы в секции. Возвращает ноль, когда исходная таблица пуста и разбиение завершено.
partition_data_id(p_parent_table text , p_batch_count int DEFAULT 1 , p_batch_interval bigint DEFAULT NULL , p_lock_wait numeric DEFAULT 0 , p_order text DEFAULT 'ASC' , p_analyze boolean DEFAULT true , p_source_table text DEFAULT NULL , p_ignored_columns text[] DEFAULT NULL ) RETURNS bigint
Эта функция используется для секционирования данных, которые могли существовать до настройки родительской таблицы как набора секций на основе чисел. Она также исправляет данные, которые вставляются по умолчанию.
Если требуемая секция не существует, он будет автоматически создан. Если требуемая секция уже существует, данные будут перемещены туда.
Если вы пытаетесь автоматически разделить большой объем данных, рекомендуется использовать процедуру
partition_data_proc
для фиксации данных небольшими партиями. Это значительно уменьшит проблемы, вызванные длительными транзакциями и конфликтами данных.Для наборов подсекций вы должны начать секционирование данных с самого высокого уровня и двигаться вниз по каждому уровню. Это означает, что вы должны сначала запустить эту функцию перед запуском create_sub_parent() для создания дополнительных уровней секционирования. Затем продолжайте запускать эту функцию снова для каждого нового суб-родителя после их создания. См. главу Раздел F.42.6 для полного примера.
Предостережение
Будьте ОЧЕНЬ осторожны с наборами подсекций и использованием этой функции, так как разделение на подсекции может быть разрушительной операцией. См. create_sub_parent().
p_parent_table
- существующая родительская таблица. ДОЛЖНА быть указана с учетом схемы, даже если находится в публичной схеме.p_batch_count
- необязательный аргумент, сколько раз выполнитьbatch_interval
в одном вызове этой функции. Значение по умолчанию - 1. Это определяет, сколько дочерних таблиц будет обработано за один запуск.p_batch_interval
- необязательный аргумент, задает интервал данных, которые будут перемещаться в каждой партии. По умолчанию используется настроенный интервал секционирования, если не указан или если вы указываете интервал, превышающий интервал секционирования.Предостережение
Это не может быть установлено меньше, чем интервал секционирования, если данные перемещаются из таблицы по умолчанию. Ведутся работы, чтобы это стало возможным, но с некоторыми ограничениями. Если вы перемещаете данные из исходной таблицы, которая не является таблицей по умолчанию набора секций, вы можете установить этот интервал меньше, чем интервал секционирования, чтобы избежать перемещения большого объема данных в долго выполняющихся транзакциях.
p_lock_wait
- необязательный аргумент, устанавливает, как долго в секундах ждать разблокировки строки перед истечением времени ожидания. По умолчанию ожидание продолжается бесконечно.p_order
- необязательный аргумент, по умолчанию данные перемещаются из родительской таблицы в порядке возрастания (ASC). Позволяет изменить порядок на убывающий (DESC).p_analyze
- необязательный аргумент, по умолчанию при создании новой дочерней таблицы выполняется анализ родительской таблицы набора секций для обеспечения исключения ограничений. Этот анализ можно пропустить, установив значение false, что поможет увеличить скорость перемещения больших объемов данных. Если это установлено в false, настоятельно рекомендуется вручную выполнить анализ набора секций после завершения, чтобы обновить статистику.p_source_table
- Этот параметр можно использовать, когда необходимо переместить данные в секционированную таблицу. Передайте имя таблицы с указанием схемы в этот параметр, и любые данные в этой таблице будут ПЕРЕМЕЩЕНЫ в набор секций, указанный p_parent_table, создавая любые дочерние таблицы по мере необходимости.p_ignored_columns
- Этот параметр позволяет исключать определенные столбцы при перемещении данных из таблицы по умолчанию/источника в целевую дочернюю таблицу(ы). Это обычно требуется только при использовании столбцов с значением GENERATED ALWAYS, так как прямая вставка значения приведет к ошибке при перемещении данных. Значение представляет собой текстовый массив имен столбцов.Возвращает количество строк, которые были перемещены из родительской таблицы в секции. Возвращает ноль, когда исходная таблица пуста и разбиение завершено.
partition_data_proc ( p_parent_table text , p_loop_count int DEFAULT NULL , p_interval text DEFAULT NULL , p_lock_wait int DEFAULT 0 , p_lock_wait_tries int DEFAULT 10 , p_wait int DEFAULT 1, p_order text DEFAULT 'ASC' , p_order text DEFAULT 'ASC', , p_source_table text DEFAULT NULL , p_ignored_columns text[] DEFAULT NULL , p_quiet boolean DEFAULT false )
Процедура, которая может разделять данные на отдельные партии коммитов, чтобы избежать длительных транзакций и проблем с конкуренцией данных.
Вызывает либо partition_data_time(), либо partition_data_id() в цикле в зависимости от типа секционирования.
p_parent_table
- Родительская таблица уже созданного набора секций.p_loop_count
- Сколько раз повторить значение, заданное для p_interval. Если p_interval не установлен, будет использоваться интервал секционирования по умолчанию и будет создано не более этого количества секций. Процедура фиксирует изменения в конце каждого цикла (НЕ передается как p_batch_count в функцию секционирования). Если не установлено, все данные в родительской/исходной таблице будут разделены за один запуск процедуры.p_interval
- Параметр, который передается в функцию разбиения в качестве аргумента p_batch_interval. См. основные функции для дальнейших объяснений.p_lock_wait
- Параметр, передаваемый непосредственно в основную функцию partition_data_*(). Количество секунд ожидания строк, которые могут быть заблокированы другой транзакцией. По умолчанию ожидать вечно (0).p_lock_wait_tries
- Параметр, устанавливающий, сколько раз процедура будет пытаться ожидать заданное время для p_lock_wait. По умолчанию 10 попыток.p_wait
- Заставляет процедуру ожидать заданное количество секунд между фиксацией (партиями), чтобы снизить нагрузку на запись.p_order
- То же самое, что и параметр p_order в вызываемой функции разбиенияp_source_table
- То же самое, что и опция p_source_table в вызываемой функции секционирования.p_ignored_columns
- Эта опция позволяет фильтровать определенные столбцы при перемещении данных из таблицы по умолчанию/родительской в соответствующую дочернюю таблицу(ы). Это обычно требуется только при использовании столбцов со значением GENERATED ALWAYS, поскольку прямая вставка значения приведет к ошибке при перемещении данных. Значение представляет собой массив текстовых имен столбцов.p_quiet
- Процедуры не могут возвращать значения, поэтому по умолчанию они выводят УВЕДОМЛЕНИЯ, чтобы показать прогресс. Установите эту опцию, чтобы подавить эти уведомления.
create_partition_time( p_parent_table text , p_partition_times timestamptz[] , p_start_partition text DEFAULT NULL ) RETURNS boolean
Эта функция используется для создания дочерних секций для заданной родительской таблицы.
Обычно эта функция никогда не вызывается вручную, так как создание секций управляется run_maintenance(). Но если вам нужно принудительно создать определенные дочерние таблицы вне нормального обслуживания, эта функция упрощает эту задачу.
p_parent_table
- родительская таблица для создания новой дочерней таблицы(таблиц).p_partition_times
- Массив значений timestamptz для создания дочерних таблиц. Если дочерняя таблица не существует, она будет создана. Если она уже существует, будет использована существующая таблица, и функция завершится корректно. Учтите, что указанное значение будет использовано как нижняя граница для дочерней таблицы и также повлияет на имя, присвоенное дочерней таблице. Поэтому убедитесь, что указанное значение временной метки согласуется с другими дочерними таблицами, иначе вы можете столкнуться с разрывом в покрытии значений.p_start_partition
- При разделении на подсекции можно передавать начальное значение секции дочерним таблицам подсекции.Возвращает TRUE, если для заданных значений timestamptz были созданы дочерние таблицы. Возвращает false, если дочерние таблицы не были созданы.
create_partition_id( p_parent_table text , p_partition_ids bigint[] , p_start_partition text DEFAULT NULL ) RETURNS boolean
Эта функция используется для создания дочерних секций для заданной родительской таблицы.
Обычно эта функция никогда не вызывается вручную, так как создание секций управляется run_maintenance(). Но если вам нужно принудительно создать определенные дочерние таблицы вне нормального обслуживания, эта функция может упростить эту задачу.
p_parent_table
- родительская таблица для создания новой дочерней таблицы(таблиц).p_partition_ids
- Массив целочисленных значений для создания дочерних таблиц. Если дочерняя таблица не существует, она будет создана. Если она уже существует, будет использована существующая таблица, и функция завершится корректно. Учтите, что указанное значение будет использоваться как нижняя граница для дочерней таблицы и также повлияет на имя, присвоенное дочерней таблице. Поэтому убедитесь, что указанное целочисленное значение согласуется с другими дочерними таблицами, иначе вы можете столкнуться с разрывом в покрытии значений.p_start_partition
- При разделении на подсекции можно передавать начальное значение секции дочерним таблицам подсекции.Возвращает TRUE, если для заданных значений integer были созданы дочерние таблицы. Возвращает false, если дочерние таблицы не были созданы.
F.42.5.3.2. Функции обслуживания #
run_maintenance( p_parent_table text DEFAULT NULL , p_analyze boolean DEFAULT false , p_jobmon boolean DEFAULT true ) RETURNS void
Запустите эту функцию как запланированное задание (cron и т. д.), чтобы автоматически создавать дочерние таблицы для наборов секций, настроенных для их использования.
Вы также можете использовать включенный фоновый рабочий процесс (BGW), чтобы это выполнялось автоматически самим Tantor SE. Обратите внимание, что параметр
p_parent_table
недоступен при использовании этого метода, поэтому, если вам нужно запустить его для конкретного набора секций, вы должны сделать это вручную или запланировать внешне. Другие параметры имеют значения в postgresql.conf, которые можно установить. См. раздел BGW ранее в этой документации.Эта функция также поддерживает систему сохранения секций для любых наборов секций, у которых она включена (см. Описание и таблицу part_config ниже).
Каждый запуск проверяет все таблицы, перечисленные в таблице part_config с automatic_maintenance установленным в true и либо создает для них новые секции, либо запускает их политику удержания.
По умолчанию все наборы секций имеют значение automatic_maintenance, установленное на true.
Новые секции создаются только в том случае, если количество дочерних таблиц перед текущей меньше значения premake, поэтому вы можете запускать эту функцию чаще, чем требуется, не боясь бесполезного создания дополнительных секций.
p_parent_table
- необязательный параметр, который, если передан, вызовет запускrun_maintenance()
только для этой указанной таблицы, независимо от значения automatic_maintenance. Таблицы с высокой скоростью транзакций могут вызывать конфликты при выполнении обслуживания для множества таблиц одновременно, поэтому это позволяет более точно контролировать время выполнения обслуживания секций для конкретных таблиц. Обратите внимание, что это также приведет к запуску системы сохранения только для данной таблицы.p_analyze
- По умолчанию анализ не выполняется после создания новых дочерних таблиц. Для больших наборов секций анализ может занять некоторое время, и еслиrun_maintenance()
управляет несколькими секциями за один запуск, это может вызвать конкуренцию, пока анализ не завершится. Однако для полной эффективности исключения ограничений или обрезки секций анализ должен быть выполнен на уровне родительской таблицы в какой-то момент. Установите это значение в true, чтобы выполнить анализ на любых наборах секций, в которых создана хотя бы одна новая дочерняя таблица. Если в наборе секций не создаются новые дочерние таблицы, анализ не будет выполнен, даже если это значение установлено в true.p_jobmon
- необязательный параметр для контроля использованияrun_maintenance()
расширенияpg_jobmon
для регистрации своих действий. Использованиеpg_jobmon
для обслуживания конкретной таблицы контролируется настройкой в таблице part_config и эта настройка не будет влиять на это. По умолчанию установлено значение true, если не указано иное.
run_maintenance_proc( p_wait int DEFAULT 0 , p_analyze boolean DEFAULT NULL , p_jobmon boolean DEFAULT true )
Эта процедура может быть вызвана вместо функции
run_maintenance()
для того, чтобы заставить Tantor SE делать коммит после завершения обслуживания каждого набора секций. Это значительно снижает проблемы с конкуренцией при долгих транзакциях, когда есть много наборов секций для обслуживания.Примечание
BGW еще не использует эту процедуру и все еще использует стандартную функцию run_maintenance().
p_wait
- Сколько секунд ждать между запусками обслуживания каждого набора секций. По умолчанию 0.p_analyze
- См. параметр p_analyze в функции run_maintenance.
check_default( p_exact_count boolean DEFAULT true )
Запустите эту функцию, чтобы отслеживать, вставляются ли строки в таблицы по умолчанию наборов секций, которыми управляет
pg_partman
.Возвращает строку для каждой родительской/таблицы по умолчанию вместе с количеством строк, которые она содержит. Возвращает ноль строк, если ничего не найдено.
partition_data_time()
иpartition_data_id()
можно использовать для перемещения данных из этих родительских/таблиц по умолчанию в соответствующие дочерние таблицы.p_exact_count позволит функции вернуть точное количество строк в каждом родительском элементе, если таковые найдены. Это значение по умолчанию, если параметр не указан. Если вам не важно точное количество, вы можете установить его в false, и функция вернет результат, если найдена хотя бы одна строка в любом родительском элементе. Это может значительно ускорить проверку, если в родительском элементе содержится большое количество данных или если управляется много секций.
show_partitions ( p_parent_table text , p_order text DEFAULT 'ASC' , p_include_default boolean DEFAULT false ) RETURNS TABLE ( partition_schemaname text , partition_tablename text )
Перечислите все дочерние таблицы заданного набора секций, управляемых pg_partman. Каждая дочерняя таблица возвращается в виде отдельной строки.
Таблицы возвращаются в порядке, который логически имеет смысл для интервала секционирования, а не по локальной сортировке их имен.
Секция по умолчанию также может быть возвращен в этом наборе результатов, если
p_include_default
установлено в true. По умолчанию это значение false, так как это гораздо более распространено во внутреннем коде.p_order
- необязательный параметр для установки порядка возврата дочерних таблиц. По умолчанию используется порядок возрастания (ASCending). Установите значение ‘DESC’ для возврата в порядке убывания. Если используется значение по умолчанию, оно всегда указывается первым.
show_partition_name( p_parent_table text , p_value text , OUT partition_schema text , OUT partition_table text , OUT suffix_timestamp timestamptz , OUT suffix_id bigint , OUT table_exists boolean ) RETURNS record
Учитывая таблицу-родителя с указанной схемой, управляемую pg_partman (p_parent_table), и соответствующее значение (время или id, но в текстовой форме для p_value), вернуть имя дочерней секции, в котором это значение будет существовать.
Если используется секционирование времени по эпохе, укажите значение временной метки, а НЕ целочисленное значение эпохи (используйте функцию to_timestamp() для преобразования значения эпохи).
Возвращает имя дочерней таблицы, независимо от того, существует она или нет
Также возвращает необработанное значение (suffix_timestamp или suffix_id) для суффикса секции для указанной дочерней таблицы.
Также возвращает логическое значение (table_exists), чтобы указать, существует ли на самом деле этот дочерний стол.
show_partition_info(p_child_table text , p_partition_interval text DEFAULT NULL , p_parent_table text DEFAULT NULL , OUT child_start_time timestamptz , OUT child_end_time timestamptz , OUT child_start_id bigint , OUT child_end_id bigint , OUT suffix text ) RETURNS record
Учитывая имя дочерней таблицы с указанием схемы (p_child_table), вернуть соответствующие граничные значения этой дочерней таблицы, а также суффикс, добавленный к имени дочерней таблицы.
Работает только для существующих дочерних таблиц, так как граничные значения рассчитываются на основе системных каталогов этой таблицы.
p_partition_interval
- Если указано, возвращает граничные результаты на основе этого интервала. Если не указано, функция ищет интервал, сохраненный в таблице part_config для этого набора секций.p_parent_table
- Необязательный аргумент, который можно указать, когда parent_table известна, чтобы избежать поиска в каталоге для родительской таблицы, связанной с p_child_table. Небольшая настройка производительности, так как эта функция часто используется внутри.OUT child_start_times и child_end_time
- Функция возвращает значения для этих выходных параметров, если набор секций основан на времени. В противном случае выводит NULL. Обратите внимание, что начальное значение ВКЛЮЧИТЕЛЬНО, а конечное значение ИСКЛЮЧАЕТ указанные границы дочерней таблицы, точно так, как они определены в базе данных.OUT child_start_id и child_end_id
- Функция возвращает значения для этих выходных параметров, если набор секций основан на целых числах. В противном случае выводит NULL. Обратите внимание, что начальное значение ВКЛЮЧЕНО, а конечное значение ИСКЛЮЧЕНО из границ данной дочерней таблицы, точно так, как они определены в базе данных.OUT suffix
- Выводит текстовую часть, добавленную к дочерней таблице, которая идентифицирует ее содержимое, за исключением "_p" (например, “20230324” ИЛИ “920000”). Полезно для создания собственных суффиксов для партицирования, аналогично тому, как это делает pg_partman.
dump_partitioned_table_definition( p_parent_table text, p_ignore_template_table boolean DEFAULT false ) RETURNS text
Функция для возврата необходимых команд для воссоздания набора секций в pg_partman для заданной родительской таблицы (p_parent_table).
Возвращает как вызов
create_parent()
, так и оператор UPDATE для установки дополнительных параметров, хранящихся в part_config.NOTE: В настоящее время это работает только с одноуровневыми наборами секций. Ищем вкладчиков для добавления поддержки наборов подсекций
p_ignore_template
- Таблица шаблонов должна быть создана до того, как SQL, сгенерированный этой функцией, будет работать правильно. Если вы вообще не изменяли таблицу шаблонов, то можно безопасно передать здесь TRUE, чтобы сгенерированный SQL указал partman создать новую таблицу шаблонов. Но для безопасности предпочтительнее использовать pg_dump для дампа таблиц шаблонов и их восстановления перед использованием сгенерированного SQL, чтобы сохранить любые переопределения шаблонов.
partition_gap_fill( p_parent_table text ) RETURNS integer
Функция для заполнения пробелов, которые могут существовать в ряду дочерних таблиц для данной родительской таблицы (p_parent_table). дочерних таблиц для заданной родительской таблицы (p_parent_table).
Начинает с текущей минимальной дочерней таблицы и заполняет любые пробелы, встреченные на основе интервала секционирования, до текущей максимальной дочерней таблицы.
Возвращает количество созданных дочерних таблиц. Возвращает 0, если ни одна не создана.
apply_constraints( p_parent_table text , p_child_table text DEFAULT NULL , p_analyze boolean DEFAULT FALSE , p_job_id bigint DEFAULT NULL ) RETURNS void
Примените ограничения к дочерним таблицам в заданном наборе секций для настроенных столбцов (имена ограничений начинаются с префикса “partmanconstr_”).
Обратите внимание, что для поддержания пользовательских ограничений это не требует вызова вручную. Создание новых секций автоматически управляет добавлением ограничений к старым дочерним таблицам.
Столбцы, которым должны быть назначены ограничения, устанавливаются в таблице part_config в массиве constraint_cols или при создании с параметром для
create_parent()
.Если ограничения
pg_partman
уже существуют на дочерней таблице, функция пропустит их и не создаст дубликаты.Если столбец (-ы), указанные, содержат только значения NULL, то ограничение не будет установлено.
Если задан параметр дочерней таблицы, то только для этой дочерней таблицы будут применены ограничения.
Если параметр дочерней таблицы НЕ указан, ограничения накладываются на последнюю дочернюю таблицу, которая старше значения
optimize_constraint
. Например, если значение optimize_constraint равно 30, то ограничения будут наложены на дочернюю таблицу, которая находится на 31 позиции от текущей секции (при условии, что предварительное создание секции было выполнено своевременно).Если вам нужно применить ограничения ко всем старым дочерним таблицам, используйте процедуру
reapply_constraints_proc
. Этот метод имеет опции, которые упрощают применение ограничений с минимальным воздействием на производительность.Параметр p_job_id является необязательным. Он предназначен для внутреннего использования и позволяет объединить ведение журнала заданий в исходное задание, которое вызвало эту функцию, если это применимо.
drop_constraints( p_parent_table text , p_child_table text , p_debug boolean DEFAULT false ) RETURNS void
Удалите ограничения, созданные
pg_partman
для столбцов, настроенных в part_config. Это упрощает очистку ограничений, если требуется редактировать старые данные, и ограничения не позволяют это сделать.Будут удалены только ограничения, которые начинаются с
partmanconstr_*
для указанной дочерней таблицы и настроенных столбцов.Если вам нужно удалить ограничения на всех дочерних таблицах, используйте процедуру
reapply_constraints_proc
. Она имеет опции, которые упрощают удаление ограничений с минимальным воздействием на производительность.Параметр отладки покажет вам оператор сброса ограничения, который был использован.
reapply_constraints_proc( p_parent_table text , p_drop_constraints boolean DEFAULT false , p_apply_constraints boolean DEFAULT false , p_wait int DEFAULT 0 , p_dryrun boolean DEFAULT false )
Процедура повторного применения дополнительных ограничений, управляемых pg_partman (см. раздел “Исключение ограничений” в разделе “О программе” выше).
Вызывает
drop_constraints()
и/илиapply_constraint()
в цикле, фиксируя после каждого удаления или добавления объекта. Это помогает избежать длительных транзакций и конфликтов при выполнении этого на больших наборах секций.Типичное использование будет заключаться в том, чтобы сначала удалить ограничения, отредактировать данные по мере необходимости, а затем снова применить ограничения.
p_parent_table
- Родительская таблица уже созданного набора секций.p_drop_constraints
- Удалить все ограничения, управляемые pg_partman. Удаляет ограничения на всех дочерних таблицах, включая текущие и будущие таблицы.p_apply_constraints
- Применить ограничения на настроенные столбцы ко всем дочерним таблицам, которые старше значения optimize_constraint.p_wait
- Подождите указанное количество секунд после того, как у таблицы были удалены или применены ограничения, прежде чем переходить к следующей.p_dryrun
- Не применять команды удаления/применения ограничений при выполнении этой процедуры. Просто выводит, к каким таблицам будут применены команды, в виде уведомлений (NOTICE).
reapply_privileges( p_parent_table text ) RETURNS void
Эта функция используется для повторного применения прав собственности и грантов на все дочерние таблицы на основе того, что установлено для родительской таблицы.
Привилегии, которые имеет родительская таблица, будут предоставлены всем дочерним таблицам, а привилегии, которых у родителя нет, будут отозваны (с CASCADE).
Проверяемые привилегии: SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES и TRIGGER.
Имейте в виду, что для больших наборов секций это может быть очень длительная операция, и именно поэтому она была сделана отдельной функцией для независимого выполнения. Применяются только те привилегии, которые отличаются между родительской и дочерней секциями, но все равно необходимо выполнять запросы к системному каталогу и сравнения для каждого отдельной дочерней секции и всех индивидуальных привилегий на каждом.
p_parent_table
- родительская таблица набора секций. Должна быть указана с указанием схемы и соответствовать уже настроенному имени родительской таблицы вpg_partman
.
stop_sub_partition( p_parent_table text , p_jobmon boolean DEFAULT true ) RETURNS boolean
По умолчанию, если вы отменяете дочернюю таблицу, которая также разбита на секции, это не остановит разделение на подсекции дочерних таблиц родительского набора секций, пока родительский набор также не будет отменен. Чтобы справиться с этой ситуацией, когда вы не удаляете родительский набор, но не хотите, чтобы чтобы дополнительные дочерние таблицы разделялись на подсекции, можно использовать эту функцию.
Эта функция просто удаляет запись parent_table из таблицы part_config_sub. Но это предоставляет предсказуемый, программный способ сделать это и также обеспечивает ведение журнала jobmon для операции.
F.42.5.3.3. Функции разрушения #
undo_partition( p_parent_table text , p_target_table text , p_loop_count int DEFAULT 1 , p_batch_interval text DEFAULT NULL , p_keep_table boolean DEFAULT true , p_lock_wait numeric DEFAULT 0 , p_ignored_columns text[] DEFAULT NULL , p_drop_cascade boolean DEFAULT false , OUT partitions_undone int , OUT rows_undone bigint) RETURNS record
Отменить набор секций, созданный с помощью
pg_partman
. Эта функция ПЕРЕМЕЩАЕТ данные из дочерних таблиц в указанную целевую таблицу.Если вы пытаетесь автоматически отменить разбиение большого объема данных, рекомендуется использовать процедуру
undo_partition_data()
для выполнения той же задачи. Это значительно уменьшит проблемы, вызванные длительными транзакциями и конфликтами данных.При выполнении этой функции, столбец
undo_in_progress
в таблице конфигурации устанавливается в значение true. Это приводит к остановке создания всех секций и управления их сохранением.По умолчанию секции не УДАЛЯЮТСЯ, они ОТКРЕПЛЯЮТСЯ. Это оставляет предыдущие дочерние таблицы пустыми, независимыми таблицами.
Без ручной установки любого из аргументов batch, каждый запуск функции будет перемещать все данные из одной секции в целевой.
Когда все дочерние таблицы были отсоединены/удалены, конфигурационные данные автоматически удаляются из
pg_partman
.Для подсекционированных таблиц вам может потребоваться начать с самой низкоуровневой родительской таблицы и отменить изменения оттуда, затем двигаться вверх.
p_parent_table
- родительская таблица набора секций. Должна быть указана с указанием схемы и соответствовать уже настроенному имени родительской таблицы вpg_partman
.p_target_table
- Схемно-квалифицированная таблица, в которую будут перемещены данные старой секционированной таблицы. Обязательно, так как секционированная таблица не может быть преобразована в не секционированную таблицу. Схема может отличаться от исходной таблицы.p_loop_count
- необязательный аргумент, который задает, сколько раз перемещать объем данных, равный аргументуp_batch_interval
(или интервалу секционирования по умолчанию, если не задан) за один запуск функции. По умолчанию 1.p_batch_interval
- необязательный аргумент. Интервал времени или идентификатор того, сколько данных перемещать. Этот интервал может быть меньше интервала секционирования, что позволяет разбивать очень большие секции на меньшие партии коммитов. По умолчанию используется настроенный интервал секционирования, если не указан или если указан интервал больше, чем интервал секционирования. Обратите внимание, что значение должно быть передано этому параметру в виде текста.p_keep_table
- необязательный аргумент, установка которого в false приведет к удалению старой дочерней таблицы вместо отсоединения после перемещения всех ее данных. Обратите внимание, что для фактического удаления таблицы из набора требуется как минимум два пакета.p_lock_wait
- необязательный аргумент, устанавливает, как долго в секундах ждать разблокировки строки или таблицы перед истечением времени ожидания. По умолчанию ожидание продолжается бесконечно.p_ignored_columns
- Эта опция позволяет фильтровать определенные столбцы при перемещении данных из дочерних таблиц в целевую таблицу. Это обычно требуется только при использовании столбцов со значением GENERATED ALWAYS, поскольку прямая вставка значения приведет к ошибке при перемещении данных. Значение представляет собой массив текстовых имен столбцов.p_drop_cascade
- Разрешить отмену наборов подпартиций от родительских таблиц выше в дереве наследования. Применяется только, когдаp_keep_tables
установлено в false. Обратите внимание, что это приводит к удалению всех дочерних таблиц ниже родительской подпартиции, когда эта родительская таблица удаляется.Возвращает количество отмененных секций и количество строк, перемещенных в родительскую таблицу. Значение отмененных секций равно -1, если возникает проблема.
undo_partition_proc( p_parent_table text , p_target_table text DEFAULT NULL , p_loop_count int DEFAULT NULL , p_interval text DEFAULT NULL , p_keep_table boolean DEFAULT true , p_lock_wait int DEFAULT 0 , p_lock_wait_tries int DEFAULT 10 , p_wait int DEFAULT 1 , p_ignored_columns text[] DEFAULT NULL , p_drop_cascade boolean DEFAULT false , p_quiet boolean DEFAULT false )
Процедура, которая может отменить секционирование данных в определенных партиях коммитов, чтобы избежать длительных транзакций и проблем с конфликтом данных.
Вызывает функцию undo_partition() в цикле, выполняя фиксацию по мере необходимости.
p_parent_table
- Родительская таблица уже созданного набора секций.p_target_table
- То же самое, что и опция p_target_table в функции undo_partition().p_loop_count
- Сколько раз повторить значение, заданное для p_interval. Если p_interval не установлен, будет использоваться интервал секционирования по умолчанию и отменяться не более этого количества секций. Процедура фиксирует изменения в конце каждого цикла (НЕ передается как p_batch_count в функцию секционирования). Если не установлено, все данные в наборе секций будут перемещены за один запуск процедуры.p_interval
- Значение, передаваемое в функцию undo_partition в качестве аргумента p_batch_interval. Используйте это значение, чтобы установить интервал, меньший, чем интервал секции, для фиксации данных пакетами меньшего размера. Если значение не указано, по умолчанию используется интервал секции.p_keep_table
- То же самое, что и опция p_keep_table в функции undo_partition().p_lock_wait
- Параметр, передаваемый напрямую в функцию undo_partition(). Количество секунд ожидания строк, которые могут быть заблокированы другой транзакцией. По умолчанию ожидание бесконечно (0).p_lock_wait_tries
- Параметр, устанавливающий, сколько раз процедура будет пытаться ожидать заданное время для p_lock_wait. По умолчанию 10 попыток.p_wait
- Заставляет процедуру ожидать заданное количество секунд между фиксацией (партиями), чтобы снизить нагрузку на запись.p_ignored_columns
- Эта опция позволяет фильтровать определенные столбцы при перемещении данных из дочерних таблиц в целевую таблицу. Это обычно требуется только при использовании столбцов со значением GENERATED ALWAYS, поскольку прямая вставка значения приведет к ошибке при перемещении данных. Значение представляет собой массив текстовых имен столбцов.p_drop_cascade
- Разрешить отмену наборов подпартиций от родительских таблиц выше в дереве наследования. Применяется только, когдаp_keep_tables
установлено в false. Обратите внимание, что это приводит к удалению всех дочерних таблиц ниже родительской подпартиции, когда эта родительская таблица удаляется.p_quiet
- Процедуры не могут возвращать значения, поэтому по умолчанию они выводят УВЕДОМЛЕНИЯ, чтобы показать прогресс. Установите эту опцию, чтобы подавить эти уведомления.
drop_partition_time( p_parent_table text , p_retention interval DEFAULT NULL , p_keep_table boolean DEFAULT NULL , p_keep_index boolean DEFAULT NULL , p_retention_schema text DEFAULT NULL , p_reference_timestamp timestamptz DEFAULT CURRENT_TIMESTAMP ) RETURNS int
Эта функция используется для удаления дочерних таблиц из набора секций на основе времени в соответствии с политикой хранения. По умолчанию таблица просто теряет наследование и фактически не удаляется. Для автоматического удаления старых таблиц рекомендуется использовать функцию
run_maintenance()
с настроенной политикой хранения вместо прямого вызова этой функции.p_parent_table
- существующая родительская таблица набора секций с временным критерием. ДОЛЖНА быть указана схемой, даже если она находится в общей схеме.p_retention
- необязательный параметр для указания интервала удержания и немедленного удаления таблиц, содержащих только данные, старше указанного интервала. Если у вас уже установлено значение удержания в таблице конфигурации, функция будет использовать его, в противном случае этот параметр переопределит его. Если нет, этот параметр является обязательным. См. раздел Описание выше для получения дополнительной информации о настройках удержания.p_keep_table
- необязательный параметр, чтобы указать partman, сохранять или удалять таблицу в дополнение к отмене наследования. TRUE означает, что таблица не будет фактически удалена; FALSE означает, что таблица будет удалена. Эта функция будет использовать значение, настроенное в part_config, если не установлено явно. Этот параметр игнорируется, если retention_schema установлен.p_keep_index
- необязательный параметр, указывающий partman, сохранять или удалять индексы дочерней таблицы при ее отмене наследования. TRUE означает, что индексы будут сохранены; FALSE означает, что все индексы будут удалены. Эта функция будет использовать значение, настроенное в part_config, если явно не указано. Этот параметр игнорируется, если p_keep_table установлен в FALSE.p_retention_schema
- необязательный параметр, чтобы указать partman переместить таблицу в другую схему вместо удаления её. Установите это значение в схему, в которую вы хотите переместить таблицу. Эта функция будет использовать значение, настроенное вpart_config
, если явно не указано. Если этот параметр установлен, параметр удержанияp_keep_table
игнорируется.p_reference_timestamp
- необязательный параметр, который указывает partman использовать другую временную метку в качестве опорной для определения, какие секции должны быть затронуты, значение по умолчанию -CURRENT_TIMESTAMP
.Возвращает количество затронутых секций.
drop_partition_id( p_parent_table text , p_retention bigint DEFAULT NULL , p_keep_table boolean DEFAULT NULL , p_keep_index boolean DEFAULT NULL , p_retention_schema text DEFAULT NULL ) RETURNS int
Эта функция используется для удаления дочерних таблиц из набора секций на основе целочисленных значений в соответствии с политикой хранения. По умолчанию таблица просто теряет наследование, но фактически не удаляется. Для автоматического удаления старых таблиц рекомендуется использовать функцию
run_maintenance()
с настроенной политикой хранения вместо прямого вызова этой функции.p_parent_table
- существующая родительская таблица набора секций с временным критерием. ДОЛЖНА быть указана схемой, даже если она находится в общей схеме.p_retention
- необязательный параметр для указания целочисленного интервала удержания и немедленного удаления таблиц, содержащих только данные, меньшие текущего максимального значения id, минус заданное значение удержания. Если у вас уже установлено значение удержания в таблице конфигурации, функция будет использовать его, в противном случае это переопределит его. В противном случае, этот параметр является обязательным. См. раздел Описание выше для получения дополнительной информации о настройках удержания.p_keep_table
- необязательный параметр, чтобы указать partman, сохранять или удалять таблицу в дополнение к отмене наследования. TRUE означает, что таблица не будет фактически удалена; FALSE означает, что таблица будет удалена. Эта функция будет использовать значение, настроенное в part_config, если не установлено явно. Этот параметр игнорируется, если retention_schema установлен.p_keep_index
- необязательный параметр, указывающий partman, сохранять или удалять индексы дочерней таблицы при ее отмене наследования. TRUE означает, что индексы будут сохранены; FALSE означает, что все индексы будут удалены. Эта функция будет использовать значение, настроенное в part_config, если явно не указано. Этот параметр игнорируется, если p_keep_table установлен в FALSE.p_retention_schema
- необязательный параметр, чтобы указать partman переместить таблицу в другую схему вместо удаления её. Установите это значение в схему, в которую вы хотите переместить таблицу. Эта функция будет использовать значение, настроенное вpart_config
, если явно не указано. Если этот параметр установлен, параметр удержанияp_keep_table
игнорируется.Возвращает количество затронутых секций.
F.42.5.3.4. Таблицы #
part_config
Хранит все конфигурационные данные для наборов секций, управляемых расширением.
parent_table text NOT NULL , control text NOT NULL , partition_interval text NOT NULL , partition_type text NOT NULL , premake int NOT NULL DEFAULT 4 , automatic_maintenance text NOT NULL DEFAULT 'on' , template_table text , retention text , retention_schema text , retention_keep_index boolean NOT NULL DEFAULT true , retention_keep_table boolean NOT NULL DEFAULT true , epoch text NOT NULL DEFAULT 'none' , constraint_cols text[] , optimize_constraint int NOT NULL DEFAULT 30 , infinite_time_partitions boolean NOT NULL DEFAULT false , datetime_string text , jobmon boolean NOT NULL DEFAULT true , sub_partition_set_full boolean NOT NULL DEFAULT false , undo_in_progress boolean NOT NULL DEFAULT false , inherit_privileges boolean DEFAULT false , constraint_valid boolean DEFAULT true NOT NULL , subscription_refresh text , ignore_default_data boolean NOT NULL DEFAULT true
parent_table
Родительская таблица набора секций
control
Столбец, используемый в качестве контроля для ограничений секционирования. Должен быть столбцом, основанным на времени или целочисленным.
partition_interval
Текстовый тип значения, определяющий интервал для каждой секции.
Должно быть значение, которое может быть приведено к типам данных интервал или bigint.
partition_type
Тип секционирования. Должен быть одним из указанных типов в информации
create_parent()
выше.
premake
Сколько секций нужно заранее создать перед текущей секцией. По умолчанию - 4.
automatic_maintenance
Флаг для установки автоматического управления обслуживанием, когда вызывается
run_maintenance()
без параметра таблицы или фоновым рабочим процессом.Текущие допустимые значения: “вкл” и “выкл”. По умолчанию - “вкл”.
Когда установлено значение "выключено",
run_maintenance()
все равно может быть вызван для отдельного набора секций, передав его в качестве параметра функции.
template_table
Схема-квалифицированное имя таблицы, используемой в качестве шаблона для применения любых опций наследования, не обрабатываемых основными опциями партиционирования Tantor SE в PG.
retention
Текстовое значение, определяющее, насколько старыми могут быть данные в дочерней секции, прежде чем они будут удалены.
Должно быть значением, которое может быть приведено либо к типу данных interval (для секционирования по времени), либо к bigint (для секционирования по числам).
Оставьте эту колонку NULL (по умолчанию), чтобы всегда сохранять все дочерние секции. Смотрите О секции для получения дополнительной информации.
retention_schema
Схема для перемещения таблиц в рамках системы хранения вместо их удаления. Переопределяет параметр retention_keep_table.
retention_keep_index
Логическое значение для определения, удаляются ли индексы для дочерних таблиц, которые отсоединены.
По умолчанию TRUE. Установите FALSE, чтобы индексы дочерней таблицы были удалены при её отсоединении.
retention_keep_table
Логическое значение для определения, будут ли удаленные дочерние таблицы только отсоединены или фактически удалены.
По умолчанию значение TRUE сохраняет таблицу и только отменяет наследование от нее. Установите значение FALSE, чтобы полностью удалить дочерние таблицы из базы данных.
epoch
Пометить таблицу для секционирования по времени с использованием целочисленного значения эпохи вместо метки времени. См. функцию
create_parent()
для получения дополнительной информации. По умолчанию 'none'.
constraint_cols
Массивная колонка, которая перечисляет колонки для применения дополнительных ограничений. Смотрите раздел "Об этом" для получения дополнительной информации о том, как работает эта функция.
optimize_constraint
Управляет тем, какие старые таблицы получают дополнительные ограничения, если это настроено. См. раздел Описание для получения дополнительной информации. По умолчанию 30.
infinite_time_partitions
По умолчанию, новые секции в наборе, основанном на времени, не будут создаваться, если новые данные не будут вставлены, чтобы не создавать бесконечное количество пустых таблиц.
Если вы все еще хотите создать новые секции, несмотря на отсутствие новых данных, установите это значение на TRUE.
По умолчанию установлено значение false.
datetime_string
Для секционирования по времени используется строка формата даты и времени при именовании дочерних секций.
jobmon
Булево значение, определяющее, используется ли расширение
pg_jobmon
для ведения журнала/мониторинга обслуживания секций. По умолчанию установлено значение true.
sub_partition_set_full
Логическое значение, указывающее, что последняя партиция для набора субпартиций была создана. Позволяет run_maintenance() работать более эффективно, когда имеется большое количество наборов субпартиций.
undo_in_progress
Устанавливается функциями undo_partition при каждом их запуске. Если значение true, то это приводит к остановке всех операций создания и управления хранением секций функцией
run_maintenance()
). По умолчанию значение false.
inherit_privileges
Устанавливает, наследовать ли права собственности/привилегии родительской таблицы для всех дочерних таблиц. По умолчанию false и должно быть необходимо только в том случае, если вам нужен прямой доступ к дочерним таблицам, минуя родительскую таблицу.
constraint_valid
Логическое значение, которое позволяет создавать дополнительные ограничения, которые pg_partman может управлять за вас, как НЕДЕЙСТВИТЕЛЬНЫЕ. См. раздел "Исключение ограничений" в начале для получения более подробной информации об этих ограничениях. Это может позволить выполнять обслуживание намного быстрее на больших наборах секций, поскольку существующие данные не проверяются перед добавлением ограничения. Новые вставленные данные проверяются, поэтому это полностью безопасный вариант для обеспечения целостности данных. Обратите внимание, что исключение по ограничению НЕ БУДЕТ работать, пока ограничения не будут проверены. По умолчанию установлено значение true, чтобы ограничения создавались как ДЕЙСТВИТЕЛЬНЫЕ (VALID). Установите значение false, чтобы новые ограничения создавались как НЕДЕЙСТВИТЕЛЬНЫЕ (NOT VALID).
subscription_refresh
- Имя подписки логической репликации для обновления при выполнении обслуживания. Если набор секций подписан на публикацию, в которую будут добавляться/удаляться таблицы, и вам нужно, чтобы ваш набор секций был в курсе этих изменений, вы должны указать эту подписку с помощью этого параметра. В противном случае подписка никогда не узнает о новых таблицах, добавленных в издателя, если вы не обновляете подписку каким-либо другим способом. См. документацию Tantor SE по ALTER SUBSCRIPTION для получения дополнительной информации об обновлении подписок - ALTER SUBSCRIPTIONignore_default_data
- По умолчанию, обслуживание будет игнорировать данные в таблице по умолчанию при определении, следует ли создавать новую дочернюю таблицу. Это означает, что если данные находятся в таблице по умолчанию и новая дочерняя таблица будет содержать эти данные, будет выдана ошибка. Если вам нужно, чтобы обслуживание учитывало данные в таблице по умолчанию для исправления проблемы обслуживания, это можно установить в значение false. Обратите внимание, что это может вызвать пробелы в покрытии дочерней таблицы, что может сделать данные, попадающие в таблицу по умолчанию, еще хуже, поэтому не следует оставлять это включенным после исправления проблем обслуживания.
part_config_sub
Хранит все данные конфигурации для наборов подсекций, управляемых
pg_partman
.Столбец
sub_parent
является родительской таблицей набора подсекций, и все остальные столбцы определяют, как дочерние элементы этого родителя разделяются на подсекции.Все остальные столбцы работают точно так же, как их аналоги в таблице
part_config
или как параметры, передаваемые вcreate_parent()
.
F.42.5.3.5. Скрипты #
Если расширение было установлено с использованием make, следующие скриптовые файлы должны были быть установлены в бинарный каталог Tantor SE.
dump_partition.py
Python-скрипт для выгрузки таблиц, содержащихся в указанной схеме. Использует pg_dump, создает файл хеша SHA-512 для выгрузки и затем удаляет таблицу.
В сочетании с параметром конфигурации retention_schema предоставляет надежный способ выгрузки таблиц, которые обычно просто удаляются системой удержания.
Таблицы не удаляются, если pg_dump не завершается успешно.
Параметры подключения для psycopg и pg_dump были разделены из-за различий в их требованиях в зависимости от конфигурации подключения к базе данных.
Все параметры по умолчанию для опций dump_* такие же, как у pg_dump, если они не указаны.
Будет работать с любой указанной схемой, не только с той, которая используется для управления удержанием
pg_partman
.--schema (-n)
: Схема, содержащая таблицы, которые будут выгружены. (Обязательно).--connection (-c)
: Строка подключения для использования psycopg. Роль, используемая, должна иметь возможность выбирать из pg_catalog.pg_tables в соответствующей базе данных и удалять все таблицы в указанной схеме. По умолчанию “host=” (локальный сокет). Обратите внимание, что это отличается от параметров, отправляемых в pg_dump.--output (-o)
: Путь к месту выгрузки файла. По умолчанию - текущий каталог.--dump_database (-d)
: Используется для pg_dump, аналогично его параметру –dbname или последнему параметру имени базы данных.--dump_host
: Используется для pg_dump, аналогично его параметру –host.--dump_username
: Используется для pg_dump, аналогично его параметру –username.--dump_port
: Используется для pg_dump, аналогично его параметру –port option.--pg_dump_path
: Путь к исполняемому файлу pg_dump. Должен быть указан, если он не находится в текущем PATH.--Fp
: Выгрузка в формате plain text с использованием pg_dump. По умолчанию - бинарный формат custom (-Fc).--nohashfile
: НЕ создавать отдельный файл с хешем SHA-512 выгрузки. Если файлы выгрузки очень большие, генерация хеша может занять много времени.--nodrop
: НЕ удалять таблицы из указанной схемы после выгрузки/хеширования.--verbose (-v)
: Предоставить более подробный вывод.--version
: Выводит минимальную версиюpg_partman
, с которой предполагается работа этого скрипта. Установленная версияpg_partman
может быть больше этой.
vacuum_maintenance.py
Скрипт на python для выполнения дополнительного обслуживания VACUUM на заданном наборе секций. Основная цель этого - предоставить более простой способ замораживания кортежей в старых секциях, в которые больше не производится запись. Это позволяет автовакууму безопасно пропускать их, не вызывая проблем с зацикливанием идентификатора транзакции. См. документацию Tantor SE для получения дополнительной информации об этой проблеме обслуживания: Раздел 24.1.5.
Очищает все дочерние таблицы в заданном наборе секций, у которых возраст (relfrozenxid) больше vacuum_freeze_min_age, включая родительскую таблицу.
Настоятельно рекомендуется запускать этот скрипт по расписанию с опцией –freeze, если у вас есть дочерние таблицы, в которые после определенного периода времени не происходят записи.
–parent (-р): Родительская таблица уже созданного набора секций. (Обязательно)
–connection (-c): Строка подключения для использования psycopg. По умолчанию установлено значение “host=” (локальный сокет).
–freeze (-z): Устанавливает опцию FREEZE для команды VACUUM.
–full (-f): Устанавливает опцию FULL для команды VACUUM. Обратите внимание, что –freeze не является обязательным, если вы установите это. Рекомендуется ознакоммиться с –dryrun перед запуском этой команды, так как она заблокирует все таблицы, с которыми она работает, возможно, включая родительскую.
–vacuum_freeze_min_age (-a): По умолчанию сценарий получает это значение из системных каталогов. Установка этого значения позволяет переопределить значение, полученное из базы данных. Обратите внимание, что это не изменяет значение в базе данных, а только значение, используемое этим сценарием.
–noparent: Обычно родительская таблица включается в список таблиц для очистки, если ее возраст (relfrozenxid) выше, чем vacuum_freeze_min_age. Установите это значение, чтобы исключить родительскую таблицу, даже если она соответствует этим критериям.
–dryrun: Показывает, что сценарий будет делать, не запуская его на самой базе данных. Настоятельно рекомендуется просмотреть это перед первым запуском.
–quiet (-q): Выключить все выводы.
–debug: Показать дополнительный отладочный вывод.
check_unique_constraints.py
Декларативное разбиение имеет недостаток, заключающийся в невозможности создания уникального ограничения, если ограничение не включает столбец разбиения. Это часто невозможно, особенно при разбиении на основе времени. Этот скрипт используется для проверки того, что все строки в наборе секций уникальны для заданных столбцов.
Обратите внимание, что для очень больших наборов секций это может быть дорогостоящая операция, которая может потреблять большие объемы дискового пространства. Требуемый объем дискового пространства достаточен для выгрузки всех данных столбцов индекса в виде текстового файла.
Если значение столбца нарушает уникальное ограничение, этот скрипт вернет эти значения столбцов вместе с количеством каждого значения. Вывод также может быть упрощен до одного общего целочисленного значения, чтобы облегчить его использование с мониторинговыми приложениями.
--parent (-p)
: Родительская таблица набора секций, которую необходимо проверить. (Обязательно)--column_list (-l)
: Список столбцов, разделенных запятыми, которые составляют ограничение уникальности для проверки. (Обязательно)--connection (-c)
: Строка подключения, используемая psycopg. По умолчанию “host=” (локальный сокет).--temp (-t)
: Путь к папке, в которую можно записывать и использовать временные рабочие файлы. По умолчанию используется системная папка для временных файлов.--psql
: Полный путь к исполняемому файлу psql, если он не находится в текущем пути PATH.--simple
: Выводит одно целочисленное значение с общим количеством дубликатов. Используйте это для программного обеспечения мониторинга, которое требует проверки простого значения.--quiet (-q)
: Подавить все выводы, кроме случаев обнаружения нарушения ограничений.--version
: Выводит минимальную версиюpg_partman
, с которой предполагается работа этого скрипта. Установленная версияpg_partman
может быть больше этой.
F.42.6. Пример руководства по настройке нативного секционирования #
В этом руководство HowTo показано несколько примеров того, как настроить простое, одноуровневое секционирование. Оно также покажет вам несколько методов секционирования данных из таблицы, которая уже содержит данные (см. Разделение существующей таблицы) и отмены секционирования существующего набора секций (см. Отмена нативного секционирования). Для получения более подробной информации о том, что делает каждая функция и о дополнительных возможностях этого расширения, пожалуйста, см. главу Раздел F.42.5.
Примеры в этом документе предполагают, что вы используете как минимум 5.0.1 pg_partman с Tantor SE 14 или выше.
F.42.6.1. Простое разделение по времени: 1 секция в день #
Для нативного секционирования необходимо начать с родительской таблицы, которая уже настроена для секционирования нужного типа. В настоящее время pg_partman поддерживает только тип секционирования RANGE (как для времени, так и для идентификатора). Невозможно превратить несекционированную таблицу в родительскую таблицу набора секционированных таблиц, что может усложнить миграцию. В этом документе будут показаны некоторые методы управления этим процессом позже. Сейчас мы начнем с совершенно новой таблицы в этом примере. Любые неуникальные индексы также могут быть добавлены в родительскую таблицу в PG11+, и они автоматически будут созданы на всех дочерних таблицах.
CREATE SCHEMA IF NOT EXISTS partman_test; CREATE TABLE partman_test.time_taptest_table (col1 int, col2 text default 'stuff', col3 timestamptz NOT NULL DEFAULT now()) PARTITION BY RANGE (col3); CREATE INDEX ON partman_test.time_taptest_table (col3);
\d+ partman_test.time_taptest_table Partitioned table "partman_test.time_taptest_table" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+---------------+----------+-------------+--------------+------------- col1 | integer | | | | plain | | | col2 | text | | | 'stuff'::text | extended | | | col3 | timestamp with time zone | | not null | now() | plain | | | Partition key: RANGE (col3) Indexes: "time_taptest_table_col3_idx" btree (col3) Number of partitions: 0
Уникальные индексы (включая первичные ключи) не могут быть созданы на нативно секционированном родительском объекте, если они не включают ключ секционирования. Для секционирования по времени это обычно не работает, так как это ограничивало бы только одно значение временной метки в каждой дочерней таблице. pg_partman помогает управлять этим, используя шаблонную таблицу для управления свойствами, которые в настоящее время не поддерживаются нативным секционированием. Обратите внимание, что это не решает проблему ограничения не применяемого ко всему набору секций. См. Раздел F.42.5.1.1 чтобы увидеть, какие свойства управляются шаблоном.
Для этого примера мы сначала вручную создадим шаблонную
таблицу, чтобы при запуске
create_parent()
первоначально созданные дочерние таблицы
имели первичный ключ. Если вы не предоставляете
шаблонную таблицу для pg_partman, он создаст ее для вас в
схеме, в которую вы установили расширение. Однако свойства,
которые вы добавляете к этому шаблону, применяются только к вновь созданным
дочерним таблицам после этого момента. Вам придется ретроактивно
применять эти свойства вручную к любым дочерним таблицам, которые уже
существовали.
CREATE TABLE partman_test.time_taptest_table_template (LIKE partman_test.time_taptest_table); ALTER TABLE partman_test.time_taptest_table_template ADD PRIMARY KEY (col1);
\d partman_test.time_taptest_table_template Table "partman_test.time_taptest_table_template" Column | Type | Collation | Nullable | Default --------+--------------------------+-----------+----------+--------- col1 | integer | | not null | col2 | text | | | col3 | timestamp with time zone | | not null | Indexes: "time_taptest_table_template_pkey" PRIMARY KEY, btree (col1)
SELECT partman.create_parent( p_parent_table := 'partman_test.time_taptest_table' , p_control := 'col3' , p_interval := '1 day' , p_template_table := 'partman_test.time_taptest_table_template' ); create_parent --------------- t (1 row)
\d+ partman_test.time_taptest_table Partitioned table "partman_test.time_taptest_table" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+---------------+----------+-------------+--------------+------------- col1 | integer | | | | plain | | | col2 | text | | | 'stuff'::text | extended | | | col3 | timestamp with time zone | | not null | now() | plain | | | Partition key: RANGE (col3) Indexes: "time_taptest_table_col3_idx" btree (col3) Partitions: partman_test.time_taptest_table_p20230324 FOR VALUES FROM ('2023-03-24 00:00:00-07') TO ('2023-03-25 00:00:00-07'), partman_test.time_taptest_table_p20230325 FOR VALUES FROM ('2023-03-25 00:00:00-07') TO ('2023-03-26 00:00:00-07'), partman_test.time_taptest_table_p20230326 FOR VALUES FROM ('2023-03-26 00:00:00-07') TO ('2023-03-27 00:00:00-07'), partman_test.time_taptest_table_p20230327 FOR VALUES FROM ('2023-03-27 00:00:00-07') TO ('2023-03-28 00:00:00-07'), partman_test.time_taptest_table_p20230328 FOR VALUES FROM ('2023-03-28 00:00:00-07') TO ('2023-03-29 00:00:00-07'), partman_test.time_taptest_table_p20230329 FOR VALUES FROM ('2023-03-29 00:00:00-07') TO ('2023-03-30 00:00:00-07'), partman_test.time_taptest_table_p20230330 FOR VALUES FROM ('2023-03-30 00:00:00-07') TO ('2023-03-31 00:00:00-07'), partman_test.time_taptest_table_p20230331 FOR VALUES FROM ('2023-03-31 00:00:00-07') TO ('2023-04-01 00:00:00-07'), partman_test.time_taptest_table_p20230401 FOR VALUES FROM ('2023-04-01 00:00:00-07') TO ('2023-04-02 00:00:00-07'), partman_test.time_taptest_table_default DEFAULT
\d+ partman_test.time_taptest_table_p20230324 Table "partman_test.time_taptest_table_p20230324" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+---------------+----------+-------------+--------------+------------- col1 | integer | | not null | | plain | | | col2 | text | | | 'stuff'::text | extended | | | col3 | timestamp with time zone | | not null | now() | plain | | | Partition of: partman_test.time_taptest_table FOR VALUES FROM ('2023-03-24 00:00:00-07') TO ('2023-03-25 00:00:00-07') Partition constraint: ((col3 IS NOT NULL) AND (col3 >= '2023-03-24 00:00:00-07'::timestamp with time zone) AND (col3 < '2023-03-25 00:00:00-07'::timestamp with time zone)) Indexes: "time_taptest_table_p20230324_pkey" PRIMARY KEY, btree (col1) "time_taptest_table_p20230324_col3_idx" btree (col3) Access method: heap
F.42.6.2. Простой серийный ID: 1 секция на 10 значений ID #
Для этого варианта использования таблица-шаблон не создается вручную
перед вызовом create_parent()
. Таким образом, показывается,
что если позже добавляется первичный/уникальный ключ, он не применяется
к текущим существующим дочерним таблицам. Это придется сделать вручную.
CREATE TABLE partman_test.id_taptest_table ( col1 bigint not null , col2 text , col3 timestamptz DEFAULT now() not null , col4 text) PARTITION BY RANGE (col1); CREATE INDEX ON partman_test.id_taptest_table (col1);
\d+ partman_test.id_taptest_table Partitioned table "partman_test.id_taptest_table" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+---------+----------+-------------+--------------+------------- col1 | bigint | | not null | | plain | | | col2 | text | | | | extended | | | col3 | timestamp with time zone | | not null | now() | plain | | | col4 | text | | | | extended | | | Partition key: RANGE (col1) Indexes: "id_taptest_table_col1_idx" btree (col1) Number of partitions: 0
SELECT partman.create_parent( p_parent_table := 'partman_test.id_taptest_table' , p_control := 'col1' , p_interval := '10' ); create_parent --------------- t (1 row)
\d+ partman_test.id_taptest_table Partitioned table "partman_test.id_taptest_table" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+---------+----------+-------------+--------------+------------- col1 | bigint | | not null | | plain | | | col2 | text | | | | extended | | | col3 | timestamp with time zone | | not null | now() | plain | | | col4 | text | | | | extended | | | Partition key: RANGE (col1) Indexes: "id_taptest_table_col1_idx" btree (col1) Partitions: partman_test.id_taptest_table_p0 FOR VALUES FROM ('0') TO ('10'), partman_test.id_taptest_table_p10 FOR VALUES FROM ('10') TO ('20'), partman_test.id_taptest_table_p20 FOR VALUES FROM ('20') TO ('30'), partman_test.id_taptest_table_p30 FOR VALUES FROM ('30') TO ('40'), partman_test.id_taptest_table_p40 FOR VALUES FROM ('40') TO ('50'), partman_test.id_taptest_table_default DEFAULT
Вы можете увидеть имя шаблонной таблицы, посмотрев в конфигурацию pg_partman для этой родительской таблицы
SELECT template_table FROM partman.part_config WHERE parent_table = 'partman_test.id_taptest_table'; template_table ------------------------------------------------ partman.template_partman_test_id_taptest_table (1 row)
ALTER TABLE partman.template_partman_test_id_taptest_table ADD PRIMARY KEY (col2);
Теперь, если мы добавим некоторые данные и снова запустим обслуживание для создания новых дочерних таблиц...
INSERT INTO partman_test.id_taptest_table (col1, col2) VALUES (generate_series(1,20), generate_series(1,20)::text||'stuff'::text); CALL partman.run_maintenance_proc(); \d+ partman_test.id_taptest_table Partitioned table "partman_test.id_taptest_table" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+---------+----------+-------------+--------------+------------- col1 | bigint | | not null | | plain | | | col2 | text | | | | extended | | | col3 | timestamp with time zone | | not null | now() | plain | | | col4 | text | | | | extended | | | Partition key: RANGE (col1) Indexes: "id_taptest_table_col1_idx" btree (col1) Partitions: partman_test.id_taptest_table_p0 FOR VALUES FROM ('0') TO ('10'), partman_test.id_taptest_table_p10 FOR VALUES FROM ('10') TO ('20'), partman_test.id_taptest_table_p20 FOR VALUES FROM ('20') TO ('30'), partman_test.id_taptest_table_p30 FOR VALUES FROM ('30') TO ('40'), partman_test.id_taptest_table_p40 FOR VALUES FROM ('40') TO ('50'), partman_test.id_taptest_table_p50 FOR VALUES FROM ('50') TO ('60'), partman_test.id_taptest_table_p60 FOR VALUES FROM ('60') TO ('70'), partman_test.id_taptest_table_default DEFAULT
… вы увидите, что только новые дочерние таблицы (p50 и p60) имеют этот первичный ключ, а оригинальные таблицы его не имеют (p40 и ранее).
keith=# \d partman_test.id_taptest_table_p40 Table "partman_test.id_taptest_table_p40" Column | Type | Collation | Nullable | Default --------+--------------------------+-----------+----------+--------- col1 | bigint | | not null | col2 | text | | | col3 | timestamp with time zone | | not null | now() col4 | text | | | Partition of: partman_test.id_taptest_table FOR VALUES FROM ('40') TO ('50') Indexes: "id_taptest_table_p40_col1_idx" btree (col1) keith=# \d partman_test.id_taptest_table_p50 Table "partman_test.id_taptest_table_p50" Column | Type | Collation | Nullable | Default --------+--------------------------+-----------+----------+--------- col1 | bigint | | not null | col2 | text | | not null | col3 | timestamp with time zone | | not null | now() col4 | text | | | Partition of: partman_test.id_taptest_table FOR VALUES FROM ('50') TO ('60') Indexes: "id_taptest_table_p50_pkey" PRIMARY KEY, btree (col2) "id_taptest_table_p50_col1_idx" btree (col1) keith=# \d partman_test.id_taptest_table_p60 Table "partman_test.id_taptest_table_p60" Column | Type | Collation | Nullable | Default --------+--------------------------+-----------+----------+--------- col1 | bigint | | not null | col2 | text | | not null | col3 | timestamp with time zone | | not null | now() col4 | text | | | Partition of: partman_test.id_taptest_table FOR VALUES FROM ('60') TO ('70') Indexes: "id_taptest_table_p60_pkey" PRIMARY KEY, btree (col2) "id_taptest_table_p60_col1_idx" btree (col1)
Добавьте их вручную:
ALTER TABLE partman_test.id_taptest_table_p0 ADD PRIMARY KEY (col2); ALTER TABLE partman_test.id_taptest_table_p10 ADD PRIMARY KEY (col2); ALTER TABLE partman_test.id_taptest_table_p20 ADD PRIMARY KEY (col2); ALTER TABLE partman_test.id_taptest_table_p30 ADD PRIMARY KEY (col2); ALTER TABLE partman_test.id_taptest_table_p40 ADD PRIMARY KEY (col2);
F.42.6.3. секционирование существующей таблицы #
Секционирование существующей таблицы с использованием нативного секционирования не так просто, как просто изменение таблицы. Как указано выше, вы не можете превратить уже существующую таблицу в родительскую таблицу нативного набора секций. Родительская таблица нативно секционированной таблицы должна быть объявлена секционированной в момент ее создания. Однако, существуют методы, позволяющие взять существующую таблицу и секционировать ее нативно. Два из них представлены ниже.
Один совет, который может помочь с увеличением скорости/нагрузки при разбиении таблицы, заключается в выполнении команды CLUSTER на исходной таблице с использованием индекса ключа разбиения незадолго до выполнения разбиения. Поскольку данные будут считываться последовательно из исходной таблицы, их упорядоченность может потенциально помочь с эффективностью ввода-вывода на очень больших таблицах. См. документацию Tantor SE - CLUSTER.
F.42.6.3.1. Оффлайн секционирование #
Этот метод получил метку “офлайн”, потому что во время некоторых этапов этого процесса данные не доступны как для новой, так и для старой таблицы из одного объекта. Данные перемещаются из исходной таблицы в совершенно новую таблицу. Преимущество этого метода заключается в том, что вы можете перемещать свои данные гораздо меньшими партиями, чем даже размер целевой секции, что может быть огромным преимуществом в эффективности для очень больших наборов секций (вы можете фиксировать изменения партиями в несколько тысяч против нескольких миллионов). Также меньше шагов переименования объектов, как мы увидим в методе онлайн-секционирования далее.
ВАЖНОЕ ЗАМЕЧАНИЕ ОТНОСИТЕЛЬНО ВНЕШНИХ КЛЮЧЕЙ
Отключение секционированной таблицы - единственный метод, который реально работает, когда у вас есть внешние ключи К таблице, которая разделяется. Поскольку в любом случае должна быть создана совершенно новая таблица, внешний ключ также должен быть создан заново, поэтому должно быть прервано взаимодействие со всеми таблицами, которые являются частью отношения FK. Более короткое прерывание может быть возможно с помощью онлайн-метода ниже, но если вам приходится проводить прерывание, этот офлайн-метод проще.
Вот исходная таблица с некоторыми сгенерированными данными:
CREATE TABLE public.original_table ( col1 bigint not null , col2 text not null , col3 timestamptz DEFAULT now() , col4 text); CREATE INDEX ON public.original_table (col1); INSERT INTO public.original_table (col1, col2, col3, col4) VALUES (generate_series(1,100000), 'stuff'||generate_series(1,100000), now(), 'stuff');
Сначала исходную таблицу следует переименовать, чтобы можно было создать секционированную таблицу с именем исходной таблицы. Это позволяет при создании дочерних таблиц дать им имена, которые связаны с именем исходной таблицы.
ALTER TABLE public.original_table RENAME to old_nonpartitioned_table;
Мы воспользуемся примером секционирование по серии из вышеуказанного.
Начальная настройка точно такая же, создается совершенно новая таблица,
которая будет родительской, а затем на ней запускается
create_parent()
. В этот раз мы сделаем
интервал немного больше. Также убедитесь, что вы
применили все те же исходные свойства к этой новой таблице,
которые были у старой таблицы: привилегии, ограничения, значения по умолчанию,
индексы и т.д. Привилегии особенно важны для того, чтобы убедиться,
что они совпадают, так что все пользователи таблицы продолжат
работать после конвертации.
Обратите внимание, что первичные ключи/уникальные индексы не могут быть применены к родительской секции, если ключ секционирования не является его частью. В этом случае это будет работать, однако, вероятно, это не намерение, так как это означало бы, что разрешена только одна строка на значение, и это означало бы, что в каждой дочерней таблице может существовать только 10,000 строк. В этом случае секционирование определенно не нужно. Следующий пример онлайн-секционирования покажет, как обрабатывать ситуацию, когда вам нужен первичный ключ для столбца, который не является частью ключа секционирования.
CREATE TABLE public.original_table ( col1 bigint not null , col2 text not null , col3 timestamptz DEFAULT now() , col4 text) PARTITION BY RANGE (col1); CREATE INDEX ON public.original_table (col1); SELECT partman.create_parent( p_parent_table := 'public.original_table' , p_control := 'col1' , p_interval := '10000' );
\d+ original_table; Partitioned table "public.original_table" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+---------+----------+-------------+--------------+------------- col1 | bigint | | not null | | plain | | | col2 | text | | not null | | extended | | | col3 | timestamp with time zone | | | now() | plain | | | col4 | text | | | | extended | | | Partition key: RANGE (col1) Indexes: "original_table_col1_idx1" btree (col1) "original_table_col1_idx2" btree (col1) Partitions: original_table_p0 FOR VALUES FROM ('0') TO ('10000'), original_table_p10000 FOR VALUES FROM ('10000') TO ('20000'), original_table_p20000 FOR VALUES FROM ('20000') TO ('30000'), original_table_p30000 FOR VALUES FROM ('30000') TO ('40000'), original_table_p40000 FOR VALUES FROM ('40000') TO ('50000'), original_table_default DEFAULT
Если вы случайно использовали столбцы IDENTITY или создали новую последовательность для новой секционированной таблицы, вы захотите получить значение этих старых последовательностей и сбросить новые последовательности, чтобы начать с этих старых значений. Некоторые советы по этому поводу приведены в разделе «Онлайн-секционирование» ниже. Если вы просто использовали ту же самую последовательность в новой секционированной таблице, вы должны быть в порядке.
Теперь можно использовать процедуру partition_data_proc()
для миграции наших данных из старой таблицы в новую.
И мы собираемся сделать это в инкрементах по 1 000 строк против
интервала в 10 000, который установлен для набора секций. Значение пакета
используется, чтобы сообщить ему, сколько раз пройти через заданный
интервал; значение по умолчанию 1 создает только одну дочернюю
таблицу. Поскольку мы хотим разделить все данные, просто дайте
ему число, равное или большее ожидаемому количеству дочерних таблиц.
У этой процедуры есть опция, где вы можете указать ей источник данных,
что и позволит нам мигрировать данные из старой таблицы. Без установки этой опции, она
пытается очистить данные из секции DEFAULT (что
мы увидим на следующем примере).
keith=# CALL partman.partition_data_proc( p_parent_table := 'public.original_table' , p_loop_count := 200 , p_interval := '1000' , p_source_table := 'public.old_nonpartitioned_table' ); NOTICE: Loop: 1, Rows moved: 1000 NOTICE: Loop: 2, Rows moved: 1000 NOTICE: Loop: 3, Rows moved: 1000 NOTICE: Loop: 4, Rows moved: 1000 NOTICE: Loop: 5, Rows moved: 1000 NOTICE: Loop: 6, Rows moved: 1000 NOTICE: Loop: 7, Rows moved: 1000 NOTICE: Loop: 8, Rows moved: 1000 NOTICE: Loop: 9, Rows moved: 1000 NOTICE: Loop: 10, Rows moved: 999 NOTICE: Loop: 11, Rows moved: 1000 NOTICE: Loop: 12, Rows moved: 1000 [...] NOTICE: Loop: 99, Rows moved: 1000 NOTICE: Loop: 100, Rows moved: 1000 NOTICE: Loop: 101, Rows moved: 1 NOTICE: Total rows moved: 100000 NOTICE: Ensure to VACUUM ANALYZE the parent (and source table if used) after partitioning data VACUUM ANALYZE public.original_table;
Снова, выполнение коммитов в меньших партиях, как это, может избежать транзакций с огромным количеством строк и длительным временем выполнения, когда вы разбиваете таблицу, которая может содержать миллиарды строк. Всегда рекомендуется избегать длительных транзакций, чтобы позволить процессу автovacуума Tantor SE работать эффективно для остальной части базы данных. Однако выполнение меньших партий за цикл может привести к тому, что процесс разбивки данных займет больше времени. Вам придется найти баланс между нагрузкой на вашу базу данных и требуемым временем.
Использование ПРОЦЕДУРЫ partition_data_proc()
против ФУНКЦИИ partition_data_id()
позволяет
выполнять эти пакеты коммитов. Функции в Tantor SE всегда выполняются
полностью в одной транзакции, даже если вы можете указать ей
делать вещи пакетами внутри функции.
Теперь, если мы проверим нашу исходную таблицу, она будет пуста
SELECT count(*) FROM old_nonpartitioned_table; count ------- 0 (1 row)
И новая, секционированная таблица с исходным именем содержит все данные и созданные дочерние таблицы
SELECT count(*) FROM original_table; count -------- 100000 (1 row) \d+ public.original_table Partitioned table "public.original_table" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+---------+----------+-------------+--------------+------------- col1 | bigint | | not null | | plain | | | col2 | text | | not null | | extended | | | col3 | timestamp with time zone | | | now() | plain | | | col4 | text | | | | extended | | | Partition key: RANGE (col1) Indexes: "original_table_col1_idx" btree (col1) Partitions: original_table_p0 FOR VALUES FROM ('0') TO ('10000'), original_table_p10000 FOR VALUES FROM ('10000') TO ('20000'), original_table_p100000 FOR VALUES FROM ('100000') TO ('110000'), original_table_p20000 FOR VALUES FROM ('20000') TO ('30000'), original_table_p30000 FOR VALUES FROM ('30000') TO ('40000'), original_table_p40000 FOR VALUES FROM ('40000') TO ('50000'), original_table_p50000 FOR VALUES FROM ('50000') TO ('60000'), original_table_p60000 FOR VALUES FROM ('60000') TO ('70000'), original_table_p70000 FOR VALUES FROM ('70000') TO ('80000'), original_table_p80000 FOR VALUES FROM ('80000') TO ('90000'), original_table_p90000 FOR VALUES FROM ('90000') TO ('100000'), original_table_default DEFAULT SELECT count(*) FROM original_table_p10000; count ------- 10000 (1 row)
Теперь вы можете начать использовать вашу таблицу так же, как вы делали это раньше!
F.42.6.3.2. Онлайн-секционирование #
Иногда невозможно отключить таблицу на длительное время для ее миграции в секционированную таблицу. Ниже представлен один из способов, позволяющих выполнить это в режиме онлайн. Он не такой гибкий, как офлайн-метод, но должен обеспечить минимальное время простоя и быть в основном незаметным для конечных пользователей таблицы.
Как упоминалось выше, эти методы не учитывают наличие внешних ключей К исходной таблице. Вы можете создать внешние ключи ИЗ исходной таблицы на новую секционированную таблицу, и все должно работать как ожидается. Однако, если у вас есть внешние ключи, входящие в таблицу, я не знаю о существовании какого-либо метода миграции, который не требует простоя для удаления исходных внешних ключей и их повторного создания для новой секционированной таблицы.
Это будет ежедневный набор секций по времени с последовательностью IDENTITY в качестве первичного ключа
CREATE TABLE public.original_table ( col1 bigint not null PRIMARY KEY GENERATED ALWAYS AS IDENTITY , col2 text not null , col3 timestamptz DEFAULT now() not null , col4 text); CREATE INDEX CONCURRENTLY ON public.original_table (col3); INSERT INTO public.original_table (col2, col3, col4) VALUES ('stuff', generate_series(now() - '1 week'::interval, now(), '5 minutes'::interval), 'stuff');
Процесс по-прежнему вначале такой же, как и в офлайн-методе, поскольку вы не можете превратить существующую таблицу в родительскую таблицу набора секций. Однако критически важно, чтобы все ограничения, привилегии, значения по умолчанию и любые другие свойства были применены к новой родительской таблице, прежде чем вы перейдете к следующему шагу переименования имен таблиц.
CREATE TABLE public.new_partitioned_table ( col1 bigint not null GENERATED BY DEFAULT AS IDENTITY , col2 text not null , col3 timestamptz DEFAULT now() not null , col4 text) PARTITION BY RANGE (col3); CREATE INDEX ON public.new_partitioned_table (col3);
Вы заметите, что я не установил “col1” в качестве первичного ключа. Это потому, что мы не можем.
CREATE TABLE public.new_partitioned_table ( col1 bigint not null PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY , col2 text not null , col3 timestamptz DEFAULT now() not null , col4 text) PARTITION BY RANGE (col3); ERROR: unique constraint on partitioned table must include all partitioning columns DETAIL: PRIMARY KEY constraint on table "new_partitioned_table" lacks column "col3" which is part of the partition key.
pg_partman имеет механизм применения первичных/уникальных
ключей, которые не являются частью столбца секционирования. Просто имейте в виду,
что они НЕ применяются ко всему набору секций;
только для отдельной секции. Это делается с помощью
шаблонной таблицы. И чтобы гарантировать, что ключи применяются при создании
начальных дочерних таблиц, эту шаблонную таблицу необходимо
предварительно создать и предоставить ее имя
при вызове create_parent()
. Мы собираемся использовать
исходную таблицу в качестве основы и дать имя, похожее на
это, чтобы оно имело смысл после переименования позже.
Еще одно важное замечание заключается в том, что мы изменили столбец IDENTITY с GENERATED ALWAYS на GENERATED BY DEFAULT. Это связано с тем, что нам нужно переместить существующие значения для этого столбца идентификатора на свое место. ALWAYS обычно предотвращает ввод значений вручную.
CREATE TABLE public.original_table_template (LIKE public.original_table); ALTER TABLE public.original_table_template ADD PRIMARY KEY (col1);
Если вы не создадите заранее шаблонную таблицу, pg_partman всегда создаст ее для вас в той же схеме, в которую было установлено расширение. Вы можете увидеть ее имя, посмотрев на столбец template_table
в таблице part_config
. Однако, если вы добавите индекс в эту шаблонную таблицу после вызова create_parent()
, уже существующие дочерние таблицы не получат этот индекс, и вам придется вернуться и сделать это вручную. Однако, любые новые дочерние таблицы, созданные после этого, будут иметь этот индекс.
Сложность здесь заключается в том, что мы пока не можем иметь дочерние таблицы в наборе секций, которые соответствуют данным, уже существующим в исходной таблице. Это потому, что мы собираемся добавить старую таблицу в качестве таблицы по умолчанию в нашу новую таблицу секций. Если таблица по умолчанию содержит любые данные, которые соответствуют ограничениям текущей дочерней таблицы, Tantor SE не позволит добавить эту таблицу. Поэтому, с вызовом create_parent()
ниже, мы начнем набор секций задолго до данных, которые мы вставили, и отключим автоматическое создание таблицы по умолчанию. В вашем случае вам нужно будет просмотреть текущий набор данных и выбрать значение, значительно опережающее текущий рабочий набор данных, который может быть вставлен до того, как вы сможете выполнить процесс замены имени таблицы ниже. Мы также установим значение premake на низкое значение, чтобы избежать необходимости переименовывать слишком много дочерних таблиц позже. Позже мы увеличим premake обратно до значения по умолчанию (или вы можете установить его на любое требуемое значение).
SELECT min(col3), max(col3) FROM original_table; min | max -------------------------------+------------------------------- 2023-03-21 11:09:31.980586-07 | 2023-03-28 11:09:31.980586-07
SELECT partman.create_parent( p_parent_table := 'public.new_partitioned_table' , p_control := 'col3' , p_interval := '1 day' , p_template_table:= 'public.original_table_template' , p_premake := 1 , p_start_partition := (CURRENT_TIMESTAMP+'2 days'::interval)::text , p_default_table := false );
Состояние новой секционированной таблицы теперь должно выглядеть примерно так. Текущая дата, когда был написан этот HowTo, дана для справки:
SELECT CURRENT_TIMESTAMP; current_timestamp ------------------------------- 2023-03-28 11:23:55.971402-07 \d+ new_partitioned_table; Partitioned table "public.new_partitioned_table" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+----------------------------------+----------+-------------+--------------+------------- col1 | bigint | | not null | generated by default as identity | plain | | | col2 | text | | not null | | extended | | | col3 | timestamp with time zone | | not null | now() | plain | | | col4 | text | | | | extended | | | Partition key: RANGE (col3) Indexes: "new_partitioned_table_col3_idx" btree (col3) Partitions: new_partitioned_table_p20230330 FOR VALUES FROM ('2023-03-30 00:00:00-07') TO ('2023-03-31 00:00:00-07')
Вам нужно будет обновить таблицу part_config
, чтобы она содержала исходное имя таблицы. Вы также можете обновить таблицу шаблона, если не создавали ее вручную, просто убедитесь, что вы переименовали таблицу и обновили таблицу part_config
. Мы также сбросим premake до значения по умолчанию.
UPDATE partman.part_config SET parent_table = 'public.original_table', premake = 4 WHERE parent_table = 'public.new_partitioned_table'; UPDATE 1
Следующий шаг, который на самом деле представляет собой несколько шагов в одной транзакции, - это единственное значительное прерывание, которое нужно предвидеть.
НАЧАЛО транзакции
Возьмите эксклюзивную блокировку на исходной таблице и новой таблице, чтобы гарантировать отсутствие промежутков, в которых данные могут быть неправильно направлены
Если используется столбец IDENTITY, получите исходное последнее значение
Переименуйте исходную таблицу в имя таблицы DEFAULT для набора секций
Если используется столбец IDENTITY, удалите IDENTITY из старой таблицы
Переименуйте новую таблицу в имя исходной таблицы и переименуйте дочерние таблицы и последовательность, чтобы они соответствовали.
Если используется столбец IDENTITY, сбросьте идентификатор новой таблицы до последнего значения, чтобы любые новые вставки продолжились с того места, где остановилась последовательность старой таблицы.
Добавьте исходную таблицу как DEFAULT для набора секций
COMMIT транзакция
Если вы используете столбец IDENTITY, важно получить его последнее значение, пока исходная таблица заблокирована и ПЕРЕД тем, как вы удалите старую идентичность. Затем используйте это возвращенное значение в операторе для СБРОСА столбца IDENTITY в новой таблице. Возможно, вам потребуется немного увеличить возвращенное значение, чтобы опередить текущее использование таблицы, поэтому это может быть немного сложно с очень загруженной таблицей, особенно если ваши значения последовательности должны оставаться непрерывными. Запрос для получения этого значения приведен в SQL-операторах ниже. Если вы не используете IDENTITY, вы можете просто игнорировать эти шаги.
Если в любой момент возникнет проблема с одним из этих мини-шагов, просто выполните ROLLBACK и вы сможете вернуться к предыдущему состоянию и ваша исходная таблица должна работать так, как раньше.
BEGIN; LOCK TABLE public.original_table IN ACCESS EXCLUSIVE MODE; LOCK TABLE public.new_partitioned_table IN ACCESS EXCLUSIVE MODE; SELECT max(col1)+1 FROM public.original_table; ALTER TABLE public.original_table RENAME TO original_table_default; -- IF using an IDENTITY column ALTER TABLE public.original_table_default ALTER col1 DROP IDENTITY; ALTER TABLE public.new_partitioned_table RENAME TO original_table; ALTER TABLE public.new_partitioned_table_p20230330 RENAME TO original_table_p20230330; -- IF using an IDENTITY column ALTER SEQUENCE public.new_partitioned_table_col1_seq RENAME TO original_table_col1_seq; -- IF using an IDENTITY column ALTER TABLE public.original_table ALTER col1 RESTART WITH <<<VALUE OBTAINED ABOVE>>>; ALTER TABLE public.original_table ATTACH PARTITION public.original_table_default DEFAULT;
COMMIT; or ROLLBACK;
После выполнения COMMIT, новая секционированная таблица должна теперь заменить оригинальную несекционированную таблицу. И если все свойства были применены к новой таблице, она должна работать без каких-либо проблем. Любые новые данные, которые поступают, должны либо идти в соответствующую дочернюю таблицу, либо, если она еще не существует, они должны идти в DEFAULT. Последнее не является проблемой, так как…
Следующим шагом будет секционирование данных из значения по умолчанию. Вы НЕ должны оставлять данные в наборе секций по умолчанию на любой протяженности времени и особенно оставлять значительное количество данных. Если вы посмотрите на ограничение, которое существует на секции по умолчанию, это в основном анти-ограничение всех других дочерних таблиц. И когда добавляется новая дочерняя таблица, Tantor SE управляет обновлением этого ограничения по умолчанию по мере необходимости. Но он должен проверить, есть ли какие-либо данные, которые должны принадлежать этой новой дочерней таблице, уже существуют в значении по умолчанию. Если он найдет такие, он завершится с ошибкой. Но что более важно, он должен проверить КАЖДУЮ запись в значении по умолчанию, что может занять довольно много времени, даже с индексом, если есть миллиарды строк. Во время этой проверки на весь набор секций налагается эксклюзивная блокировка.
Функция partition_data_proc()
может обрабатывать перемещение
данных из значения по умолчанию. Однако она не может перемещать данные в
любом интервале, меньшем, чем интервал секционирования, при перемещении
данных из значения DEFAULT. Это связано с тем, что было только что
упомянуто: вы не можете добавить дочернюю таблицу в набор секций, если
ограничение новой дочерней таблицы охватывает данные, которые уже
существуют в значении по умолчанию.
pg_partman обрабатывает это, сначала перемещая все данные для данной дочерней таблицы во временную таблицу, затем создавая дочернюю таблицу, а затем перемещая данные из временной таблицы в новую дочернюю таблицу. Поскольку мы перемещаем данные из DEFAULT и мы не можем использовать меньший интервал, единственный параметр, который нам нужно передать, это размер пакета. По умолчанию размер пакета 1 будет создавать только одну дочернюю таблицу, а затем остановится. Если нужно переместить все данные за один вызов, просто передайте значение, достаточно большое, чтобы охватить ожидаемое количество дочерних таблиц. Однако, при работе с активной таблицей и МНОГО строками, это потенциально может генерировать МНОГО файлов WAL, особенно учитывая, что этот метод удваивает количество записей по сравнению с оффлайн методом (default -> temp -> child table). Поэтому, если вам важно контролировать использование диска, просто укажите меньшее значение пакета и дайте Tantor SE некоторое время для выполнения нескольких CHECKPOINT и очистки собственного WAL перед переходом к следующему пакету.
CALL partman.partition_data_proc('public.original_table', p_loop_count := 200); NOTICE: Loop: 1, Rows moved: 134 NOTICE: Loop: 2, Rows moved: 288 NOTICE: Loop: 3, Rows moved: 288 NOTICE: Loop: 4, Rows moved: 288 NOTICE: Loop: 5, Rows moved: 288 NOTICE: Loop: 6, Rows moved: 288 NOTICE: Loop: 7, Rows moved: 288 NOTICE: Loop: 8, Rows moved: 155 NOTICE: Total rows moved: 2017 NOTICE: Ensure to VACUUM ANALYZE the parent (and source table if used) after partitioning data VACUUM ANALYZE original_table; VACUUM
Если вы ранее использовали столбец IDENTITY с GENERATED ALWAYS, вам потребуется изменить идентификатор в секционированной таблице обратно на тот, что был до текущего значения BY DEFAULT
ALTER TABLE public.original_table ALTER col1 SET GENERATED ALWAYS;
Теперь дважды проверьте, что создание дочерней таблицы было выполнено как ожидалось. Здесь не хватает одного, если вы внимательно посмотрите, но мы обсудим это ниже.
\d+ original_table Partitioned table "public.original_table" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+------------------------------+----------+-------------+--------------+------------- col1 | bigint | | not null | generated always as identity | plain | | | col2 | text | | not null | | extended | | | col3 | timestamp with time zone | | not null | now() | plain | | | col4 | text | | | | extended | | | Partition key: RANGE (col3) Indexes: "new_partitioned_table_col3_idx" btree (col3) Partitions: original_table_p20230321 FOR VALUES FROM ('2023-03-21 00:00:00-07') TO ('2023-03-22 00:00:00-07'), original_table_p20230322 FOR VALUES FROM ('2023-03-22 00:00:00-07') TO ('2023-03-23 00:00:00-07'), original_table_p20230323 FOR VALUES FROM ('2023-03-23 00:00:00-07') TO ('2023-03-24 00:00:00-07'), original_table_p20230324 FOR VALUES FROM ('2023-03-24 00:00:00-07') TO ('2023-03-25 00:00:00-07'), original_table_p20230325 FOR VALUES FROM ('2023-03-25 00:00:00-07') TO ('2023-03-26 00:00:00-07'), original_table_p20230326 FOR VALUES FROM ('2023-03-26 00:00:00-07') TO ('2023-03-27 00:00:00-07'), original_table_p20230327 FOR VALUES FROM ('2023-03-27 00:00:00-07') TO ('2023-03-28 00:00:00-07'), original_table_p20230328 FOR VALUES FROM ('2023-03-28 00:00:00-07') TO ('2023-03-29 00:00:00-07'), original_table_p20230330 FOR VALUES FROM ('2023-03-30 00:00:00-07') TO ('2023-03-31 00:00:00-07'), original_table_default DEFAULT
И теперь, чтобы гарантировать, что все новые данные поступают в соответствующие дочерние таблицы, а не по умолчанию, выполните обслуживание новой секционированной таблицы, чтобы убедиться, что текущие предварительно созданные секции созданы
SELECT partman.run_maintenance('public.original_table'); \d+ original_table Partitioned table "public.original_table" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+------------------------------+----------+-------------+--------------+------------- col1 | bigint | | not null | generated always as identity | plain | | | col2 | text | | not null | | extended | | | col3 | timestamp with time zone | | not null | now() | plain | | | col4 | text | | | | extended | | | Partition key: RANGE (col3) Indexes: "new_partitioned_table_col3_idx" btree (col3) Partitions: original_table_p20230321 FOR VALUES FROM ('2023-03-21 00:00:00-07') TO ('2023-03-22 00:00:00-07'), original_table_p20230322 FOR VALUES FROM ('2023-03-22 00:00:00-07') TO ('2023-03-23 00:00:00-07'), original_table_p20230323 FOR VALUES FROM ('2023-03-23 00:00:00-07') TO ('2023-03-24 00:00:00-07'), original_table_p20230324 FOR VALUES FROM ('2023-03-24 00:00:00-07') TO ('2023-03-25 00:00:00-07'), original_table_p20230325 FOR VALUES FROM ('2023-03-25 00:00:00-07') TO ('2023-03-26 00:00:00-07'), original_table_p20230326 FOR VALUES FROM ('2023-03-26 00:00:00-07') TO ('2023-03-27 00:00:00-07'), original_table_p20230327 FOR VALUES FROM ('2023-03-27 00:00:00-07') TO ('2023-03-28 00:00:00-07'), original_table_p20230328 FOR VALUES FROM ('2023-03-28 00:00:00-07') TO ('2023-03-29 00:00:00-07'), original_table_p20230330 FOR VALUES FROM ('2023-03-30 00:00:00-07') TO ('2023-03-31 00:00:00-07'), original_table_p20230331 FOR VALUES FROM ('2023-03-31 00:00:00-07') TO ('2023-04-01 00:00:00-07'), original_table_p20230401 FOR VALUES FROM ('2023-04-01 00:00:00-07') TO ('2023-04-02 00:00:00-07'), original_table_default DEFAULT
До этого, в зависимости от созданных дочерних таблиц и поступающих новых данных, некоторые данные могли все еще поступать по умолчанию. Вы можете проверить это с помощью функции, которая поставляется с pg_partman:
SELECT * FROM partman.check_default(p_exact_count := true);
Если вы не передаете “true” в функцию, она просто возвращает 1 или 0, чтобы указать, есть ли какие-либо данные в любом значении по умолчанию. Это удобно для мониторинга ситуаций и это также может быть быстрее, поскольку оно прекращает проверку, как только оно находит данные в любой дочерней таблице. Однако, в этом случае мы хотим видеть точно, в какой ситуации мы находимся, поэтому передача true даст нам точное количество оставшихся строк в значении по умолчанию.
Вы также заметите, что в приведенном выше наборе отсутствует дочерняя таблица (29 марта 2023 года). Это потому, что мы установили таблицу секций на 2 дня вперед, и у нас не было данных для этой даты в исходной таблице. Вы можете исправить это одним из двух способов:
Дождитесь, пока данные за этот период времени будут вставлены, и как только вы убедитесь, что интервал завершен, разделите данные из DEFAULT таким же образом, как мы делали ранее.
Запустите функцию
partition_gap_fill()
для немедленного заполнения любых пропусков:
SELECT * FROM partman.partition_gap_fill('public.original_table'); partition_gap_fill -------------------- 1 (1 row) keith=# \d+ original_table Partitioned table "public.original_table" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+------------------------------+----------+-------------+--------------+------------- col1 | bigint | | not null | generated always as identity | plain | | | col2 | text | | not null | | extended | | | col3 | timestamp with time zone | | not null | now() | plain | | | col4 | text | | | | extended | | | Partition key: RANGE (col3) Indexes: "new_partitioned_table_col3_idx" btree (col3) Partitions: original_table_p20230321 FOR VALUES FROM ('2023-03-21 00:00:00-07') TO ('2023-03-22 00:00:00-07'), original_table_p20230322 FOR VALUES FROM ('2023-03-22 00:00:00-07') TO ('2023-03-23 00:00:00-07'), original_table_p20230323 FOR VALUES FROM ('2023-03-23 00:00:00-07') TO ('2023-03-24 00:00:00-07'), original_table_p20230324 FOR VALUES FROM ('2023-03-24 00:00:00-07') TO ('2023-03-25 00:00:00-07'), original_table_p20230325 FOR VALUES FROM ('2023-03-25 00:00:00-07') TO ('2023-03-26 00:00:00-07'), original_table_p20230326 FOR VALUES FROM ('2023-03-26 00:00:00-07') TO ('2023-03-27 00:00:00-07'), original_table_p20230327 FOR VALUES FROM ('2023-03-27 00:00:00-07') TO ('2023-03-28 00:00:00-07'), original_table_p20230328 FOR VALUES FROM ('2023-03-28 00:00:00-07') TO ('2023-03-29 00:00:00-07'), original_table_p20230329 FOR VALUES FROM ('2023-03-29 00:00:00-07') TO ('2023-03-30 00:00:00-07'), original_table_p20230330 FOR VALUES FROM ('2023-03-30 00:00:00-07') TO ('2023-03-31 00:00:00-07'), original_table_p20230331 FOR VALUES FROM ('2023-03-31 00:00:00-07') TO ('2023-04-01 00:00:00-07'), original_table_p20230401 FOR VALUES FROM ('2023-04-01 00:00:00-07') TO ('2023-04-02 00:00:00-07'), original_table_default DEFAULT
Вы можете видеть, что создана недостающая таблица для 29 марта.
На этом этапе ваша новая секционированная таблица уже должна была использоваться и работать без каких-либо проблем!
INSERT INTO original_table (col2, col3, col4) VALUES ('newstuff', now(), 'newstuff'); INSERT INTO original_table (col2, col3, col4) VALUES ('newstuff', now(), 'newstuff'); SELECT * FROM original_table ORDER BY col1 DESC limit 5;
F.42.6.4. Отмена нативного секционирования #
Так же как обычная таблица не может быть преобразована в нативно секционированную таблицу, то же самое верно и в обратном случае. Чтобы отменить нативное секционирование, необходимо переместить данные в новую таблицу. Возможно, есть способ сделать это в онлайн-режиме, но на данный момент у нас нет такого метода. Если кто-то может предложить метод или хочет, чтобы я изучил вопрос подробнее, пожалуйста, создайте запрос на Github. Ниже приведен метод, показывающий как отменить ежедневное секционирование, приведенное в примере выше, включая обработку столбца IDENTITY, при необходимости.
Сначала мы создаем новую таблицу для миграции данных. Можно установить
первичный ключ или любые уникальные индексы, которые были созданы на
шаблоне. Если есть какие-либо столбцы идентификаторов, они должны установить
метод на GENERATED BY DEFAULT
, так как мы
будем добавлять значения вручную в рамках миграции. Если
это должно быть ALWAYS
, это можно изменить
позже.
Если эта таблица будет использоваться так же, как и предыдущая секционированная таблица, убедитесь, что все привилегии, ограничения и индексы созданы для этой таблицы также. Создание индексов и ограничений можно отложить до тех пор, пока данные не будут перемещены, чтобы ускорить миграцию.
CREATE TABLE public.new_regular_table ( col1 bigint not null GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY , col2 text not null , col3 timestamptz DEFAULT now() not null , col4 text); CREATE INDEX ON public.new_regular_table (col3);
Теперь можно использовать процедуру undo_partition_proc()
для перемещения данных из нашей секционированной таблицы в
обычную таблицу. Мы даже можем выбрать меньший размер интервала для
этого, чтобы уменьшить время выполнения транзакции для каждой партии.
Размер партии по умолчанию равен 1, что означает выполнение заданного
интервала один раз. Мы хотим отменить все с одним
вызовом, поэтому передаем число, достаточно большое, чтобы пройти через все
партии. Оно остановится, когда все данные будут перемещены, даже если
вы передали больший номер партии. Нам также не нужно сохранять старые
дочерние таблицы, когда они пусты, поэтому это установлено как false.
Смотрите документацию для получения дополнительной информации о других вариантах
функций/процедур отмены.
CALL partman.undo_partition_proc( p_parent_table := 'public.original_table' , p_target_table := 'public.new_regular_table' , p_interval := '1 hour'::text , p_loop_count := 500 , p_keep_table := false); NOTICE: Moved 13 row(s) to the target table. Removed 1 partitions. NOTICE: Batch: 1, Partitions undone this batch: 1, Rows undone this batch: 13 NOTICE: Moved 13 row(s) to the target table. Removed 0 partitions. NOTICE: Batch: 2, Partitions undone this batch: 0, Rows undone this batch: 13 NOTICE: Moved 13 row(s) to the target table. Removed 0 partitions. NOTICE: Batch: 3, Partitions undone this batch: 0, Rows undone this batch: 13 NOTICE: Moved 13 row(s) to the target table. Removed 0 partitions. [...] NOTICE: Batch: 160, Partitions undone this batch: 0, Rows undone this batch: 13 NOTICE: Moved 12 row(s) to the target table. Removed 0 partitions. NOTICE: Batch: 161, Partitions undone this batch: 0, Rows undone this batch: 12 NOTICE: Moved 2 row(s) to the target table. Removed 1 partitions. NOTICE: Batch: 162, Partitions undone this batch: 1, Rows undone this batch: 2 NOTICE: Moved 0 row(s) to the target table. Removed 4 partitions. NOTICE: Total partitions undone: 13, Total rows moved: 2019 NOTICE: Ensure to VACUUM ANALYZE the old parent and target table after undo has finished VACUUM ANALYZE original_table; VACUUM ANALYZE new_regular_table;
Теперь имена объектов могут быть переставлены, а последовательность идентификаторов сброшена и метод изменен при необходимости. Обязательно запомните исходное значение последовательности и используйте его при сбросе.
SELECT max(col1)+1 FROM public.new_regular_table; ALTER TABLE original_table RENAME TO old_partitioned_table; ALTER SEQUENCE original_table_col1_seq RENAME TO old_partitioned_table_col1_seq; ALTER TABLE new_regular_table RENAME TO original_table; ALTER SEQUENCE new_regular_table_col1_seq RENAME TO original_table_col1_seq; ALTER TABLE public.original_table ALTER col1 RESTART WITH <<<VALUE OBTAINED ABOVE>>>; ALTER TABLE public.original_table ALTER col1 SET GENERATED ALWAYS;
INSERT INTO original_table (col2, col3, col4) VALUES ('newstuff', now(), 'newstuff'); INSERT INTO original_table (col2, col3, col4) VALUES ('newstuff', now(), 'newstuff'); SELECT * FROM original_table ORDER BY col1 DESC limit 5;
F.42.7. Миграция существующего набора секций в PG Partition Manager #
Этот документ является пособием по миграции существующего набора таблиц с нативным секционированием для использования pg_partman. Для миграции набора секций на основе триггеров на нативное секционирование, см. главу Раздел F.42.8 для получения помощи в этом процессе. Затем вы можете вернуться к этому документу, чтобы управлять этим набором секций с помощью pg_partman.
Как всегда, настоятельно рекомендуется сначала протестировать эту миграцию на системе разработки. Полный набор данных для этого не требуется, достаточно только схемы с меньшим набором данных в каждом дочернем элементе, чтобы убедиться в его правильной работе.
Следующие таблицы являются примерами, которые мы будем использовать:
CREATE TABLE tracking.hits_time (id int GENERATED BY DEFAULT AS IDENTITY NOT NULL, start timestamptz DEFAULT now() NOT NULL) PARTITION BY RANGE (start); CREATE INDEX ON tracking.hits_time (start); CREATE TABLE tracking.hits_time2023_02_26 partition of tracking.hits_time FOR VALUES FROM ('2023-02-26'::timestamptz) TO ('2023-03-05'::timestamptz); CREATE TABLE tracking.hits_time2023_03_05 partition of tracking.hits_time FOR VALUES FROM ('2023-03-05'::timestamptz) TO ('2023-03-12'::timestamptz); CREATE TABLE tracking.hits_time2023_03_12 partition of tracking.hits_time FOR VALUES FROM ('2023-03-12'::timestamptz) TO ('2023-03-19'::timestamptz); INSERT INTO tracking.hits_time VALUES (1, generate_series('2023-02-27 01:00:00'::timestamptz, '2023-03-04 23:00:00'::timestamptz, '1 hour'::interval)); INSERT INTO tracking.hits_time VALUES (2, generate_series('2023-03-06 01:00:00'::timestamptz, '2023-03-11 23:00:00'::timestamptz, '1 hour'::interval)); INSERT INTO tracking.hits_time VALUES (3, generate_series('2023-03-12 01:00:00'::timestamptz, '2023-03-18 23:00:00'::timestamptz, '1 hour'::interval)); \d+ tracking.hits_time Partitioned table "tracking.hits_time" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+----------------------------------+---------+-------------+--------------+------------- id | integer | | not null | generated by default as identity | plain | | | start | timestamp with time zone | | not null | now() | plain | | | Partition key: RANGE (start) Indexes: "hits_time_start_idx" btree (start) Partitions: tracking.hits_time20230226 FOR VALUES FROM ('2023-02-26 00:00:00-05') TO ('2023-03-05 00:00:00-05'), tracking.hits_time20230305 FOR VALUES FROM ('2023-03-05 00:00:00-05') TO ('2023-03-12 00:00:00-05'), tracking.hits_time20230312 FOR VALUES FROM ('2023-03-12 00:00:00-05') TO ('2023-03-19 00:00:00-04')
CREATE TABLE tracking.hits_id (id int GENERATED BY DEFAULT AS IDENTITY NOT NULL, start timestamptz DEFAULT now() NOT NULL) PARTITION BY RANGE (id); CREATE INDEX ON tracking.hits_id (id); CREATE TABLE tracking.hits_id1000 partition of tracking.hits_id FOR VALUES FROM (1000) TO (2000); CREATE TABLE tracking.hits_id2000 partition of tracking.hits_id FOR VALUES FROM (2000) TO (3000); CREATE TABLE tracking.hits_id3000 partition of tracking.hits_id FOR VALUES FROM (3000) TO (4000); INSERT INTO tracking.hits_id VALUES (generate_series(1000,1999), now()); INSERT INTO tracking.hits_id VALUES (generate_series(2000,2999), now()); INSERT INTO tracking.hits_id VALUES (generate_series(3000,3999), now()); \d+ tracking.hits_id Partitioned table "tracking.hits_id" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+----------------------------------+---------+-------------+--------------+------------- id | integer | | not null | generated by default as identity | plain | | | start | timestamp with time zone | | not null | now() | plain | | | Partition key: RANGE (id) Indexes: "hits_id_id_idx" btree (id) Partitions: tracking.hits_id1000 FOR VALUES FROM (1000) TO (2000), tracking.hits_id2000 FOR VALUES FROM (2000) TO (3000), tracking.hits_id3000 FOR VALUES FROM (3000) TO (4000)
CREATE TABLE tracking.hits_stufftime (id int GENERATED BY DEFAULT AS IDENTITY NOT NULL, start timestamptz DEFAULT now() NOT NULL) PARTITION BY RANGE (start); CREATE INDEX ON tracking.hits_stufftime (start); CREATE TABLE tracking.hits_stufftimeaa partition of tracking.hits_stufftime FOR VALUES FROM ('2023-01-01'::timestamptz) TO ('2023-01-08'::timestamptz); CREATE TABLE tracking.hits_stufftimebb partition of tracking.hits_stufftime FOR VALUES FROM ('2023-01-08'::timestamptz) TO ('2023-01-15'::timestamptz); CREATE TABLE tracking.hits_stufftimecc partition of tracking.hits_stufftime FOR VALUES FROM ('2023-01-15'::timestamptz) TO ('2023-01-22'::timestamptz); INSERT INTO tracking.hits_stufftime VALUES (1, generate_series('2023-01-02 01:00:00'::timestamptz, '2023-01-06 23:00:00'::timestamptz, '1 hour'::interval)); INSERT INTO tracking.hits_stufftime VALUES (2, generate_series('2023-01-09 01:00:00'::timestamptz, '2023-01-13 23:00:00'::timestamptz, '1 hour'::interval)); INSERT INTO tracking.hits_stufftime VALUES (3, generate_series('2023-01-15 01:00:00'::timestamptz, '2023-01-20 23:00:00'::timestamptz, '1 hour'::interval)); \d+ tracking.hits_stufftime Partitioned table "tracking.hits_stufftime" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+----------------------------------+---------+-------------+--------------+------------- id | integer | | not null | generated by default as identity | plain | | | start | timestamp with time zone | | not null | now() | plain | | | Partition key: RANGE (start) Indexes: "hits_stufftime_start_idx" btree (start) Partitions: tracking.hits_stufftimeaa FOR VALUES FROM ('2023-01-01 00:00:00-05') TO ('2023-01-08 00:00:00-05'), tracking.hits_stufftimebb FOR VALUES FROM ('2023-01-08 00:00:00-05') TO ('2023-01-15 00:00:00-05'), tracking.hits_stufftimecc FOR VALUES FROM ('2023-01-15 00:00:00-05') TO ('2023-01-22 00:00:00-05')
CREATE TABLE tracking.hits_stuffid (id int GENERATED BY DEFAULT AS IDENTITY NOT NULL, start timestamptz DEFAULT now() NOT NULL) PARTITION BY RANGE (id); CREATE INDEX ON tracking.hits_stuffid (id); CREATE TABLE tracking.hits_stuffidaa partition of tracking.hits_stuffid FOR VALUES FROM (1000) TO (2000); CREATE TABLE tracking.hits_stuffidbb partition of tracking.hits_stuffid FOR VALUES FROM (2000) TO (3000); CREATE TABLE tracking.hits_stuffidcc partition of tracking.hits_stuffid FOR VALUES FROM (3000) TO (4000); See below for data inserted \d+ tracking.hits_stuffid Partitioned table "tracking.hits_stuffid" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+----------------------------------+---------+-------------+--------------+------------- id | integer | | not null | generated by default as identity | plain | | | start | timestamp with time zone | | not null | now() | plain | | | Partition key: RANGE (id) Indexes: "hits_stuffid_id_idx" btree (id) Partitions: tracking.hits_stuffidaa FOR VALUES FROM (1000) TO (2000), tracking.hits_stuffidbb FOR VALUES FROM (2000) TO (3000), tracking.hits_stuffidcc FOR VALUES FROM (3000) TO (4000)
F.42.7.1. Шаг 1 #
Отключить вызовы run_maintenance()
Если у вас есть какие-либо секции, которые в настоящее время поддерживаются pg_partman, вы можете уже вызывать это для них. Они должны быть в порядке на протяжении времени, когда выполняется это преобразование. Это сделано для избежания любых проблем с существованием только частичной конфигурации во время преобразования. Если вы используете фоновый рабочий процесс, добавление комментария к параметру “pg_partman_bgw.dbname” в postgresql.conf и затем перезагрузка (SELECT pg_reload_conf();) должны остановить его работу. Если вы запускаете pg_partman на нескольких базах данных в кластере и вы не хотите останавливать их все, можно также просто удалить ту, на которой вы выполняете миграцию, из того же параметра.
F.42.7.2. Шаг 2 #
Остановите все записи в набор секций, который переносится, если это возможно. Если вы не можете сделать это на период времени, необходимый для выполнения конверсии, все следующие шаги должны быть выполнены в одной транзакции, чтобы избежать ошибок записи из-за изменения имен таблиц.
F.42.7.3. Шаг 3 #
Переименуйте существующие секции в соответствии с новой схемой именования. pg_partman использует статический шаблон суффиксов для всех секций, как временных, так и серийных. Все суффиксы начинаются со строки "_p" и перечислены здесь для справки.
_pYYYYMMDD - All time intervals greater than 1 day _pYYYYMMDD_HH24MISS - All time intervals less than 1 day _p##### - Serial/ID partition has a suffix that is the value of the lowest possible entry in that table (Ex: _p10, _p20000, etc)
Вы можете использовать пользовательские форматы datetime_string, чтобы изменить суффикс,
который будут получать дочерние элементы с pg_partman 5.0.1 и выше, но
это не рассматривается в этом руководстве. Здесь рассматривается только то,
как перейти к использованию суффиксов по умолчанию pg_partman, и pg_partman
всегда добавляет _p
в начало, чтобы
отличить границу суффикса.
F.42.7.4. Шаг 3a #
Для преобразования наборов секций на основе времени или последовательности, если у вас уже есть нижнее граничное значение в имени раздела, то это просто вопрос переименования с некоторым форматированием подстроки, поскольку это тот шаблон, который использует сам pg_partman. Предположим, ваша таблица была разделена по неделям, и ваш исходный формат содержал только первый день недели (воскресенье) в имени раздела (как в приведенном выше примере). Ниже вы можете увидеть, что у нас было 3 раздела со старым шаблоном именования “YYYYMMDD” без префикса _p. Посмотрев на приведенный выше список, вы можете увидеть новый недельный шаблон, который использует pg_partman.
Таким образом, запрос, подобный следующему, который сначала извлекает оригинальное
имя, а затем форматирует суффикс, будет работать. Он фактически не
выполняет переименование, а просто генерирует все операторы ALTER TABLE
для вас для всех дочерних таблиц в наборе. Если по какой-то причине
у всех них нет одинакового шаблона, вы можете легко просто перезапустить это,
редактируя вещи по мере необходимости, и
фильтровать полученный список операторов ALTER TABLE соответственно.
Обратите внимание, что функция to_timestamp()
получает
старый шаблон строки даты и времени, а функция to_char()
получает новый шаблон строки.
SELECT format( 'ALTER TABLE %I.%I RENAME TO %I;' , n.nspname , c.relname , substring(c.relname from 1 for 9) || '_p' || to_char(to_timestamp(substring(c.relname from 10), 'YYYY_MM_DD'), 'YYYYMMDD') ) FROM pg_inherits h JOIN pg_class c ON h.inhrelid = c.oid JOIN pg_namespace n ON c.relnamespace = n.oid WHERE h.inhparent = 'tracking.hits_time'::regclass ORDER BY c.relname; ?column? ----------------------------------------------------------------------- ALTER TABLE tracking.hits_time20230226 RENAME TO hits_time_p20230226; ALTER TABLE tracking.hits_time20230305 RENAME TO hits_time_p20230305; ALTER TABLE tracking.hits_time20230312 RENAME TO hits_time_p20230312;
Запуск этого должен переименовать ваши таблицы, чтобы они теперь выглядели так:
table_schema | table_name --------------+--------------------- tracking | hits_time_p20230226 tracking | hits_time_p20230305 tracking | hits_time_p20230312
Если вы переносите набор секций на основе serial/id, и также используете соглашение об именах с наименьшим возможным значением, вы сделаете что-то очень похожее. Все будет так же, как и в приведенном выше примере с временными рядами, за исключением того, что переименование будет немного отличаться. Используя мою вторую примерную таблицу выше, это будет что-то вроде этого.
SELECT format( 'ALTER TABLE %I.%I RENAME TO %I;' , n.nspname , c.relname , substring(c.relname from 1 for 7) || '_p' || substring(c.relname from 8) ) FROM pg_inherits h JOIN pg_class c ON h.inhrelid = c.oid JOIN pg_namespace n ON c.relnamespace = n.oid WHERE h.inhparent = 'tracking.hits_id'::regclass ORDER by c.relname; ?column? ----------------------------------------------------------- ALTER TABLE tracking.hits_id1000 RENAME TO hits_id_p1000; ALTER TABLE tracking.hits_id2000 RENAME TO hits_id_p2000; ALTER TABLE tracking.hits_id3000 RENAME TO hits_id_p3000;
table_schema | table_name --------------+--------------- tracking | hits_id tracking | hits_id_p1000 tracking | hits_id_p2000 tracking | hits_id_p3000
F.42.7.5. Шаг 3b #
Если ваши секционированные наборы названы таким образом, что они по-разному относятся к содержащимся данным или вообще не относятся, вам придется переименовывать их, основываясь на наименьшем значении в контрольной колонке. Я буду использовать пример выше с суффиксами _aa, _bb и _cc.
Мы будем использовать таблицу hits_stufftime
в первом примере, которая имеет дочерние таблицы, не связанные с содержащимися данными.
Этот следующий шаг использует анонимные блоки кода. Это по сути написание кода функции pl/pgsql без создания фактической функции. Просто выполните этот блок кода, настроив значения по мере необходимости, прямо в сессии psql. Обратите внимание, что в Tantor SE недели начинаются с понедельника по умолчанию для функции date_trunc. Однако, допустим, мы хотим, чтобы они начинались с воскресенья, как это было в нашем другом примере секционирования времени, чтобы сохранить последовательность. В этом случае нам нужно сделать немного дополнительных вычислений с датами, чтобы получить этот результат.
DO $rename$ DECLARE v_min_val timestamp; v_row record; v_sql text; BEGIN -- Adjust your parent table name in the for loop query FOR v_row IN SELECT n.nspname AS child_schema, c.relname AS child_table FROM pg_inherits h JOIN pg_class c ON h.inhrelid = c.oid JOIN pg_namespace n ON c.relnamespace = n.oid WHERE h.inhparent = 'tracking.hits_stufftime'::regclass ORDER BY c.relname LOOP v_min_val := NULL; -- Substitute your control column's name here in the min() function v_sql := format('SELECT min(start) FROM %I.%I', v_row.child_schema, v_row.child_table); EXECUTE v_sql INTO v_min_val; -- Adjust the date_trunc here to account for whatever your partitioning interval is. -- This is a trick to have the week begin on sunday since PG defaults to monday v_min_val := date_trunc('week', v_min_val + '1 day'::interval) - '1 day'::interval; -- Build the sql statement to rename the child table v_sql := format('ALTER TABLE %I.%I RENAME TO %I' , v_row.child_schema , v_row.child_table , substring(v_row.child_table from 1 for 14)||'_p'||to_char(v_min_val, 'YYYYMMDD')); -- I just have it outputting the ALTER statement for review. If you'd like this code to actually run it, uncomment the EXECUTE below. RAISE NOTICE '%', v_sql; -- EXECUTE v_sql; END LOOP; END $rename$;
Это выведет что-то вроде этого:
NOTICE: ALTER TABLE tracking.hits_stufftimeaa RENAME TO hits_stufftime_p20230101 NOTICE: ALTER TABLE tracking.hits_stufftimebb RENAME TO hits_stufftime_p20230108 NOTICE: ALTER TABLE tracking.hits_stufftimecc RENAME TO hits_stufftime_p20230115
Я бы рекомендовал запустить его хотя бы один раз с закомментированным окончательным EXECUTE для проверки того, что он генерирует. Если все выглядит хорошо, вы можете раскомментировать EXECUTE и переименовать свои таблицы!
Если у вас есть набор секций serial/id, вычисление правильного значения суффикса можно выполнить, воспользовавшись арифметикой по модулю. Предположим, что в таблице tracking.hits_stuffid следующие значения:
INSERT INTO tracking.hits_stuffid VALUES (generate_series(1100,1294), now()); INSERT INTO tracking.hits_stuffid VALUES (generate_series(2400,2991), now()); INSERT INTO tracking.hits_stuffid VALUES (generate_series(3602,3843), now());
Мы снова будем разделять на 1000, и вы можете видеть, что ни одно из минимальных значений не является таким четким.
DO $rename$ DECLARE v_min_val bigint; v_row record; v_sql text; BEGIN -- Adjust your parent table name in the for loop query FOR v_row IN SELECT n.nspname AS child_schema, c.relname AS child_table FROM pg_inherits h JOIN pg_class c ON h.inhrelid = c.oid JOIN pg_namespace n ON c.relnamespace = n.oid WHERE h.inhparent = 'tracking.hits_stuffid'::regclass ORDER BY c.relname LOOP -- Substitute your control column's name here in the min() function v_sql := format('SELECT min(id) FROM %I.%I', v_row.child_schema, v_row.child_table); EXECUTE v_sql INTO v_min_val; -- Adjust the numerical value after the % to account for whatever your partitioning interval is. v_min_val := v_min_val - (v_min_val % 1000); -- Build the sql statement to rename the child table v_sql := format('ALTER TABLE %I.%I RENAME TO %I' , v_row.child_schema , v_row.child_table , substring(v_row.child_table from 1 for 12)||'_p'||v_min_val::text); -- I just have it outputting the ALTER statement for review. If you'd like this code to actually run it, uncomment the EXECUTE below. RAISE NOTICE '%', v_sql; -- EXECUTE v_sql; END LOOP; END $rename$;
Вы можете видеть, что это создает красивые равномерные имена секций:
NOTICE: ALTER TABLE tracking.hits_stuffidaa RENAME TO hits_stuffid_p1000 NOTICE: ALTER TABLE tracking.hits_stuffidbb RENAME TO hits_stuffid_p2000 NOTICE: ALTER TABLE tracking.hits_stuffidcc RENAME TO hits_stuffid_p3000
F.42.7.6. Шаг 4 #
Настройте pg_partman для управления вашим набором секций.
Я упомянул в начале, что если у вас есть текущие записи, практически все, начиная с Шага 2, должно быть выполнено в одной транзакции. Даже если вам не нужно беспокоиться о записях, я все равно настоятельно рекомендую выполнить шаг 4 в той же транзакции.
Обратите внимание, что мы используем недельное разбиение, но pg_partman знает этот интервал только как период в 7 дней. Допустим, мы мигрируем эту родительскую таблицу 31 марта 2023 года с уже имеющимися дочерними таблицами. Если мы попытаемся просто вызвать функцию create_parent() без указания времени начала набора секций, она предположит, что наша неделя начинается в пятницу, что собьет с толку как имена дочерних таблиц, так и границы интервалов. Мы хотим быть уверены, что наш набор секций настроен на начало недельных секций в воскресенье, поэтому мы используем параметр p_start_partition
, чтобы указать это (26 марта — это воскресенье для недели, начинающейся 31 марта).
Вам может понадобиться или не понадобиться устанавливать параметр начального раздела. Все зависит от используемого интервала, поэтому, пожалуйста, протестируйте все, чтобы убедиться, что оно работает как ожидалось, перед запуском в производственной среде.
SELECT partman.create_parent('tracking.hits_time', 'start', '1 week', p_start_partition := '2023-03-26 00:00:00'); COMMIT;
Этот единичный вызов функции добавит ваш старый набор секций в конфигурацию pg_partman и, возможно, создаст несколько новых дочерних таблиц. pg_partman всегда поддерживает минимальное количество заранее созданных будущих секций (основанных на значении premake в таблице конфигурации или как параметр функции create_parent()), поэтому, если у вас их еще нет, этот шаг позаботится и об этом. Настройте параметры по мере необходимости и ознакомьтесь с документацией для получения дополнительных доступных опций. Этот вызов соответствует временной секции, использованному в примере до сих пор.
\d+ tracking.hits_time Partitioned table "tracking.hits_time" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+----------------------------------+---------+-------------+--------------+------------- id | integer | | not null | generated by default as identity | plain | | | start | timestamp with time zone | | not null | now() | plain | | | Partition key: RANGE (start) Indexes: "hits_time_start_idx" btree (start) Partitions: tracking.hits_time_p20230226 FOR VALUES FROM ('2023-02-26 00:00:00-05') TO ('2023-03-05 00:00:00-05'), tracking.hits_time_p20230305 FOR VALUES FROM ('2023-03-05 00:00:00-05') TO ('2023-03-12 00:00:00-05'), tracking.hits_time_p20230312 FOR VALUES FROM ('2023-03-12 00:00:00-05') TO ('2023-03-19 00:00:00-04'), tracking.hits_time_p20230326 FOR VALUES FROM ('2023-03-26 00:00:00-04') TO ('2023-04-02 00:00:00-04'), tracking.hits_time_p20230402 FOR VALUES FROM ('2023-04-02 00:00:00-04') TO ('2023-04-09 00:00:00-04'), tracking.hits_time_p20230409 FOR VALUES FROM ('2023-04-09 00:00:00-04') TO ('2023-04-16 00:00:00-04'), tracking.hits_time_p20230416 FOR VALUES FROM ('2023-04-16 00:00:00-04') TO ('2023-04-23 00:00:00-04'), tracking.hits_time_p20230423 FOR VALUES FROM ('2023-04-23 00:00:00-04') TO ('2023-04-30 00:00:00-04'), tracking.hits_time_default DEFAULT
По умолчанию значение premake равно 4, поэтому создается 4 недели в будущем. И поскольку это было первоначальное создание, также создаются 4 таблицы в прошлом. Хотя у нас уже были некоторые таблицы, которые покрывали эти прошлые 4 недели, pg_partman увидел, что они там есть, и просто продолжил работу. Если бы мы не передали параметр p_start_partition, Tantor SE на самом деле выдал бы ошибку, так как прошлые таблицы с другими границами, которые он попытался бы создать, пересекли бы границу уже существующей старой таблицы.
Этот последний шаг абсолютно одинаков независимо от типа или интервала партиционирования, поэтому, как только вы дойдете до этого момента, выполните COMMIT, и все готово! Запланируйте выполнение функции run_maintenance() (либо через cron, либо через BGW), и будущая поддержка партиционирования будет выполняться автоматически. Ознакомьтесь с главой Раздел F.42.5 для дополнительных параметров конфигурации.
Я привел примеры времени здесь с набором еженедельного секционирования, начинающегося в воскресенье, чтобы показать, что могут быть некоторые нюансы при вашей миграции на pg_partman, которые нужно учитывать. Если вы делаете что-то более простое, например, ежедневные или серийные целочисленные значения, это может быть не так сложно. Или если вы делаете что-то более сложное, например, интервал в 9 недель, может быть еще больше нюансов, которые могут не казаться очевидными на первый взгляд без обширного тестирования в разработке. Поэтому, пожалуйста, тщательно планируйте свою миграцию.
Если у вас возникли проблемы с этим документом по миграции, пожалуйста, создайте проблему на Github.
F.42.8. Миграция с триггерного разбиения на нативное декларативное разбиение #
Этот документ охватывает, как мигрировать набор секций, используя старый метод триггеров/наследования/ограничений, к набору секций, используя нативные функции, найденные в Tantor SE. Этот документ предполагает, что вы используете как минимум Tantor SE 14. Это не мигрирует набор секций полностью для использования pg_partman, это просто предоставляет общее руководство для процесса триггер->нативный. Пожалуйста, смотрите главу Раздел F.42.7 для миграции ваших наборов секций в pg_partman.
Для разделения на подсекции вы должны быть в состоянии следовать всем тем же процессам, описанным здесь, но вам придется работать с самого нижнего уровня вверх и выполнять миграцию на каждом суб-родителе до самого верхнего уровня родителя.
Как всегда, настоятельно рекомендуется сначала протестировать эту миграцию на системе разработки. Полный набор данных для этого не требуется, достаточно только схемы с меньшим набором данных в каждом дочернем элементе, чтобы убедиться в его правильной работе.
Вот как выглядит наш набор секций перед миграцией:
\d+ partman_test.time_taptest_table Table "partman_test.time_taptest_table" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+---------+----------+-------------+--------------+------------- col1 | integer | | not null | | plain | | | col2 | text | | | | extended | | | col3 | timestamp with time zone | | not null | now() | plain | | | Indexes: "time_taptest_table_pkey" PRIMARY KEY, btree (col1) Triggers: time_taptest_table_part_trig BEFORE INSERT ON partman_test.time_taptest_table FOR EACH ROW EXECUTE FUNCTION partman_test.time_taptest_table_part_trig_func() Child tables: partman_test.time_taptest_table_p2023_03_26, partman_test.time_taptest_table_p2023_03_27, partman_test.time_taptest_table_p2023_03_28, partman_test.time_taptest_table_p2023_03_29, partman_test.time_taptest_table_p2023_03_30, partman_test.time_taptest_table_p2023_03_31, partman_test.time_taptest_table_p2023_04_01, partman_test.time_taptest_table_p2023_04_02, partman_test.time_taptest_table_p2023_04_03, partman_test.time_taptest_table_p2023_04_04, partman_test.time_taptest_table_p2023_04_05, partman_test.time_taptest_table_p2023_04_06, partman_test.time_taptest_table_p2023_04_07, partman_test.time_taptest_table_p2023_04_08, partman_test.time_taptest_table_p2023_04_09 Access method: heap
Если ваш набор секций на основе триггеров управляется
pg_partman версии до 5.0.0, лучше удалить его из
управления partman. Это можно сделать, удалив его из
part_config
и
part_config_sub
таблиц (если есть подсекции,
убедитесь, что все дочерние таблицы также удалены). После того как он будет
мигрирован на нативное секционирование, см. документ "Миграция в pg_partman",
упомянутый выше, чтобы вернуть его под управление partman.
DELETE FROM partman.part_config WHERE parent_table = 'partman_test.time_taptest_table';
Если он не управляется pg_partman и у вас есть какой-то другой метод автоматического обслуживания, убедитесь, что этот процесс отключен.
Далее нам нужно создать новую родительскую таблицу с использованием
нативного секционирования, поскольку в настоящее время нельзя преобразовать существующую таблицу
в родительскую таблицу с встроенным секционированием. Обратите внимание, что в этом случае наша исходная
таблица имела первичный ключ на col1
. Поскольку
col1
не является частью ключа секции, встроенное
секционирование не позволяет нам объявить его в качестве первичного ключа на
верхнем уровне таблицы. Если вам все еще нужен этот первичный ключ,
pg_partman предоставляет шаблон таблицы, на которой вы можете установить это, но он
все равно не будет обеспечивать уникальность по всему набору секций,
только на основе каждого дочернего элемента, аналогично тому, как это работало до встроенного.
Пожалуйста, смотрите главу Раздел F.42.5.1.1 для получения информации о том, какие свойства могут быть установлены на родительском объекте и какие должны управляться через шаблон.
CREATE TABLE partman_test.time_taptest_table_native (col1 int, col2 text default 'stuff', col3 timestamptz NOT NULL DEFAULT now()) PARTITION BY RANGE (col3); CREATE INDEX ON partman_test.time_taptest_table_native (col3);
Далее проверьте, каковы были права собственности и привилегии на вашей исходной
таблице, и убедитесь, что они существуют на новой родительской таблице. Это
обеспечит тот же доступ к таблице после
миграции. По умолчанию при нативном секционировании привилегии больше не
предоставляются на дочерние таблицы для обеспечения прямого доступа к ним.
Если нужно сохранить это поведение, установите
столбец inherit_privileges
в
part_config
(и part_config_sub, если необходимо) в
значение true.
\dt partman_test.time_taptest_table List of relations Schema | Name | Type | Owner --------------+--------------------+-------+--------------- partman_test | time_taptest_table | table | partman_owner (1 row) \dp+ partman_test.time_taptest_table Access privileges Schema | Name | Type | Access privileges | Column privileges | Policies --------------+--------------------+-------+-------------------------------------+-------------------+---------- partman_test | time_taptest_table | table | partman_owner=arwdDxt/partman_owner+| | | | | partman_basic=arwd/partman_owner +| | | | | testing=r/partman_owner | | (1 row)
ALTER TABLE partman_test.time_taptest_table_native OWNER TO partman_owner; GRANT SELECT, INSERT, UPDATE, DELETE ON partman_test.time_taptest_table_native TO partman_basic; GRANT SELECT ON partman_test.time_taptest_table_native TO testing;
Лучше всего остановить всю активность на исходной таблице во время процесса миграции, чтобы избежать любых проблем. Это можно сделать, либо временно отозвав все разрешения на таблицу, либо взяв эксклюзивную блокировку на родительскую таблицу и выполнив все эти шаги в одной транзакции. Метод транзакции настоятельно рекомендуется по простой причине, что если у вас возникнут какие-либо проблемы до того, как вы завершите процесс миграции, вы можете просто откатиться и вернуться к состоянию, в котором была ваша база данных до начала миграции.
BEGIN; LOCK TABLE partman_test.time_taptest_table IN ACCESS EXCLUSIVE MODE NOWAIT;
Если это таблица с разделением на подсекции, блокировка верхнего уровня родительской таблицы должна блокировать доступ ко всем дочерним таблицам, пока вы не используете предложение ONLY.
Первым важным шагом в этом процессе миграции теперь является отмена наследования всех дочерних таблиц от старого родителя. Вы можете использовать запрос, подобный приведенному ниже, чтобы сгенерировать операторы ALTER TABLE для отмены наследования всех дочерних таблиц от данной родительской таблицы. Лучше всего использовать сгенерированный таким образом SQL, чтобы избежать опечаток, особенно при работе с очень большими наборами секций:
НЕ ВЫПОЛНЯЙТЕ ПРИВЕДЕННЫЕ НИЖЕ ЗАЯВЛЕНИЯ. Будущий запрос не будет работать, если дочерние таблицы больше не являются частью набора наследования.
SELECT format('ALTER TABLE %s NO INHERIT %s;', inhrelid::regclass, inhparent::regclass) FROM pg_inherits WHERE inhparent::regclass = 'partman_test.time_taptest_table'::regclass; ?column? ----------------------------------------------------------------------------------------------------- ALTER TABLE partman_test.time_taptest_table_p2023_03_26 NO INHERIT partman_test.time_taptest_table; ALTER TABLE partman_test.time_taptest_table_p2023_03_27 NO INHERIT partman_test.time_taptest_table; ALTER TABLE partman_test.time_taptest_table_p2023_03_28 NO INHERIT partman_test.time_taptest_table; ALTER TABLE partman_test.time_taptest_table_p2023_03_29 NO INHERIT partman_test.time_taptest_table; ALTER TABLE partman_test.time_taptest_table_p2023_03_30 NO INHERIT partman_test.time_taptest_table; ALTER TABLE partman_test.time_taptest_table_p2023_03_31 NO INHERIT partman_test.time_taptest_table; ALTER TABLE partman_test.time_taptest_table_p2023_04_01 NO INHERIT partman_test.time_taptest_table; ALTER TABLE partman_test.time_taptest_table_p2023_04_02 NO INHERIT partman_test.time_taptest_table; ALTER TABLE partman_test.time_taptest_table_p2023_04_03 NO INHERIT partman_test.time_taptest_table; ALTER TABLE partman_test.time_taptest_table_p2023_04_04 NO INHERIT partman_test.time_taptest_table; ALTER TABLE partman_test.time_taptest_table_p2023_04_05 NO INHERIT partman_test.time_taptest_table; ALTER TABLE partman_test.time_taptest_table_p2023_04_06 NO INHERIT partman_test.time_taptest_table; ALTER TABLE partman_test.time_taptest_table_p2023_04_07 NO INHERIT partman_test.time_taptest_table; ALTER TABLE partman_test.time_taptest_table_p2023_04_08 NO INHERIT partman_test.time_taptest_table; ALTER TABLE partman_test.time_taptest_table_p2023_04_09 NO INHERIT partman_test.time_taptest_table; (15 rows)
СНОВА, НЕ ВЫПОЛНЯЙТЕ ЭТИ ЗАЯВЛЕНИЯ СЕЙЧАС. Следующий запрос не будет работать, если дочерние таблицы больше не являются частью набора наследования.
Для любых наборов секций, даже тех, которые не управляются pg_partman, следующим шагом является определение граничных значений ваших существующих дочерних таблиц и передача их в команду ATTACH PARTITION, используемую в нативном секционировании. Вам нужно будет найти метод для определения границ ваших дочерних таблиц, чтобы иметь возможность преобразовать их в синтаксис, необходимый для декларативных команд Tantor SE. В нашем случае суффиксы дочерних таблиц имеют фиксированный шаблон именования (YYYY_MM_DD
), который можно разобрать для определения начального граничного значения. В этом случае нам также нужно будет знать интервал секционирования (1 день
), чтобы иметь возможность рассчитать конечное время границы.
Если имена ваших дочерних таблиц не имеют подходящего шаблона, вам придется найти какой-то метод для определения границ каждой дочерней таблицы.
Снова мы можем использовать некоторый sql для генерации операторов, чтобы повторно присоединить дочерние элементы к новому родителю:
WITH child_tables AS ( SELECT inhrelid::regclass::text AS child_tablename_safe , relname AS child_tablename -- need unquoted name for parsing FROM pg_inherits JOIN pg_class c ON inhrelid = c.oid WHERE inhparent = 'partman_test.time_taptest_table'::regclass ) SELECT format( 'ALTER TABLE %s ATTACH PARTITION %s FOR VALUES FROM (%L) TO (%L);' , 'partman_test.time_taptest_table_native'::regclass , child_tablename_safe , to_timestamp(right(x.child_tablename, 10), 'YYYY_MM_DD') , to_timestamp(right(x.child_tablename, 10), 'YYYY_MM_DD')+'1 day'::interval ) FROM child_tables x; ?column? ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ALTER TABLE partman_test.time_taptest_table_native ATTACH PARTITION partman_test.time_taptest_table_p2023_03_26 FOR VALUES FROM ('2023-03-26 00:00:00-04') TO ('2023-03-27 00:00:00-04'); ALTER TABLE partman_test.time_taptest_table_native ATTACH PARTITION partman_test.time_taptest_table_p2023_03_27 FOR VALUES FROM ('2023-03-27 00:00:00-04') TO ('2023-03-28 00:00:00-04'); ALTER TABLE partman_test.time_taptest_table_native ATTACH PARTITION partman_test.time_taptest_table_p2023_03_28 FOR VALUES FROM ('2023-03-28 00:00:00-04') TO ('2023-03-29 00:00:00-04'); ALTER TABLE partman_test.time_taptest_table_native ATTACH PARTITION partman_test.time_taptest_table_p2023_03_29 FOR VALUES FROM ('2023-03-29 00:00:00-04') TO ('2023-03-30 00:00:00-04'); ALTER TABLE partman_test.time_taptest_table_native ATTACH PARTITION partman_test.time_taptest_table_p2023_03_30 FOR VALUES FROM ('2023-03-30 00:00:00-04') TO ('2023-03-31 00:00:00-04'); ALTER TABLE partman_test.time_taptest_table_native ATTACH PARTITION partman_test.time_taptest_table_p2023_03_31 FOR VALUES FROM ('2023-03-31 00:00:00-04') TO ('2023-04-01 00:00:00-04'); ALTER TABLE partman_test.time_taptest_table_native ATTACH PARTITION partman_test.time_taptest_table_p2023_04_01 FOR VALUES FROM ('2023-04-01 00:00:00-04') TO ('2023-04-02 00:00:00-04'); ALTER TABLE partman_test.time_taptest_table_native ATTACH PARTITION partman_test.time_taptest_table_p2023_04_02 FOR VALUES FROM ('2023-04-02 00:00:00-04') TO ('2023-04-03 00:00:00-04'); ALTER TABLE partman_test.time_taptest_table_native ATTACH PARTITION partman_test.time_taptest_table_p2023_04_03 FOR VALUES FROM ('2023-04-03 00:00:00-04') TO ('2023-04-04 00:00:00-04'); ALTER TABLE partman_test.time_taptest_table_native ATTACH PARTITION partman_test.time_taptest_table_p2023_04_04 FOR VALUES FROM ('2023-04-04 00:00:00-04') TO ('2023-04-05 00:00:00-04'); ALTER TABLE partman_test.time_taptest_table_native ATTACH PARTITION partman_test.time_taptest_table_p2023_04_05 FOR VALUES FROM ('2023-04-05 00:00:00-04') TO ('2023-04-06 00:00:00-04'); ALTER TABLE partman_test.time_taptest_table_native ATTACH PARTITION partman_test.time_taptest_table_p2023_04_06 FOR VALUES FROM ('2023-04-06 00:00:00-04') TO ('2023-04-07 00:00:00-04'); ALTER TABLE partman_test.time_taptest_table_native ATTACH PARTITION partman_test.time_taptest_table_p2023_04_07 FOR VALUES FROM ('2023-04-07 00:00:00-04') TO ('2023-04-08 00:00:00-04'); ALTER TABLE partman_test.time_taptest_table_native ATTACH PARTITION partman_test.time_taptest_table_p2023_04_08 FOR VALUES FROM ('2023-04-08 00:00:00-04') TO ('2023-04-09 00:00:00-04'); ALTER TABLE partman_test.time_taptest_table_native ATTACH PARTITION partman_test.time_taptest_table_p2023_04_09 FOR VALUES FROM ('2023-04-09 00:00:00-04') TO ('2023-04-10 00:00:00-04'); (15 rows)
Теперь можно выполнить эти два набора операторов ALTER TABLE, чтобы сначала отменить их наследование от старого родителя на основе триггера и присоединить их к новому нативному родителю. После этого у старого родителя на основе триггера не должно больше быть дочерних элементов:
\d+ partman_test.time_taptest_table Table "partman_test.time_taptest_table" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+---------+----------+-------------+--------------+------------- col1 | integer | | not null | | plain | | | col2 | text | | | | extended | | | col3 | timestamp with time zone | | not null | now() | plain | | | Indexes: "time_taptest_table_pkey" PRIMARY KEY, btree (col1) Triggers: time_taptest_table_part_trig BEFORE INSERT ON partman_test.time_taptest_table FOR EACH ROW EXECUTE FUNCTION partman_test.time_taptest_table_part_trig_func() Access method: heap
И наш новый нативной родитель теперь должен был принять всех своих новых детей:
\d+ partman_test.time_taptest_table_native Partitioned table "partman_test.time_taptest_table_native" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+---------------+----------+-------------+--------------+------------- col1 | integer | | | | plain | | | col2 | text | | | 'stuff'::text | extended | | | col3 | timestamp with time zone | | not null | now() | plain | | | Partition key: RANGE (col3) Indexes: "time_taptest_table_native_col3_idx" btree (col3) Partitions: partman_test.time_taptest_table_p2023_03_26 FOR VALUES FROM ('2023-03-26 00:00:00-04') TO ('2023-03-27 00:00:00-04'), partman_test.time_taptest_table_p2023_03_27 FOR VALUES FROM ('2023-03-27 00:00:00-04') TO ('2023-03-28 00:00:00-04'), partman_test.time_taptest_table_p2023_03_28 FOR VALUES FROM ('2023-03-28 00:00:00-04') TO ('2023-03-29 00:00:00-04'), partman_test.time_taptest_table_p2023_03_29 FOR VALUES FROM ('2023-03-29 00:00:00-04') TO ('2023-03-30 00:00:00-04'), partman_test.time_taptest_table_p2023_03_30 FOR VALUES FROM ('2023-03-30 00:00:00-04') TO ('2023-03-31 00:00:00-04'), partman_test.time_taptest_table_p2023_03_31 FOR VALUES FROM ('2023-03-31 00:00:00-04') TO ('2023-04-01 00:00:00-04'), partman_test.time_taptest_table_p2023_04_01 FOR VALUES FROM ('2023-04-01 00:00:00-04') TO ('2023-04-02 00:00:00-04'), partman_test.time_taptest_table_p2023_04_02 FOR VALUES FROM ('2023-04-02 00:00:00-04') TO ('2023-04-03 00:00:00-04'), partman_test.time_taptest_table_p2023_04_03 FOR VALUES FROM ('2023-04-03 00:00:00-04') TO ('2023-04-04 00:00:00-04'), partman_test.time_taptest_table_p2023_04_04 FOR VALUES FROM ('2023-04-04 00:00:00-04') TO ('2023-04-05 00:00:00-04'), partman_test.time_taptest_table_p2023_04_05 FOR VALUES FROM ('2023-04-05 00:00:00-04') TO ('2023-04-06 00:00:00-04'), partman_test.time_taptest_table_p2023_04_06 FOR VALUES FROM ('2023-04-06 00:00:00-04') TO ('2023-04-07 00:00:00-04'), partman_test.time_taptest_table_p2023_04_07 FOR VALUES FROM ('2023-04-07 00:00:00-04') TO ('2023-04-08 00:00:00-04'), partman_test.time_taptest_table_p2023_04_08 FOR VALUES FROM ('2023-04-08 00:00:00-04') TO ('2023-04-09 00:00:00-04'), partman_test.time_taptest_table_p2023_04_09 FOR VALUES FROM ('2023-04-09 00:00:00-04') TO ('2023-04-10 00:00:00-04')
Далее следует поменять местами имена вашего старого родителя на основе триггера и нового родительского элемента.
ALTER TABLE partman_test.time_taptest_table RENAME TO time_taptest_table_old; ALTER TABLE partman_test.time_taptest_table_native RENAME TO time_taptest_table;
PG11+ поддерживает функцию секции по умолчанию для захвата любых
данных, которые не имеют соответствующего дочернего элемента. Если ваши имена таблиц
особенно длинные, убедитесь, что добавление суффикса
_default
не будет неожиданно усечено.
Суффикс не обязателен для функциональности, но
предоставляет хороший контекст для того, для чего предназначена таблица, поэтому лучше
сократить само имя таблицы, чтобы соответствовать суффиксу.
CREATE TABLE partman_test.time_taptest_table_default (LIKE partman_test.time_taptest_table INCLUDING ALL); ALTER TABLE partman_test.time_taptest_table ATTACH PARTITION partman_test.time_taptest_table_default DEFAULT;
На исходной родительской таблице был первичный ключ, но это невозможно с использованием нативного секционирования, если только первичный ключ также не включает ключ разбиения. Это обычно непрактично при разбиении на основе времени. Вы можете установить первичный ключ на каждую отдельную дочернюю таблицу, но это будет обеспечивать ограничение только для этой дочерней таблицы, а не для всего набора секций. Вы можете добавить первичный ключ к каждой отдельной таблице, используя аналогичную генерацию SQL, как выше, но если вам нужен метод для управления добавлением этих ключей к любым новым дочерним таблицам, пожалуйста, ознакомьтесь с функциями, доступными в pg_partman.
Если вы запустили этот процесс внутри транзакции, обязательно подтвердите свою работу сейчас:
COMMIT;
Это должно завершить процесс миграции. Если вы хотите мигрировать ваш набор секций для управления с помощью pg_partman, пожалуйста, смотрите главу Раздел F.42.7.
F.42.9. Руководство по обновлению до pg_partman 5.0.1 #
Предостережение
Этот документ предполагает, что все наборы секций являются нативными наборами секций. Если у вас есть наборы секций на основе триггеров, вы должны сначала мигрировать их на нативные, прежде чем выполнять какую-либо дальнейшую работу по приведению ваших наборов секций в соответствие с pg_partman 5.0.1 и выше.
F.42.9.1. Ошибка триггера во время обновления #
Если вы видите следующие ошибки во время обновления, вам придется выполнить поэтапное обновление pg_partman. Обновление должно добавить ограничения и изменить значения таблицы в одной транзакции, и Tantor SE не всегда это позволяет.
ERROR: cannot ALTER TABLE "part_config_sub" because it has pending trigger events
Или из Amazon RDS
ERROR: 42501: cannot fire deferred trigger within security-restricted operation
Сначала обновите напрямую до 5.0.0
BEGIN; ALTER EXTENSION pg_partman UPDATE TO '5.0.0'; COMMIT;
Затем НЕЗАМЕДЛИТЕЛЬНО обновитесь до 5.0.1
BEGIN; ALTER EXTENSION pg_partman UPDATE TO '5.0.1'; COMMIT;
Если вы не можете выполнить оба этих обновления в быстрой последовательности, каждое в своей отдельной транзакции, вам следует подождать до окна обслуживания, которое позволит это сделать, прежде чем обновляться до версии 5.x или выше.
F.42.9.2. Устаревшие методы разбиения #
Существует несколько схем секционирования, которые поддерживались pg_partman до версии 5.0.1, но больше не поддерживаются, а именно ISO еженедельно и ежеквартально. Обратите внимание, что все еще возможно секционирование с этими интервалами в версии 5 и выше, используя интервалы “1 неделя” или “3 месяца”. Просто специализированные версии этого секционирования, которые были сделаны ранее, больше не поддерживаются.
Ранее еженедельное разбиение можно было выполнять с использованием формата ISO недели
IYYYwIW
, что приводило к суффиксам разбиения, таким как 2021w44 или 1994w32, где число
после w
было номером недели этого года, и год всегда был бы выровнен по ISO
неделе. Также поддерживался метод ежеквартального разбиения с
суффиксом YYYYq#
, где # был одним из 4
стандартных кварталов в году, начиная с 1 января. Метод
ежеквартального разбиения был особенно проблематичен для поддержки, так как
не все функции, основанные на времени, поддерживали его должным образом.
Так что, хотя ежеквартальное обновление было проблематично поддерживать, еженедельное работало хорошо в большинстве случаев. Но после пересмотра кода для поддержания всех различных специализированных суффиксов (всего 8), было решено упростить суффиксы, которые будут поддерживаться. Теперь есть только две возможности:
YYYYMMDD
для интервалов, равных или превышающих 1 деньYYYYMMDD_HH24MISS
для интервалов менее 1 дня (поддерживается до 1 секунды)
Поддержка пользовательских интервалов всегда была возможна с pg_partman, особенно с нативным партиционированием. Но упрощение поддерживаемых суффиксов значительно упрощает сопровождение кода. Если вы использовали любой из этих методов партиционирования, вам придется отказаться от них, чтобы использовать pg_partman 5.0.1 или выше. Миграцию можно выполнить до или после обновления, но обратите внимание, что обслуживание партиций не будет работать для этих методов в версии 5+ и будет генерировать ошибки при запуске обслуживания для этих наборов до завершения миграции.
Обратите внимание, что ранее hourly
разбиение не имело секунд в суффиксе, но любые новые наборы секций, созданные с этим интервалом, будут их иметь. Нет жесткого требования к миграции, как это было для еженедельных и ежеквартальных, но будет несоответствие в именовании дочерних таблиц с любыми существующими наборами секций до версии 5.x. Если требуется согласованность, можно выполнить миграцию, аналогичную приведенным ниже примерам.
Миграция представляет собой простое переименование дочерних таблиц и обновление таблицы(таблиц) конфигурации partman, поэтому это должен быть относительно плавный процесс с минимальным временем простоя.
F.42.9.2.1. Еженедельная миграция #
Вот пример набора еженедельных секций, созданного с помощью pg_partman версии 4.7.3.
\d+ partman_test.time_taptest_table Partitioned table "partman_test.time_taptest_table" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+------------------------------------------------+----------+-------------+--------------+------------- col1 | timestamp with time zone | | | | plain | | | col2 | text | | | | extended | | | col3 | integer | | not null | EXTRACT(epoch FROM CURRENT_TIMESTAMP)::integer | plain | | | Partition key: RANGE (col1) Partitions: partman_test.time_taptest_table_p2023w05 FOR VALUES FROM ('2023-01-30 00:00:00-05') TO ('2023-02-06 00:00:00-05'), partman_test.time_taptest_table_p2023w06 FOR VALUES FROM ('2023-02-06 00:00:00-05') TO ('2023-02-13 00:00:00-05'), partman_test.time_taptest_table_p2023w07 FOR VALUES FROM ('2023-02-13 00:00:00-05') TO ('2023-02-20 00:00:00-05'), partman_test.time_taptest_table_p2023w08 FOR VALUES FROM ('2023-02-20 00:00:00-05') TO ('2023-02-27 00:00:00-05'), partman_test.time_taptest_table_p2023w09 FOR VALUES FROM ('2023-02-27 00:00:00-05') TO ('2023-03-06 00:00:00-05'), partman_test.time_taptest_table_p2023w10 FOR VALUES FROM ('2023-03-06 00:00:00-05') TO ('2023-03-13 00:00:00-04'), partman_test.time_taptest_table_p2023w11 FOR VALUES FROM ('2023-03-13 00:00:00-04') TO ('2023-03-20 00:00:00-04'), partman_test.time_taptest_table_p2023w12 FOR VALUES FROM ('2023-03-20 00:00:00-04') TO ('2023-03-27 00:00:00-04'), partman_test.time_taptest_table_p2023w13 FOR VALUES FROM ('2023-03-27 00:00:00-04') TO ('2023-04-03 00:00:00-04'), partman_test.time_taptest_table_p2023w14 FOR VALUES FROM ('2023-04-03 00:00:00-04') TO ('2023-04-10 00:00:00-04'), partman_test.time_taptest_table_p2023w15 FOR VALUES FROM ('2023-04-10 00:00:00-04') TO ('2023-04-17 00:00:00-04'), partman_test.time_taptest_table_p2023w16 FOR VALUES FROM ('2023-04-17 00:00:00-04') TO ('2023-04-24 00:00:00-04'), partman_test.time_taptest_table_p2023w17 FOR VALUES FROM ('2023-04-24 00:00:00-04') TO ('2023-05-01 00:00:00-04'), partman_test.time_taptest_table_default DEFAULT
Содержимое таблицы конфигурации выглядит следующим образом (обратите внимание, что столбцы в таблице конфигурации значительно изменились в версии 5.x и выше)
SELECT * FROM partman.part_config; -[ RECORD 1 ]--------------+------------------------------------------------- parent_table | partman_test.time_taptest_table control | col1 partition_type | native partition_interval | 7 days constraint_cols | premake | 4 optimize_trigger | 4 optimize_constraint | 30 epoch | none inherit_fk | t retention | retention_schema | retention_keep_table | t retention_keep_index | t infinite_time_partitions | f datetime_string | IYYY"w"IW automatic_maintenance | on jobmon | t sub_partition_set_full | f undo_in_progress | f trigger_exception_handling | f upsert | trigger_return_null | t template_table | partman.template_partman_test_time_taptest_table publications | inherit_privileges | f constraint_valid | t subscription_refresh | drop_cascade_fk | f ignore_default_data | f
Мы используем запрос ниже, чтобы сгенерировать SQL, который переименует таблицы в новый шаблон именования, поддерживаемый в версии 5.x и выше. Корректировки этого запроса для ваших таблиц являются
Замените имя таблицы родителя в этом запросе на ваше имя
В первой функции подстроки число после
for
должно быть равно длине имени вашей родительской таблицы +2, чтобы учесть_p
. В этом случае20
Во второй функции подстроки число после
from
должно быть предыдущим числом +1. В этом случае21
SELECT format( 'ALTER TABLE %I.%I RENAME TO %I;' , n.nspname , c.relname , substring(c.relname from 1 for 20) || to_char(to_timestamp(substring(c.relname from 21), 'IYYY"w"IW'), 'YYYYMMDD') ) FROM pg_inherits h JOIN pg_class c ON h.inhrelid = c.oid JOIN pg_namespace n ON c.relnamespace = n.oid WHERE h.inhparent::regclass = 'partman_test.time_taptest_table'::regclass AND c.relname NOT LIKE '%_default' ORDER BY c.relname; ?column? ---------------------------------------------------------------------------------------------- ALTER TABLE partman_test.time_taptest_table_p2023w05 RENAME TO time_taptest_table_p20230130; ALTER TABLE partman_test.time_taptest_table_p2023w06 RENAME TO time_taptest_table_p20230206; ALTER TABLE partman_test.time_taptest_table_p2023w07 RENAME TO time_taptest_table_p20230213; ALTER TABLE partman_test.time_taptest_table_p2023w08 RENAME TO time_taptest_table_p20230220; ALTER TABLE partman_test.time_taptest_table_p2023w09 RENAME TO time_taptest_table_p20230227; ALTER TABLE partman_test.time_taptest_table_p2023w10 RENAME TO time_taptest_table_p20230306; ALTER TABLE partman_test.time_taptest_table_p2023w11 RENAME TO time_taptest_table_p20230313; ALTER TABLE partman_test.time_taptest_table_p2023w12 RENAME TO time_taptest_table_p20230320; ALTER TABLE partman_test.time_taptest_table_p2023w13 RENAME TO time_taptest_table_p20230327; ALTER TABLE partman_test.time_taptest_table_p2023w14 RENAME TO time_taptest_table_p20230403; ALTER TABLE partman_test.time_taptest_table_p2023w15 RENAME TO time_taptest_table_p20230410; ALTER TABLE partman_test.time_taptest_table_p2023w16 RENAME TO time_taptest_table_p20230417; ALTER TABLE partman_test.time_taptest_table_p2023w17 RENAME TO time_taptest_table_p20230424;
Обратите внимание, что все ISO недели начинаются с понедельника, поэтому это первый день недели, на основе которого будут создаваться имена дочерних таблиц. Это также совпадает с исходными границами дочерних таблиц, если вы посмотрите на них выше, поэтому имена дочерних таблиц должны совпадать с нижними границами данных, которые они содержат. Если вы хотите, чтобы ваши недели начинались с воскресенья (или какого-то другого дня), это потребует гораздо более сложной миграции самих данных и выходит за рамки данного документа.
Наконец, вам нужно обновить
datetime_string
столбец в таблице part_config
на новый шаблон суффикса.
UPDATE partman.part_config SET datetime_string = 'YYYYMMDD';
Теперь мы можем проверить, работает ли это, увеличив значение premake. Значение premake по умолчанию равно 4, поэтому, если вы изменили его ранее, просто добавьте к этому значению единицу. Мы также устанавливаем infinite_time_partitions
в true, потому что в наборе секций может быть недостаточно данных, чтобы вызвать создание будущих таблиц. Это можно отключить после тестирования, если это не требуется.
UPDATE partman.part_config SET premake = premake+1, infinite_time_partitions = true;
Теперь мы можем вызвать run_maintenance(), чтобы убедиться, что обслуживание секций работает должным образом
SELECT partman.run_maintenance('partman_test.time_taptest_table');
keith=# \d+ partman_test.time_taptest_table Partitioned table "partman_test.time_taptest_table" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+------------------------------------------------+----------+-------------+--------------+------------- col1 | timestamp with time zone | | | | plain | | | col2 | text | | | | extended | | | col3 | integer | | not null | EXTRACT(epoch FROM CURRENT_TIMESTAMP)::integer | plain | | | Partition key: RANGE (col1) Partitions: partman_test.time_taptest_table_p20230130 FOR VALUES FROM ('2023-01-30 00:00:00-05') TO ('2023-02-06 00:00:00-05'), partman_test.time_taptest_table_p20230206 FOR VALUES FROM ('2023-02-06 00:00:00-05') TO ('2023-02-13 00:00:00-05'), partman_test.time_taptest_table_p20230213 FOR VALUES FROM ('2023-02-13 00:00:00-05') TO ('2023-02-20 00:00:00-05'), partman_test.time_taptest_table_p20230220 FOR VALUES FROM ('2023-02-20 00:00:00-05') TO ('2023-02-27 00:00:00-05'), partman_test.time_taptest_table_p20230227 FOR VALUES FROM ('2023-02-27 00:00:00-05') TO ('2023-03-06 00:00:00-05'), partman_test.time_taptest_table_p20230306 FOR VALUES FROM ('2023-03-06 00:00:00-05') TO ('2023-03-13 00:00:00-04'), partman_test.time_taptest_table_p20230313 FOR VALUES FROM ('2023-03-13 00:00:00-04') TO ('2023-03-20 00:00:00-04'), partman_test.time_taptest_table_p20230320 FOR VALUES FROM ('2023-03-20 00:00:00-04') TO ('2023-03-27 00:00:00-04'), partman_test.time_taptest_table_p20230327 FOR VALUES FROM ('2023-03-27 00:00:00-04') TO ('2023-04-03 00:00:00-04'), partman_test.time_taptest_table_p20230403 FOR VALUES FROM ('2023-04-03 00:00:00-04') TO ('2023-04-10 00:00:00-04'), partman_test.time_taptest_table_p20230410 FOR VALUES FROM ('2023-04-10 00:00:00-04') TO ('2023-04-17 00:00:00-04'), partman_test.time_taptest_table_p20230417 FOR VALUES FROM ('2023-04-17 00:00:00-04') TO ('2023-04-24 00:00:00-04'), partman_test.time_taptest_table_p20230424 FOR VALUES FROM ('2023-04-24 00:00:00-04') TO ('2023-05-01 00:00:00-04'), partman_test.time_taptest_table_p20230501 FOR VALUES FROM ('2023-05-01 00:00:00-04') TO ('2023-05-08 00:00:00-04'), partman_test.time_taptest_table_p20230508 FOR VALUES FROM ('2023-05-08 00:00:00-04') TO ('2023-05-15 00:00:00-04'), partman_test.time_taptest_table_default DEFAULT
Вы можете увидеть, что обслуживание создало новые сеекции с нашим новым шаблоном именования без каких-либо проблем. Вы можете получить один или несколько в зависимости от состояния ваших дочерних таблиц на момент выполнения этого.
Если все в порядке, вы можете вернуть свои значения premake
и infinite_time_partitions
к их предыдущим значениям, если это необходимо.
Если вы хотите, чтобы любые еженедельно секционируемые таблицы начинались с
понедельника при их создании, вы можете использовать функцию
date_trunc()
в параметре
p_start_partition
для
create_parent()
для этого. Следующий
пример показывает, как это сделать во вторник. Без установки
конкретного начального раздела таким образом, набор секций начался бы
во вторник, 29 августа 2023 года, и каждый будущий раздел
основывался бы на неделе, начинающейся во вторник.
SELECT CURRENT_TIMESTAMP; current_timestamp ------------------------------- 2023-08-29 13:22:08.190552-04 CREATE TABLE public.time_table ( col1 int, col2 text, col3 timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP) PARTITION BY RANGE (col3); SELECT partman.create_parent('public.time_table', 'col3', '1 week', p_start_partition := to_char(date_trunc('week',CURRENT_TIMESTAMP), 'YYYY-MM-DD HH24:MI:SS'));
\d+ public.time_table Partitioned table "public.time_table" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+-------------------+----------+-------------+--------------+------------- col1 | integer | | | | plain | | | col2 | text | | | | extended | | | col3 | timestamp with time zone | | not null | CURRENT_TIMESTAMP | plain | | | Partition key: RANGE (col3) Partitions: time_table_p20230828 FOR VALUES FROM ('2023-08-28 00:00:00-04') TO ('2023-09-04 00:00:00-04'), time_table_p20230904 FOR VALUES FROM ('2023-09-04 00:00:00-04') TO ('2023-09-11 00:00:00-04'), time_table_p20230911 FOR VALUES FROM ('2023-09-11 00:00:00-04') TO ('2023-09-18 00:00:00-04'), time_table_p20230918 FOR VALUES FROM ('2023-09-18 00:00:00-04') TO ('2023-09-25 00:00:00-04'), time_table_p20230925 FOR VALUES FROM ('2023-09-25 00:00:00-04') TO ('2023-10-02 00:00:00-04'), time_table_default DEFAULT
F.42.9.2.2. Ежеквартальное Разделение #
Аналогично еженедельному, имена дочерних таблиц просто нужно переименовать и обновить конфигурацию partman с новым datetime_string. Ниже представлена таблица, как она была с оригинальными квартальными именами
\d+ partman_test.time_taptest_table Partitioned table "partman_test.time_taptest_table" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+---------+----------+-------------+--------------+------------- col1 | integer | | | | plain | | | col2 | text | | | | extended | | | col3 | timestamp with time zone | | not null | now() | plain | | | Partition key: RANGE (col3) Partitions: partman_test.time_taptest_table_p2022q1 FOR VALUES FROM ('2022-01-01 00:00:00-05') TO ('2022-04-01 00:00:00-04'), partman_test.time_taptest_table_p2022q2 FOR VALUES FROM ('2022-04-01 00:00:00-04') TO ('2022-07-01 00:00:00-04'), partman_test.time_taptest_table_p2022q3 FOR VALUES FROM ('2022-07-01 00:00:00-04') TO ('2022-10-01 00:00:00-04'), partman_test.time_taptest_table_p2022q4 FOR VALUES FROM ('2022-10-01 00:00:00-04') TO ('2023-01-01 00:00:00-05'), partman_test.time_taptest_table_p2023q1 FOR VALUES FROM ('2023-01-01 00:00:00-05') TO ('2023-04-01 00:00:00-04'), partman_test.time_taptest_table_p2023q2 FOR VALUES FROM ('2023-04-01 00:00:00-04') TO ('2023-07-01 00:00:00-04'), partman_test.time_taptest_table_p2023q3 FOR VALUES FROM ('2023-07-01 00:00:00-04') TO ('2023-10-01 00:00:00-04'), partman_test.time_taptest_table_p2023q4 FOR VALUES FROM ('2023-10-01 00:00:00-04') TO ('2024-01-01 00:00:00-05'), partman_test.time_taptest_table_p2024q1 FOR VALUES FROM ('2024-01-01 00:00:00-05') TO ('2024-04-01 00:00:00-04'), partman_test.time_taptest_table_default DEFAULT
Вот SQL для генерации переименований дочерних таблиц.
Обратите внимание, что это значительно сложнее, потому что квартальные
данные не работают как ожидалось с функцией
to_timestamp()
. Нам придется использовать
анонимную функцию для выполнения некоторого кода PL/PQSL, чтобы сгенерировать
SQL для изменения этих имен таблиц.
Note you will have to adjust the substring in the generation
of the ALTER TABLE statement to match the length of your
parent table name +2 (to account for the
_p
). In this case the value is
20
.
DO $rename$ DECLARE v_child_start_time timestamptz; v_row record; v_quarter text; v_sql text; v_suffix text; v_suffix_position int; v_year text; BEGIN -- Adjust your parent table name in the for loop query FOR v_row IN SELECT n.nspname AS child_schema, c.relname AS child_table FROM pg_inherits h JOIN pg_class c ON h.inhrelid = c.oid JOIN pg_namespace n ON c.relnamespace = n.oid WHERE h.inhparent = 'partman_test.time_taptest_table'::regclass AND c.relname NOT LIKE '%_default' ORDER BY c.relname LOOP v_suffix_position := (length(v_row.child_table) - position('p_' in reverse(v_row.child_table))) + 2; v_suffix := substring(v_row.child_table from v_suffix_position); v_year := split_part(v_suffix, 'q', 1); v_quarter := split_part(v_suffix, 'q', 2); CASE WHEN v_quarter = '1' THEN v_child_start_time := to_timestamp(v_year || '-01-01', 'YYYY-MM-DD'); WHEN v_quarter = '2' THEN v_child_start_time := to_timestamp(v_year || '-04-01', 'YYYY-MM-DD'); WHEN v_quarter = '3' THEN v_child_start_time := to_timestamp(v_year || '-07-01', 'YYYY-MM-DD'); WHEN v_quarter = '4' THEN v_child_start_time := to_timestamp(v_year || '-10-01', 'YYYY-MM-DD'); ELSE RAISE EXCEPTION 'Unexpected code path'; END CASE; -- Build the sql statement to rename the child table v_sql := format('ALTER TABLE %I.%I RENAME TO %I;' , v_row.child_schema , v_row.child_table , substring(v_row.child_table from 1 for 20)||to_char(v_child_start_time, 'YYYYMMDD')); RAISE NOTICE '%', v_sql; END LOOP; END $rename$;
Затем обновите конфигурацию, чтобы использовать новую datetime_string. Обратите внимание, что это то же самое, что и еженедельно сейчас
UPDATE partman.part_config SET datetime_string = 'YYYYMMDD';
Оставшиеся шаги для проверки того, что все работает, такие же, как еженедельно
UPDATE partman.part_config SET premake = premake+1, infinite_time_partitions = true; SELECT partman.run_maintenance('partman_test.time_taptest_table');
Вы должны увидеть как минимум еще одну дополнительную дочернюю таблицу
\d+ partman_test.time_taptest_table Partitioned table "partman_test.time_taptest_table" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description --------+--------------------------+-----------+----------+---------+----------+-------------+--------------+------------- col1 | integer | | | | plain | | | col2 | text | | | | extended | | | col3 | timestamp with time zone | | not null | now() | plain | | | Partition key: RANGE (col3) Partitions: partman_test.time_taptest_table_p20220101 FOR VALUES FROM ('2022-01-01 00:00:00-05') TO ('2022-04-01 00:00:00-04'), partman_test.time_taptest_table_p20220401 FOR VALUES FROM ('2022-04-01 00:00:00-04') TO ('2022-07-01 00:00:00-04'), partman_test.time_taptest_table_p20220701 FOR VALUES FROM ('2022-07-01 00:00:00-04') TO ('2022-10-01 00:00:00-04'), partman_test.time_taptest_table_p20221001 FOR VALUES FROM ('2022-10-01 00:00:00-04') TO ('2023-01-01 00:00:00-05'), partman_test.time_taptest_table_p20230101 FOR VALUES FROM ('2023-01-01 00:00:00-05') TO ('2023-04-01 00:00:00-04'), partman_test.time_taptest_table_p20230401 FOR VALUES FROM ('2023-04-01 00:00:00-04') TO ('2023-07-01 00:00:00-04'), partman_test.time_taptest_table_p20230701 FOR VALUES FROM ('2023-07-01 00:00:00-04') TO ('2023-10-01 00:00:00-04'), partman_test.time_taptest_table_p20231001 FOR VALUES FROM ('2023-10-01 00:00:00-04') TO ('2024-01-01 00:00:00-05'), partman_test.time_taptest_table_p20240101 FOR VALUES FROM ('2024-01-01 00:00:00-05') TO ('2024-04-01 00:00:00-04'), partman_test.time_taptest_table_p20240401 FOR VALUES FROM ('2024-04-01 00:00:00-04') TO ('2024-07-01 00:00:00-04'), partman_test.time_taptest_table_p20240701 FOR VALUES FROM ('2024-07-01 00:00:00-04') TO ('2024-10-01 00:00:00-04'), partman_test.time_taptest_table_default DEFAULT
Вы можете при необходимости вернуть значения ваших столбцов premake и infinite_time_partitions к их исходным значениям.