Версионирование данных параметров¶
Обзор¶
Механизм версионирования позволяет сохранять снимки данных параметров в определенные моменты времени и восстанавливать их при необходимости. Это критически важно для:
- Создания точек восстановления перед рискованными операциями
- Сравнения данных между разными периодами планирования
- Хранения исторических срезов для аудита и анализа
- Тестирования различных сценариев с возможностью отката
Ключевая особенность: При сохранении и восстановлении версий используются фильтры, которые позволяют точно указать, какие данные должны быть сохранены или восстановлены. Это дает гибкость в работе с версиями — можно версионировать не весь параметр целиком, а только нужное подмножество данных.
Архитектура механизма¶
Основные компоненты¶
1. Version (Версия)¶
Модель: /src/planiqum/core/parameters/models.py: Version
class Version(HierarchyItem):
# Наследуется от HierarchyItem
# Автоматически получает поля: shortname, description, is_active
level = VersionHierarchy.get_version_level() # version__version
Характеристики:
- Version — это обычный элемент иерархии уровня
version__version - Хранится в таблице
core_parameter_version - Имеет
shortname(имя версии, например "v1.0", "2024-Q1") - Может быть активной/неактивной (
is_active)
2. Backup-параметр¶
Функция создания: /src/planiqum/core/parameters/scripts/backup.py: create_backup_parameter
Суть: Для каждого параметра с флагом has_backup=True создается отдельный параметр-дублер.
Структура backup-параметра:
Основной параметр "Sales Plan":
Dimensions: [Product, Region, Date]
Measures: [Quantity, Revenue]
Backup-параметр "Sales Plan (backup)":
Dimensions: [Version, Product, Region, Date] ← Version добавлен!
Measures: [Quantity, Revenue]
Особенности:
- Имя:
"{original_name} (backup)"(суффикс изsettings.PARAMETERS_BACKUP_SUFFIX) - Key:
"{original_key}_backup" - Флаг:
is_backup=True - Дополнительное измерение: Version (первое в списке dimensions)
- Структура мер: Полностью копируется из исходного параметра
- Fact-таблица: Отдельная таблица
fact__{backup_key}с колонкой version
3. Fact-таблица backup-параметра¶
Структура:
CREATE TABLE fact__sales_plan_backup (
id BIGSERIAL PRIMARY KEY,
dim_version__abc123 BIGINT, -- ID версии (ПЕРВАЯ dimension!)
dim_product__def456 BIGINT,
dim_region__ghi789 BIGINT,
dim_date__jkl012 BIGINT,
m_quantity__mno345 NUMERIC(20, 4),
m_revenue__pqr678 NUMERIC(20, 4)
);
-- Уникальность: (version_id + все остальные dimensions)
CREATE UNIQUE INDEX idx_unique ON fact__sales_plan_backup
(dim_version__abc123, dim_product__def456, dim_region__ghi789, dim_date__jkl012);
Принципиальная схема¶
┌─────────────────────────────────────────────────────────────────┐
│ ВЕРСИОНИРОВАНИЕ ДАННЫХ │
└─────────────────────────────────────────────────────────────────┘
┌──────────────────────┐ backup() ┌───────────────────────┐
│ Основной параметр │ ──────────────────────► │ Backup-параметр │
│ "Sales Plan" │ │ "Sales Plan (backup)"│
│ │ restore() │ │
│ Dimensions: │ ◄────────────────────── │ Dimensions: │
│ - Product │ │ - Version ← NEW! │
│ - Region │ │ - Product │
│ - Date │ │ - Region │
│ │ │ - Date │
│ Measures: │ │ │
│ - Quantity │ │ Measures: │
│ - Revenue │ │ - Quantity │
│ │ │ - Revenue │
│ fact__sales_plan │ │ fact__sales_plan_bkp │
└──────────────────────┘ └───────────────────────┘
▲ │
│ │
│ Хранит все версии: │
│ ┌─────────────────────────┐ │
│ │ Version = v1.0 │◄───┤
│ │ Version = v2.0 │◄───┤
│ │ Version = 2024-Q1 │◄───┤
│ │ ... │◄───┘
│ └─────────────────────────┘
│
Восстановление
с фильтром по версии
Создание версий¶
Через Django Admin¶
URL: /admin/parameters/version/add/
Поля:
shortname— имя версии (обязательное, уникальное)description— описание версииis_active— флаг активности
Пример:
Shortname: v1.0
Description: Первая версия бюджета 2024
Is active: ✓
Через API¶
Endpoint: POST /core/parameters/api/versions/
ViewSet: /src/planiqum/core/parameters/views.py: VersionViewSet
Запрос:
curl -X POST http://localhost:8000/core/parameters/api/versions/ \
-H "Content-Type: application/json" \
-d '{
"name": "v1.0",
"description": "Первая версия бюджета 2024"
}'
Ответ:
{
"id": 123,
"name": "v1.0",
"description": "Первая версия бюджета 2024",
"level": 45,
"is_active": true
}
Через Python API¶
from planiqum.core.parameters.models import Version
from planiqum.core.parameters.libs.backup import VersionHierarchy
# Способ 1: Прямое создание
version = Version.objects.create(
shortname="v1.0",
description="Первая версия бюджета 2024",
is_active=True
)
# Способ 2: Через HierarchyItem (с явным указанием level)
from planiqum.core.hierarchy.models import Item as HierarchyItem
version_level = VersionHierarchy.get_version_level()
version = HierarchyItem.objects.create(
level=version_level,
shortname="v2.0",
description="Вторая версия бюджета 2024"
)
Важно: При создании Version автоматически выполняются скрипты с триггером on_version_created (если они зарегистрированы).
Создание backup-параметров¶
Автоматическое создание¶
Backup-параметр создается автоматически при установке флага has_backup=True и синхронизации параметра.
Процесс:
- Установить флаг в админке:
- Открыть параметр в Django Admin
- Установить
has_backup = True -
Сохранить параметр
-
Синхронизировать структуру:
- Нажать кнопку "Sync" в админке
-
Или вызвать
parameter.sync()программно -
Результат:
- Создан параметр
"{name} (backup)" - Создана fact-таблица с dimension Version
- Структура мер скопирована
Программное создание¶
from planiqum.core.parameters.models import Parameter
from planiqum.core.parameters.scripts.backup import create_backup_parameter
# Получить основной параметр
parameter = Parameter.objects.get(key="sales_plan")
# Установить флаг
parameter.has_backup = True
parameter.save()
# Создать backup-параметр
backup_param = create_backup_parameter(parameter)
# Синхронизировать структуру (создать таблицы)
backup_param.sync()
Проверка существования backup-параметра¶
parameter = Parameter.objects.get(key="sales_plan")
# Получить backup-параметр (или None)
backup_param = parameter.get_backup_parameter()
if backup_param:
print(f"Backup-параметр существует: {backup_param.shortname}")
else:
print("Backup-параметр не создан")
Сохранение данных в версию¶
Функция backup¶
Функция: /src/planiqum/core/parameters/scripts/backup.py: backup
Назначение: Копирует данные из основных параметров в backup-параметры с привязкой к версии.
Параметры функции¶
def backup(settings, user=None):
"""
Сохранение данных параметров в версию.
:param settings: Словарь с настройками
{
"version": int, # ID версии (обязательно)
"parameters": [int, ...], # Список ID параметров (обязательно)
"filter": dict или None, # Фильтр для отбора данных (опционально)
"overwrite": bool # Перезаписать существующие данные версии
}
:param user: Объект User, выполняющий операцию
"""
Использование фильтров при сохранении¶
Критически важно: Параметр filter определяет, какие именно данные будут сохранены в версию.
Примеры использования фильтров:
Пример 1: Сохранить все данные параметра¶
from planiqum.core.parameters.scripts.backup import backup
from planiqum.core.hierarchy.models import Item as HierarchyItem
from planiqum.core.parameters.models import Parameter
version = HierarchyItem.objects.get(shortname="v1.0")
parameter = Parameter.objects.get(key="sales_plan")
backup(
settings={
"version": version.id,
"parameters": [parameter.id],
"filter": None, # Нет фильтра = все данные
"overwrite": True
},
user=request.user
)
Пример 2: Сохранить только данные по определенному продукту¶
from planiqum.core.filters.libs.filter import Filter
# Получить уровень и элемент иерархии
product_level = Level.objects.get(key="product__product")
iphone_product = Item.objects.get(shortname="iPhone 15", level=product_level)
# Создать фильтр
filter_dict = {
"level": product_level.id,
"dimension": "product",
"elements": [{"id": iphone_product.id, "level": product_level.id}]
}
backup(
settings={
"version": version.id,
"parameters": [parameter.id],
"filter": [filter_dict], # Только данные по iPhone 15
"overwrite": True
},
user=request.user
)
Пример 3: Сохранить данные за определенный период¶
# Фильтр по датам (2024 год)
filter_dict = {
"level": date_level.id,
"dimension": "date",
"elements": [
{"id": item.id, "level": date_level.id}
for item in Item.objects.filter(
level=date_level,
shortname__startswith="2024"
)
]
}
backup(
settings={
"version": version.id,
"parameters": [parameter.id],
"filter": [filter_dict], # Только 2024 год
"overwrite": True
},
user=request.user
)
Пример 4: Сохранить данные с комплексным фильтром¶
# Комбинированный фильтр: iPhone 15 за 2024 год в регионе Европа
filter_data = [
{
"level": product_level.id,
"dimension": "product",
"elements": [{"id": iphone_product.id, "level": product_level.id}]
},
{
"level": date_level.id,
"dimension": "date",
"elements": [
{"id": item.id, "level": date_level.id}
for item in date_2024_items
]
},
{
"level": region_level.id,
"dimension": "region",
"elements": [{"id": europe_region.id, "level": region_level.id}]
}
]
backup(
settings={
"version": version.id,
"parameters": [parameter.id],
"filter": filter_data, # Комплексный фильтр
"overwrite": True
},
user=request.user
)
Алгоритм работы функции backup¶
- Валидация и подготовка:
- Проверка обязательных параметров (version, parameters)
- Получение объектов Version и Parameter из БД
- Парсинг фильтра через класс Filter
-
Применение пользовательского фильтра (если user задан)
-
Для каждого параметра:
a. Создание/получение backup-параметра:
backup_param = create_backup_parameter(source_param)
b. Создание ревизии (опционально):
if backup_param.supports_revisions():
revision = Revision.objects.create(created_by=user, type=2)
c. Подготовка маппинга колонок:
# Dimensions: одинаковые имена (кроме version)
dimension_columns = [
(dim.fact_field_name(), dim.fact_field_name())
for dim in source_param.dimensions.all()
]
# Measures: маппинг по short_key
measure_columns = [
(source_measure.fact_field_name(), backup_measure.fact_field_name())
for source_measure, backup_measure in zip(...)
]
d. Определение unique_columns:
# Все dimension-колонки backup, включая version!
unique_columns = [
dim.fact_field_name()
for dim in backup_param.dimensions.all()
]
e. Добавление version_id в default_values:
version_dim_field = get_version_dimension_field(backup_param)
default_values = {version_dim_field: version.id}
f. Вызов низкоуровневой функции переноса:
transfer_table_data(
source_table=source_param.fact_table_name(),
target_table=backup_param.fact_table_name(),
columns=dimension_columns + measure_columns,
source_filter=filter_, # ← Фильтр применяется здесь!
source_parameter=source_param,
unique_columns=unique_columns,
default_values=default_values,
flush=True,
revision=revision,
user=user
)
- Результат:
- Данные скопированы в backup-таблицу
- К каждой записи добавлен version_id
- Фильтр определил, какие данные скопированы
- Старые данные этой версии удалены (flush=True)
Скрипт для пользователей¶
Скрипт: /src/planiqum/core/parameters/scripts/backup.py: save_data_to_backup
Декоратор: @pq_script(label="00.3.1 Версионность - сохранение данных в версию")
Использование через UI:
- Доступен в меню "Routines"
- Позволяет выбрать версию, параметры и фильтр через графический интерфейс
- Вызывает функцию backup() с подготовленными параметрами
Восстановление данных из версии¶
Функция restore¶
Функция: /src/planiqum/core/parameters/scripts/backup.py: restore
Назначение: Восстанавливает данные из backup-параметров в основные параметры.
Параметры функции¶
def restore(settings, user=None):
"""
Восстановление данных параметров из версии.
:param settings: Словарь с настройками
{
"version": int или str, # ID или shortname версии (обязательно)
"parameters": [int, ...], # Список ID параметров (обязательно)
"filter": dict или None # Фильтр для отбора данных (опционально)
}
:param user: Объект User, выполняющий операцию
"""
Использование фильтров при восстановлении¶
Критически важно: Параметр filter определяет, какие именно данные будут восстановлены из версии.
Важное отличие от backup: К переданному фильтру автоматически добавляется фильтр по версии!
# Переданный фильтр
user_filter = Filter(settings.get("filter"))
# Автоматически добавляется фильтр по версии
version_filter = Filter([{
"level": version_level.id,
"dimension": "version",
"elements": [{"id": version.id, "level": version_level.id}]
}])
# Итоговый фильтр
final_filter = user_filter + version_filter # Оба фильтра применяются!
Примеры использования фильтров:
Пример 1: Восстановить все данные версии¶
from planiqum.core.parameters.scripts.backup import restore
restore(
settings={
"version": "v1.0", # Можно передать shortname
"parameters": [parameter.id],
"filter": None # Нет дополнительного фильтра = все данные версии
},
user=request.user
)
Что произойдет:
- Применится автоматический фильтр: version = "v1.0"
- Будут восстановлены все данные этой версии
Пример 2: Восстановить только данные по определенному продукту¶
# Фильтр по продукту
filter_dict = [{
"level": product_level.id,
"dimension": "product",
"elements": [{"id": iphone_product.id, "level": product_level.id}]
}]
restore(
settings={
"version": "v1.0",
"parameters": [parameter.id],
"filter": filter_dict # Дополнительный фильтр
},
user=request.user
)
Что произойдет:
- Применятся оба фильтра: version = "v1.0" AND product = "iPhone 15"
- Будут восстановлены только данные по iPhone 15 из версии v1.0
Пример 3: Восстановить данные за период¶
# Фильтр по датам
filter_dict = [{
"level": date_level.id,
"dimension": "date",
"elements": [{"id": item.id, "level": date_level.id} for item in q1_2024]
}]
restore(
settings={
"version": version_id,
"parameters": [parameter.id],
"filter": filter_dict
},
user=request.user
)
Что произойдет:
- Применятся оба фильтра: version = ID AND date IN (Q1 2024)
- Будут восстановлены только данные Q1 2024 из указанной версии
Алгоритм работы функции restore¶
- Валидация и подготовка:
- Проверка обязательных параметров
- Парсинг версии (по ID или shortname)
- Парсинг параметров
-
Создание пользовательского фильтра
-
Добавление version_filter:
version_filter = __get_version_filter(version) filter_.add_filter(version_filter) # ← Ключевой момент! -
Добавление пользовательского фильтра (если есть):
if user: user_filter = user.profile.get_view_filter() filter_.add_filter(user_filter) -
Создание ревизии для восстановления:
revision = Revision.objects.create(created_by=user, type=2) -
Использование FactManager:
fm = FactManager(revision=revision, filter_=filter_, user=user) for target_param in parameters: # Получить backup-параметр source_param = target_param.get_backup_parameter() # Получить данные с применением фильтров target_facts = fm.get_facts(target_param, filter_=filter_) source_facts = fm.get_facts(source_param, filter_=filter_) # Вычислить изменения changes = get_facts_transfer_changes(source_facts, target_facts) # Добавить изменения for c in changes: fm.add_changes(c) # Сохранить все изменения fm.write(flush=False) -
Результат:
- Данные из backup-таблицы (с фильтром по версии!) восстановлены в основную таблицу
- Применены дополнительные фильтры (если указаны)
- Создана ревизия с информацией об изменениях
Скрипт для пользователей¶
Скрипт: /src/planiqum/core/parameters/scripts/backup.py: restore_data_from_backup
Декоратор: @pq_script(label="00.3.2 Версионность - восстановление данных из версии")
Использование через UI:
- Доступен в меню "Routines"
- Позволяет выбрать версию, параметры и фильтр через графический интерфейс
- Вызывает функцию restore() с подготовленными параметрами
Внутренние механизмы¶
Функция transfer_table_data¶
Функция: /src/planiqum/core/libs/db.py: transfer_table_data
Назначение: Универсальная низкоуровневая функция для переноса данных между таблицами на уровне SQL.
Параметры:
def transfer_table_data(
source_table: Union[str, Table], # Исходная таблица
target_table: Union[str, Table], # Целевая таблица
columns: List[Union[str, Tuple[str, str]]], # Список колонок для переноса
source_filter: Optional[Filter] = None, # Фильтр для source
source_parameter: Optional[Parameter] = None, # Параметр source
unique_columns: Optional[List[str]] = None, # Колонки для ON CONFLICT
default_values: Optional[Dict[str, Any]] = None, # Значения по умолчанию
flush: bool = False, # Удалить старые данные
flush_filter: Optional[Filter] = None, # Фильтр для flush
flush_parameter: Optional[Parameter] = None, # Параметр для flush
revision: Optional[Revision] = None, # Ревизия (опционально)
user: Optional[User] = None # Пользователь
) -> None:
Алгоритм:
- Нормализация параметров:
- Преобразование columns в пары
(source_col, target_col) -
Нормализация unique_columns
-
Создание SELECT запроса:
select_query = Query.from_(source_table).select(*source_cols) # Применение фильтра if source_filter: select_query = apply_to_query(select_query, source_filter, source_parameter) -
Создание временной таблицы:
temp_table = create_table_as(query=select_query, temporary=True) -
Добавление default_values:
for col, value in default_values.items(): execute_query(f"ALTER TABLE {temp_table} ADD COLUMN {col} BIGINT") execute_query(f"UPDATE {temp_table} SET {col} = {value}") -
Создание индекса:
execute_query(f"CREATE INDEX ON {temp_table} ({', '.join(unique_cols)})") -
Flush (удаление старых данных):
if flush: # Удалить из target записи, которых нет в temp_table DELETE FROM target_table WHERE NOT EXISTS ( SELECT 1 FROM temp_table WHERE target.col1 = temp.col1 AND target.col2 = temp.col2 ... ) -
INSERT с ON CONFLICT:
INSERT INTO target_table (col1, col2, ...) SELECT col1, col2, ... FROM temp_table ON CONFLICT (unique_col1, unique_col2, ...) DO UPDATE SET measure1 = EXCLUDED.measure1, measure2 = EXCLUDED.measure2 -
Очистка:
execute_query(f"DROP TABLE IF EXISTS {temp_table}")
Функция get_facts_transfer_changes¶
Функция: /src/planiqum/core/parameters/scripts/backup.py: get_facts_transfer_changes
Назначение: Вычисляет разницу между двумя DataFrames (source и target) и формирует список изменений для FactManager.
Алгоритм:
- Сравнивает DataFrames по ключевым полям (dimensions)
- Находит новые записи (есть в source, нет в target)
- Находит измененные записи (значения мер отличаются)
- Формирует список изменений в формате FactManager
Возвращает: Список объектов изменений для FactManager.add_changes()
Примеры использования¶
Пример 1: Создание точки восстановления перед массовой корректировкой¶
from planiqum.core.parameters.models import Parameter, Version
from planiqum.core.parameters.scripts.backup import backup, restore
# 1. Создать версию
version_before = Version.objects.create(
shortname="before_correction_2024_03_15",
description="Состояние перед корректировкой продаж"
)
# 2. Сохранить текущее состояние
parameter = Parameter.objects.get(key="sales_plan")
backup(
settings={
"version": version_before.id,
"parameters": [parameter.id],
"filter": None, # Все данные
"overwrite": True
},
user=request.user
)
# 3. Выполнить корректировку
# ... массовое изменение данных ...
# 4. Если что-то пошло не так — откатить
restore(
settings={
"version": version_before.id,
"parameters": [parameter.id],
"filter": None
},
user=request.user
)
Пример 2: Сравнение сценариев¶
# Сохранить оптимистичный сценарий
version_optimistic = Version.objects.create(shortname="scenario_optimistic")
backup(
settings={
"version": version_optimistic.id,
"parameters": [parameter.id],
"filter": None
},
user=user
)
# Изменить данные для пессимистичного сценария
# ... изменения ...
# Сохранить пессимистичный сценарий
version_pessimistic = Version.objects.create(shortname="scenario_pessimistic")
backup(
settings={
"version": version_pessimistic.id,
"parameters": [parameter.id],
"filter": None
},
user=user
)
# Переключаться между сценариями:
restore(settings={"version": "scenario_optimistic", "parameters": [parameter.id]}, user=user)
restore(settings={"version": "scenario_pessimistic", "parameters": [parameter.id]}, user=user)
Пример 3: Версионирование по продуктам¶
from planiqum.core.hierarchy.models import Level, Item
# Получить продукты
product_level = Level.objects.get(key="product__product")
iphone = Item.objects.get(shortname="iPhone 15", level=product_level)
samsung = Item.objects.get(shortname="Samsung S24", level=product_level)
version = Version.objects.create(shortname="products_snapshot_2024_q1")
# Сохранить только данные по iPhone
backup(
settings={
"version": version.id,
"parameters": [parameter.id],
"filter": [{
"level": product_level.id,
"dimension": "product",
"elements": [{"id": iphone.id, "level": product_level.id}]
}]
},
user=user
)
# Сохранить только данные по Samsung (в ту же версию!)
backup(
settings={
"version": version.id,
"parameters": [parameter.id],
"filter": [{
"level": product_level.id,
"dimension": "product",
"elements": [{"id": samsung.id, "level": product_level.id}]
}]
},
user=user
)
# Теперь в версии есть данные по обоим продуктам
# Восстановить только iPhone:
restore(
settings={
"version": version.id,
"parameters": [parameter.id],
"filter": [{
"level": product_level.id,
"dimension": "product",
"elements": [{"id": iphone.id, "level": product_level.id}]
}]
},
user=user
)
API для работы с версиями¶
REST API эндпоинты¶
Список версий¶
GET /core/parameters/api/versions/
Параметры запроса:
- shortname — фильтр по имени
Ответ:
[
{
"id": 1,
"name": "v1.0",
"description": "Первая версия",
"is_active": true,
"level": 45
},
{
"id": 2,
"name": "v2.0",
"description": "Вторая версия",
"is_active": false,
"level": 45
}
]
Создание версии¶
POST /core/parameters/api/versions/
Content-Type: application/json
{
"name": "v3.0",
"description": "Третья версия"
}
Получение версии¶
GET /core/parameters/api/versions/{id}/
Обновление версии¶
PATCH /core/parameters/api/versions/{id}/
Content-Type: application/json
{
"description": "Обновленное описание",
"is_active": false
}
Удаление версии¶
DELETE /core/parameters/api/versions/{id}/
Важно: При удалении версии не удаляются данные из backup-таблиц! Они остаются со ссылками на несуществующую версию. Рекомендуется сначала очистить данные версии, а потом удалять саму версию.
Python API¶
Работа с версиями¶
from planiqum.core.parameters.models import Version
from planiqum.core.hierarchy.models import Item as HierarchyItem
# Создать версию
version = Version.objects.create(shortname="v1.0", description="...")
# Получить версию по shortname
version = HierarchyItem.objects.get(
level__key="version__version",
shortname="v1.0"
)
# Получить все версии
versions = HierarchyItem.objects.filter(level__key="version__version")
# Активировать/деактивировать
version.is_active = True
version.save()
# Удалить версию
version.delete()
Работа с backup-параметрами¶
from planiqum.core.parameters.models import Parameter
# Проверить, есть ли backup
parameter = Parameter.objects.get(key="sales_plan")
has_backup = parameter.has_backup
# Получить backup-параметр
backup_param = parameter.get_backup_parameter()
# Получить основной параметр из backup
if backup_param.is_backup:
regular_param = backup_param.get_regular_parameter()
# Имя backup-параметра
backup_name = parameter.get_backup_name() # "Sales Plan (backup)"
backup_key = parameter.get_backup_key() # "sales_plan_backup"
Лучшие практики¶
1. Именование версий¶
Рекомендации:
- Используйте семантическое версионирование:
v1.0,v2.0,v2.1 - Или даты:
2024-Q1,2024-03-15 - Или описательные имена:
before_correction,approved_budget - Избегайте спецсимволов и пробелов
Хорошо:
v1.0
2024-Q1-baseline
approved-budget-march
before-mass-correction
Плохо:
Версия 1 (черновик)!!!
test123
temp
2. Использование описаний¶
Всегда заполняйте поле description — это поможет понять назначение версии спустя время:
Version.objects.create(
shortname="v1.0",
description="Утвержденный бюджет 2024, версия после согласования с финансовым директором 15.03.2024"
)
3. Фильтры при сохранении¶
- Сохраняйте только нужные данные — не создавайте огромные версии без необходимости
- Используйте фильтры для версионирования по регионам, продуктам, периодам
- Комбинируйте фильтры для точного отбора данных
4. Очистка старых версий¶
Периодически удаляйте неиспользуемые версии и их данные:
from planiqum.core.parameters.models import Parameter
# Удалить данные версии из backup-таблицы
backup_param = parameter.get_backup_parameter()
fm = FactManager()
facts = fm.get_facts(
backup_param,
filter_=Filter([{
"level": version_level.id,
"dimension": "version",
"elements": [{"id": old_version.id, "level": version_level.id}]
}])
)
# Удалить факты через FactManager или напрямую SQL
# Удалить версию
old_version.delete()
5. Тестирование перед восстановлением¶
Перед восстановлением критичных данных:
- Создайте точку восстановления текущего состояния
- Проверьте содержимое версии (выгрузите данные в Excel)
- Восстановите на тестовой среде
- Только потом восстанавливайте на продакшене
6. Мониторинг размера backup-таблиц¶
-- Размер backup-таблиц
SELECT
schemaname,
tablename,
pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS size
FROM pg_tables
WHERE tablename LIKE 'fact__%_backup'
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC;
Ограничения и особенности¶
1. Backup-таблица растет с каждой версией¶
Каждая новая версия добавляет данные в backup-таблицу. Если создать 100 версий, размер таблицы увеличится в ~100 раз.
Решение: Регулярная очистка старых версий.
2. Version dimension всегда первая¶
В backup-параметре dimension Version добавляется первой. Это влияет на порядок колонок в таблице.
Важно: Не изменяйте порядок dimensions в backup-параметре вручную!
3. Синхронизация структуры¶
При изменении структуры основного параметра (добавление/удаление мер или dimensions) необходимо пересоздать backup-параметр:
parameter.save()
parameter.sync() # Автоматически обновит backup-параметр
4. Производительность при большом объеме данных¶
Операции backup/restore для больших параметров (миллионы записей) могут занимать значительное время.
Оптимизация: - Используйте фильтры для уменьшения объема данных - Выполняйте операции в фоновом режиме (через Celery) - Создавайте индексы на dimension-колонках
5. Транзакции и откаты¶
Операции backup/restore выполняются в транзакциях. При ошибке изменения откатываются автоматически.
6. Ревизии при восстановлении¶
При восстановлении создается ревизия (если параметр поддерживает ревизии). Это позволяет отследить, кто и когда восстанавливал данные.
Связанные материалы¶
- Синхронизация параметров — работа с fact-таблицами и структурой параметров
- Ревизии и корректировки — механизм отслеживания изменений (устаревший)
- Фильтры — работа с фильтрами для отбора данных
- Иерархии — понимание структуры иерархий и элементов
- API — REST API для работы с параметрами и версиями