Перейти к содержанию

Проверка целостности таблиц фактов

Обзор

В системе Planiqum предусмотрены команды для проверки и анализа целостности таблиц фактов параметров. Эти инструменты помогают выявить проблемы с данными, отсутствующие индексы и дубликаты.

Доступные команды

  1. check_fact_tables_integrity - комплексная проверка целостности таблиц фактов
  2. show_duplicates - детальный анализ и экспорт дубликатов

Команда check_fact_tables_integrity

Назначение

Выполняет комплексную проверку целостности таблиц фактов для невычисляемых параметров.

Что проверяется

1. Наличие таблиц фактов

Для всех параметров с is_calculated=False проверяется наличие таблицы фактов в базе данных.

Ошибка: Отсутствует таблица фактов для невычисляемого параметра.

2. Наличие полей

Для существующих таблиц проверяется наличие всех необходимых колонок:

  • Dim-колонки: для всех измерений параметра
  • Measure-колонки: для мер с is_calculated=False и calculation_method='generated_column'

Ошибка: Отсутствуют необходимые поля в таблице.

Примечание: Меры с другими calculation_method (Raw SQL, Custom Aggregation и т.д.) не должны иметь колонок в таблице фактов.

3. Наличие индексов

Проверяется наличие индексов согласно стандарту синхронизации:

  • Индивидуальные индексы: на каждую dim-колонку
  • Композитный уникальный индекс: на все dim-колонки (предотвращает дубликаты)

Ошибка: Отсутствуют необходимые индексы.

Критично: Отсутствие уникального композитного индекса позволяет создавать дубликаты!

4. Дубликаты (опционально)

Для параметров без уникального композитного индекса проверяется наличие дубликатов по dim-колонкам.

⚠️ Ресурсоёмкая операция! Включается флагом --check-duplicates.

Выводится:

  • Количество дубликатов
  • Общее количество записей
  • Процент дубликатов от общего числа записей

5. Статистика заполненности (опционально)

Собирается статистика по таблицам:

  • Общее количество записей
  • Количество записей, где все меры NULL
  • Процент пустых записей

⚠️ Ресурсоёмкая операция! Включается флагом --collect-stats.

Использование

Синтаксис

python manage.py check_fact_tables_integrity [опции]

Опции

Опция Описание По умолчанию
--parameters PARAM1 PARAM2 ... Список ключей параметров для проверки Все невычисляемые
--check-duplicates Проверять дубликаты (ресурсоёмко) false
--collect-stats Собирать статистику заполненности (ресурсоёмко) false
--exact-count Точный подсчёт записей false (быстрая оценка)
--format {table\|json} Формат вывода table
--workers N Количество параллельных воркеров 1

Примеры

Базовая проверка:

# Проверить все невычисляемые параметры
python manage.py check_fact_tables_integrity

Проверка конкретных параметров:

python manage.py check_fact_tables_integrity --parameters sales_plan revenue_plan

Полная проверка с дубликатами и статистикой:

python manage.py check_fact_tables_integrity \
    --check-duplicates \
    --collect-stats \
    --exact-count \
    --workers 4

Экспорт результатов в JSON:

python manage.py check_fact_tables_integrity \
    --format json > integrity_report.json

Формат вывода

Табличный формат (по умолчанию)

Результаты выводятся в виде markdown таблиц с выравненными колонками.

Пример вывода:

=== ИТОГИ ===
Параметров проверено: 149
Найдено ошибок: 110

--- ОШИБКИ: Отсутствующие индексы (99) ---
| Ключ параметра                      | Название                        | Индексы измерений | Уникальный индекс |
|-------------------------------------|---------------------------------|-------------------|-------------------|
| demand__sellin_history_weekly       | ВП - история (недели)           | ✓                 | ❌ ОТСУТСТВУЕТ     |
| demand__sellin_history_clean_weekly | ВП - очищенная история (недели) | ✓                 | ❌ ОТСУТСТВУЕТ     |

--- ДУБЛИКАТЫ (3) ---
| Ключ параметра                      | Название                        | Всего записей | Дубликаты | Процент |
|-------------------------------------|---------------------------------|---------------|-----------|---------|
| demand__sellin_history_clean_weekly | ВП - очищенная история (недели) | 7,236,107     | 7,112,012 | 98.29%  |
| demand__sellin_history_weekly       | ВП - история (недели)           | 3,406,842     | 3,282,747 | 96.36%  |
| project__order_history_weekly       | История заказов                 | 2,108,637     | 2,011,768 | 95.41%  |

--- СТАТИСТИКА (3) ---
| Ключ параметра                      | Название                        | Всего записей | Пустых записей | Процент пустых |
|-------------------------------------|---------------------------------|---------------|----------------|----------------|
| working_days_calendar               | Календарь рабочих дней          | 1,826         | 0              | 0.0%           |
| demand__sellin_history_weekly       | ВП - история (недели)           | 3,406,842     | 0              | 0.0%           |

✗ Обнаружены проблемы с целостностью данных!

JSON формат

{
  "summary": {
    "parameters_checked": 3,
    "total_errors": 4,
    "has_duplicates": true
  },
  "errors": {
    "missing_table": [],
    "missing_fields": {},
    "missing_indexes": {
      "sales_plan": {
        "parameter_name": "План продаж",
        "missing_dimension_indexes": [],
        "missing_unique_index": true
      }
    },
    "duplicates": {
      "sales_plan": {
        "parameter_name": "План продаж",
        "duplicate_count": 3282747,
        "total_records": 3406842,
        "duplicate_percent": 96.36
      }
    }
  },
  "statistics": {
    "sales_plan": {
      "parameter_name": "План продаж",
      "total_records": 3406842,
      "null_measures_records": 0,
      "null_measures_percent": 0.0
    }
  }
}

Производительность

Подсчёт записей

  • Быстрая оценка (по умолчанию): pg_class.reltuples - очень быстро, может быть неточно на 5-10%
  • Точный подсчёт (--exact-count): COUNT(*) - медленнее, абсолютно точно

Параллелизм

Используйте --workers для ускорения проверки большого количества параметров:

# Последовательно (безопасно, медленнее)
python manage.py check_fact_tables_integrity --workers 1

# Параллельно (быстрее в 2-4 раза)
python manage.py check_fact_tables_integrity --workers 4

Оценка времени выполнения

Опции Параметров Время
Без опций 149 ~2-5 сек
--check-duplicates 149 ~30-120 сек
--collect-stats 149 ~10-30 сек
--check-duplicates --collect-stats 149 ~60-180 сек
С --workers 4 149 В 2-3 раза быстрее

Интерпретация результатов

Критичные ошибки

  1. Отсутствующие таблицы → Требуется синхронизация параметра
  2. Отсутствующие поля → Требуется синхронизация параметра
  3. Отсутствует уникальный индекс → Высокий риск дубликатов, требуется синхронизация

Важные предупреждения

  1. Найдены дубликаты → Требуется агрегация данных перед созданием уникального индекса
  2. Высокий процент пустых записей → Возможно, данные импортируются некорректно

Рекомендации по устранению

Отсутствующие таблицы/поля/индексы:

from planiqum.core.parameters.models import Parameter

# Синхронизировать конкретный параметр
param = Parameter.objects.get(key='sales_plan')
param.sync()

# Синхронизировать все параметры с ошибками
for param_key in ['sales_plan', 'revenue_plan']:
    param = Parameter.objects.get(key=param_key)
    param.sync()

Дубликаты:

Перед созданием уникального индекса необходимо агрегировать дубликаты. См. раздел Устранение дубликатов.

Использование из Python

from planiqum.core.parameters.scripts.check_fact_tables_integrity import check_fact_tables_integrity

# Проверка всех параметров
results = check_fact_tables_integrity()

# Проверка конкретных параметров
results = check_fact_tables_integrity(
    parameters=['sales_plan', 'revenue_plan'],
    check_duplicates=True,
    collect_stats=True,
    exact_count=False,
    workers=4
)

# Анализ результатов
if results['summary']['total_errors'] > 0:
    print(f"Найдено ошибок: {results['summary']['total_errors']}")

    # Параметры с отсутствующими таблицами
    for item in results['errors']['missing_table']:
        print(f"Отсутствует таблица: {item['key']}")

    # Параметры с дубликатами
    for key, data in results['errors']['duplicates'].items():
        print(f"{key}: {data['duplicate_count']} дубликатов ({data['duplicate_percent']}%)")

Команда show_duplicates

Назначение

Выводит и экспортирует дубликаты из таблицы фактов конкретного параметра для детального анализа.

Режимы работы

1. Режим grouped (по умолчанию)

Группирует дубликаты и показывает количество повторений каждой комбинации.

Формат вывода:

dim_column1,dim_column2,...,duplicate_count
value1,value2,...,177

Использование:

Идеально для анализа какие комбинации измерений чаще всего дублируются.

2. Режим unique

Выводит только уникальные комбинации dim-колонок без количества повторений.

Формат вывода:

dim_column1,dim_column2,...
value1,value2,...

Использование:

Полезно для получения списка проблемных комбинаций для последующей обработки.

3. Режим full

Выводит все дублирующиеся строки со всеми полями таблицы (включая id и меры).

Формат вывода:

id,dim_column1,dim_column2,...,measure_column1,...
100,value1,value2,...,1000,...
101,value1,value2,...,1000,...

Использование:

Необходим для детального анализа конкретных дублирующихся записей.

Использование

Синтаксис

python manage.py show_duplicates <parameter> [опции]

Опции

Опция Описание По умолчанию
parameter (обязательно) Ключ параметра -
--mode {grouped\|full\|unique} Режим вывода grouped
--limit N Максимальное количество групп/строк Консоль: 100
Файл: без ограничений
--output FILE Путь к CSV файлу для экспорта Вывод в консоль

Примеры

Быстрый просмотр топ-10 групп:

python manage.py show_duplicates sales_plan --limit 10

Экспорт всех дубликатов в файл:

python manage.py show_duplicates sales_plan --output duplicates.csv

Экспорт топ-500 групп:

python manage.py show_duplicates sales_plan --limit 500 --output top_500.csv

Получить список уникальных комбинаций:

python manage.py show_duplicates sales_plan --mode unique --output unique_combos.csv

Экспорт всех дублирующихся строк:

python manage.py show_duplicates sales_plan --mode full --output all_rows.csv

Формат вывода

Вывод в консоль

Если групп ≤ 1000:

Выводится полная markdown таблица:

Всего групп дубликатов в таблице: 150
Общее количество дубликатов в таблице: 1,500

Показаны первые 150 групп:
| dim_client | dim_product | duplicate_count |
|------------|-------------|-----------------|
| 123        | 456         | 25              |
...все группы...

Если групп > 1000:

Выводятся первые 10 групп + предупреждение:

Всего групп дубликатов в таблице: 97,417
Общее количество дубликатов в таблице: 3,282,747

Первые 100 групп:
| dim_client | dim_product | duplicate_count |
|------------|-------------|-----------------|
| 1061383    | 977785      | 177             |
| 1061383    | 863683      | 177             |
...первые 100...

... и ещё 97,317 групп не показано

Для просмотра всех данных используйте опцию --output для экспорта в файл
или --limit для увеличения количества показанных строк (по умолчанию: 100)

Экспорт в файл

С limit:

python manage.py show_duplicates sales_plan --limit 50 --output dup.csv

Экспортируется ровно 50 групп в файл + превью в консоли (если ≤ 100).

Без limit:

python manage.py show_duplicates sales_plan --output all_dup.csv

Экспортируются ВСЕ группы дубликатов в файл (без ограничений).

Интерпретация результатов

Пример вывода grouped режима

| dim_client | dim_product | duplicate_count |
|------------|-------------|-----------------|
| 123        | 456         | 177             |

Означает:

  • Комбинация client=123, product=456 встречается 177 раз в таблице
  • Из них 1 оригинал и 176 дубликатов
  • Эти 176 лишних строк можно удалить

Общая статистика

Всего групп дубликатов в таблице: 97,417
Общее количество дубликатов в таблице: 3,282,747

Означает:

  • В таблице есть 97,417 уникальных комбинаций измерений, которые повторяются
  • Суммарно это даёт 3,282,747 лишних строк (дубликатов)
  • Если удалить дубликаты, таблица уменьшится на 3,282,747 записей

Использование из Python

from planiqum.core.parameters.scripts.show_duplicates import show_duplicates

# Получить дубликаты
data = show_duplicates(
    parameter_key='sales_plan',
    mode='grouped',
    limit=100,
    output_file='/tmp/duplicates.csv'
)

# Анализ результатов
print(f"Групп дубликатов: {data['total_groups']}")
print(f"Всего дубликатов: {data['total_duplicates']}")
print(f"Заголовки: {data['headers']}")
print(f"Первая группа: {data['rows'][0]}")

Устранение дубликатов

Процесс устранения

  1. Экспорт дубликатов для анализа:
python manage.py show_duplicates sales_plan --output sales_duplicates.csv
  1. Анализ дубликатов:

Открыть CSV в Excel/LibreOffice и проанализировать: - Какие комбинации измерений дублируются? - Есть ли закономерность? - Почему возникли дубликаты?

  1. Агрегация дубликатов:

⚠️ Перед созданием уникального индекса необходимо агрегировать дубликаты!

Варианты агрегации: - SUM: суммирование значений мер - AVG: среднее значение - MAX/MIN: выбор максимального/минимального - FIRST: оставить первую запись

Пример агрегации (через Django shell):

from django.db import connection
from planiqum.core.libs.db import execute_query

# Создаём временную таблицу с агрегированными данными
execute_query("""
    CREATE TABLE fact__sales_plan_tmp AS
    SELECT 
        MIN(id) as id,
        dim_product,
        dim_region,
        dim_period,
        SUM(m_revenue) as m_revenue,
        SUM(m_quantity) as m_quantity
    FROM fact__sales_plan
    GROUP BY dim_product, dim_region, dim_period
""")

# Переименовываем таблицы
execute_query("DROP TABLE fact__sales_plan")
execute_query("ALTER TABLE fact__sales_plan_tmp RENAME TO fact__sales_plan")

# Синхронизируем параметр (создаст индексы)
from planiqum.core.parameters.models import Parameter
param = Parameter.objects.get(key='sales_plan')
param.sync()
  1. Синхронизация параметра:

После агрегации запустите синхронизацию для создания уникального индекса:

param.sync()
  1. Проверка результатов:
python manage.py check_fact_tables_integrity --parameters sales_plan
python manage.py show_duplicates sales_plan

Автоматическая агрегация (TODO)

⚠️ В будущих версиях: Планируется автоматическая агрегация при создании уникального индекса (см. TODO в коде синхронизации).


Сценарии использования

Проверка перед деплоем

# Быстрая проверка всех параметров
python manage.py check_fact_tables_integrity --workers 4

# Если найдены ошибки - синхронизировать проблемные параметры

Периодический мониторинг

# Cron job для ежедневной проверки
0 2 * * * cd /path/to/project && python manage.py check_fact_tables_integrity \
    --format json > /var/log/planiqum/integrity_$(date +\%Y\%m\%d).json

Анализ проблемных таблиц

# 1. Найти параметры с дубликатами
python manage.py check_fact_tables_integrity --check-duplicates

# 2. Детально изучить дубликаты
python manage.py show_duplicates sales_plan --output sales_dup.csv

# 3. Проанализировать в Excel
# 4. Агрегировать дубликаты
# 5. Синхронизировать параметр

Очистка базы данных

# 1. Найти таблицы с высоким процентом пустых записей
python manage.py check_fact_tables_integrity --collect-stats

# 2. Удалить пустые записи
python manage.py shell -c "
from planiqum.core.libs.db import execute_query
execute_query('DELETE FROM fact__sales_plan WHERE m_revenue IS NULL AND m_cost IS NULL')
"

API для разработчиков

check_fact_tables_integrity

from planiqum.core.parameters.scripts.check_fact_tables_integrity import (
    check_fact_tables_integrity,
    FactTableIntegrityChecker
)

# Простой вызов
results = check_fact_tables_integrity(
    parameters=['sales_plan', 'revenue_plan'],  # или None для всех
    check_duplicates=True,
    collect_stats=True,
    exact_count=False,
    workers=4,
    progress_callback=lambda curr, total, key: print(f"{curr}/{total}: {key}")
)

# Использование класса напрямую
checker = FactTableIntegrityChecker(
    parameters=None,  # Все параметры
    check_duplicates=True,
    collect_stats=True,
    exact_count=False,
    workers=4
)
results = checker.check()

# Обработка результатов
for key, data in results['errors']['duplicates'].items():
    print(f"{key}: {data['duplicate_percent']}% дубликатов")

show_duplicates

from planiqum.core.parameters.scripts.show_duplicates import (
    show_duplicates,
    DuplicatesExporter
)

# Простой вызов
data = show_duplicates(
    parameter_key='sales_plan',
    mode='grouped',
    limit=100,
    output_file='/tmp/dup.csv'
)

# Использование класса напрямую
exporter = DuplicatesExporter('sales_plan', mode='grouped', limit=100)
data = exporter.get_duplicates()

# Экспорт
exporter.export_to_csv('/tmp/dup.csv', data)

# Анализ результатов
print(f"Всего групп: {data['total_groups']}")
print(f"Всего дубликатов: {data['total_duplicates']}")
print(f"Заголовки: {data['headers']}")
print(f"Первые 5 групп: {data['rows'][:5]}")

Устранение проблем

Ошибка: "Параметр не найден или является вычисляемым"

Причина: Команды работают только с невычисляемыми параметрами.

Решение: Проверьте, что параметр существует и is_calculated=False.

Ошибка: "Параметр не имеет измерений"

Причина: Для проверки дубликатов параметр должен иметь измерения.

Решение: Эта команда не применима к параметрам без измерений.

Ошибка: "Таблица фактов не существует"

Причина: Таблица не создана или была удалена.

Решение: Выполните синхронизацию параметра:

from planiqum.core.parameters.models import Parameter
param = Parameter.objects.get(key='parameter_key')
param.sync()

Слишком долгое выполнение

Проблема: Проверка дубликатов занимает слишком много времени.

Решение:

  1. Используйте --limit для ограничения выборки
  2. Проверьте наличие индексов на dim-колонки
  3. Рассмотрите использование --workers для параллелизма

Лучшие практики

Регулярная проверка

Рекомендуется регулярно (раз в неделю/месяц) проверять целостность таблиц:

python manage.py check_fact_tables_integrity --workers 4

После изменений структуры

После изменения измерений или мер параметра всегда проверяйте целостность:

python manage.py check_fact_tables_integrity --parameters modified_parameter

Перед импортом больших объёмов данных

Перед импортом убедитесь в наличии уникального индекса:

python manage.py check_fact_tables_integrity --parameters target_parameter

Если индекса нет - сначала синхронизируйте параметр, потом импортируйте данные.

Мониторинг дубликатов

Периодически проверяйте наличие дубликатов в критичных параметрах:

# Раз в неделю
python manage.py check_fact_tables_integrity \
    --parameters sales_plan revenue_plan order_plan \
    --check-duplicates \
    --format json > weekly_check.json

Работа с большими таблицами

Для таблиц с миллионами записей:

  1. Используйте быструю оценку (без --exact-count)
  2. Проверяйте дубликаты только при необходимости
  3. Используйте параллелизм (--workers 4)
  4. Экспортируйте результаты в файлы для анализа

Связанные разделы


Справочная информация

Файлы

Сценарии: - /src/planiqum/core/parameters/scripts/check_fact_tables_integrity.py - /src/planiqum/core/parameters/scripts/show_duplicates.py

Команды: - /src/planiqum/core/parameters/management/commands/check_fact_tables_integrity.py - /src/planiqum/core/parameters/management/commands/show_duplicates.py

Связанный код


Важно: описанные настройки и сценарии могут отличаться в вашей инсталляции Planiqum
За уточнениями и методологической поддержкой обращайтесь в компанию ЮНИК СОФТ