PgGraph β€” ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Π° для Π°Ρ€Ρ…ΠΈΠ²Π°Ρ†ΠΈΠΈ ΠΈ поиска зависимостСй Ρ‚Π°Π±Π»ΠΈΡ† Π² PostgreSQL

PgGraph — ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Π° для Π°Ρ€Ρ…ΠΈΠ²Π°Ρ†ΠΈΠΈ ΠΈ поиска зависимостСй Ρ‚Π°Π±Π»ΠΈΡ† Π² PostgreSQL
БСгодня я Ρ…ΠΎΡ‡Ρƒ ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ читатСлям Π₯Π°Π±Ρ€Π° ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρƒ, Π½Π°ΠΏΠΈΡΠ°Π½Π½ΡƒΡŽ Π½Π° Python, для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с зависимостями Ρ‚Π°Π±Π»ΠΈΡ† Π² Π‘Π£Π‘Π” PostgreSQL.

API ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹ простоС ΠΈ состоит ΠΈΠ· Ρ‚Ρ€Π΅Ρ… ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ²:

  • archive_table β€” рСкурсивная архивация/ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠ΅ строк с ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹ΠΌΠΈ Primary Keys
  • get_table_references β€” поиск зависимостСй для Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ (ΠΏΠΎΠΊΠ°ΠΆΠ΅Ρ‚ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ссылаСтся указанная ΠΈ ΡΡΡ‹Π»Π°ΡŽΡ‰ΠΈΠ΅ΡΡ Π½Π° Π½Π΅Π΅)
  • get_rows_references β€” поиск строк Π² Π΄Ρ€ΡƒΠ³ΠΈΡ… Ρ‚Π°Π±Π»ΠΈΡ†Π°Ρ…, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΡΡΡ‹Π»Π°ΡŽΡ‚ΡΡ Π½Π° ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹Π΅ строки Π² Π½ΡƒΠΆΠ½ΠΎΠΉ Ρ‚Π°Π±Π»ΠΈΡ†Π΅

ΠŸΡ€Π΅Π΄Ρ‹ΡΡ‚ΠΎΡ€ΠΈΡ

МСня Π·ΠΎΠ²ΡƒΡ‚ ОлСг Π‘ΠΎΡ€Π·ΠΎΠ², я Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Π² ΠΊΠΎΠΌΠ°Π½Π΄Π΅ CRM для ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€ΠΎΠ² ΠΈΠΏΠΎΡ‚Π΅Ρ‡Π½ΠΎΠ³ΠΎ крСдитования Π² Π”ΠΎΠΌΠΊΠ»ΠΈΠΊΠ΅.

Основная Π‘Π” нашСй CRM-систСмы являСтся ΠΎΠ΄Π½ΠΎΠΉ ΠΈΠ· ΠΊΡ€ΡƒΠΏΠ½Π΅ΠΉΡˆΠΈΡ… ΠΏΠΎ ΠΎΠ±ΡŠΠ΅ΠΌΡƒ Π² ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ. Она ΠΆΠ΅ ΠΎΠ΄Π½Π° ΠΈΠ· самых старых: появилась ΠΏΡ€ΠΈ самом запускС ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°, ΠΊΠΎΠ³Π΄Π° Π΄Π΅Ρ€Π΅Π²ΡŒΡ Π±Ρ‹Π»ΠΈ большими, Π”ΠΎΠΌΠΊΠ»ΠΈΠΊ β€” стартапом, Π° вмСсто микросСрвиса Π½Π° ΠΌΠΎΠ΄Π½ΠΎΠΌ питоновском асинхронном Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊΠ΅ Π±Ρ‹Π» ΠΎΠ³Ρ€ΠΎΠΌΠ½Ρ‹ΠΉ ΠΌΠΎΠ½ΠΎΠ»ΠΈΡ‚ Π½Π° PHP.

ΠŸΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ с PHP Π½Π° Python Π±Ρ‹Π» ΠΎΡ‡Π΅Π½ΡŒ Π΄ΠΎΠ»Π³ΠΈΠΌ ΠΈ Ρ‚Ρ€Π΅Π±ΠΎΠ²Π°Π» ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΈ ΠΎΠ±Π΅ΠΈΡ… систСм, Ρ‡Ρ‚ΠΎ ΡΠΊΠ°Π·Ρ‹Π²Π°Π»ΠΎΡΡŒ Π½Π° ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠΈ Π‘Π”.

Π’ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ ΠΌΡ‹ ΠΈΠΌΠ΅Π΅ΠΌ Π±Π°Π·Ρƒ с большим количСством сильно связанных ΠΈ ΠΎΠ³Ρ€ΠΎΠΌΠ½Ρ‹Ρ… ΠΏΠΎ Ρ€Π°Π·ΠΌΠ΅Ρ€Π°ΠΌ Ρ‚Π°Π±Π»ΠΈΡ† с ΠΊΡƒΡ‡Π΅ΠΉ индСксов ΠΏΠΎΠ΄ Ρ€Π°Π·Π½Ρ‹Π΅ Ρ‚ΠΈΠΏΡ‹ запросов. Всё это Π½Π΅Π³Π°Ρ‚ΠΈΠ²Π½ΠΎ сказываСтся Π½Π° ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ Π‘Π”: ΠΈΠ·-Π·Π° Π±ΠΎΠ»ΡŒΡˆΠΈΡ… Ρ‚Π°Π±Π»ΠΈΡ† ΠΈ ΠΊΡƒΡ‡ΠΈ связСй ΠΌΠ΅ΠΆΠ΄Ρƒ Π½ΠΈΠΌΠΈ постоянно растСт ΡΠ»ΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ запросов, Ρ‡Ρ‚ΠΎ особСнно ΠΊΡ€ΠΈΡ‚ΠΈΡ‡Π½ΠΎ для самых Π½Π°Π³Ρ€ΡƒΠΆΠ΅Π½Π½Ρ‹Ρ… Ρ‚Π°Π±Π»ΠΈΡ†.

Для сниТСния Π½Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ Π½Π° Π‘Π” ΠΌΡ‹ Ρ€Π΅ΡˆΠΈΠ»ΠΈ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ скрипт, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±Ρ‹ Π΅ΠΆΠ΅Π΄Π½Π΅Π²Π½ΠΎ ΠΏΠΎ ΠΊΡ€ΠΎΠ½Ρƒ пСрСносил старыС записи ΠΈΠ· самых ΠΎΠ±ΡŠΠ΅ΠΌΠ½Ρ‹Ρ… ΠΈ Π½Π°Π³Ρ€ΡƒΠΆΠ΅Π½Π½Ρ‹Ρ… Ρ‚Π°Π±Π»ΠΈΡ† Π² Π°Ρ€Ρ…ΠΈΠ²Π½Ρ‹Π΅ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΈΠ· task Π² task_archive).

Π­Ρ‚Π° Π·Π°Π΄Π°Ρ‡Π° услоТняСтся большим количСством связСй ΠΌΠ΅ΠΆΠ΄Ρƒ Ρ‚Π°Π±Π»ΠΈΡ†Π°ΠΌΠΈ: просто пСрСнСсти строки ΠΈΠ· task Π² task_archive нСдостаточно, ΠΏΠ΅Ρ€Π΅Π΄ этим Π½ΡƒΠΆΠ½ΠΎ Ρ‚ΠΎ ΠΆΠ΅ самоС рСкурсивно ΠΏΡ€ΠΎΠ΄Π΅Π»Π°Ρ‚ΡŒ со всСми ΡΡΡ‹Π»Π°ΡŽΡ‰ΠΈΠΌΠΈΡΡ Π½Π° task Ρ‚Π°Π±Π»ΠΈΡ†Π°ΠΌΠΈ.

ΠŸΡ€ΠΎΠ΄Π΅ΠΌΠΎΠ½ΡΡ‚Ρ€ΠΈΡ€ΡƒΡŽ Π½Π° ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ дСмонстрационной Π‘Π” с сайта postgrespro.ru:

PgGraph — ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Π° для Π°Ρ€Ρ…ΠΈΠ²Π°Ρ†ΠΈΠΈ ΠΈ поиска зависимостСй Ρ‚Π°Π±Π»ΠΈΡ† Π² PostgreSQL
Допустим, Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ записи ΠΈΠ· Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Flights. ΠŸΡ€ΠΎΡΡ‚ΠΎ Ρ‚Π°ΠΊ это ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Postgres Π½Π°ΠΌ Π½Π΅ ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΡ‚: ΠΏΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ Π½ΡƒΠΆΠ½ΠΎ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ записи ΠΈΠ· всСх ΡΡΡ‹Π»Π°ΡŽΡ‰ΠΈΡ…ΡΡ Ρ‚Π°Π±Π»ΠΈΡ†, ΠΈ Ρ‚Π°ΠΊ рСкурсивно Π΄ΠΎ Ρ‚Π°Π±Π»ΠΈΡ†, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π½ΠΈΠΊΡ‚ΠΎ Π½Π΅ ссылаСтся.

Π’ нашСм ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ Π½Π° Flights ссылаСтся Ticket_flights, Π° Π½Π° Π½Π΅Π΅ β€” Boarding_passes.

ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ ΡƒΠ΄Π°Π»ΡΡ‚ΡŒ Π½ΡƒΠΆΠ½ΠΎ Π² Ρ‚Π°ΠΊΠΎΠΌ порядкС:

  1. ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ значСния ΠΏΠ΅Ρ€Π²ΠΈΡ‡Π½Ρ‹Π΅ ΠΊΠ»ΡŽΡ‡ΠΈ (Primary Keys, PK) строк Π² Ticket_flights, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΡΡΡ‹Π»Π°ΡŽΡ‚ΡΡ Π½Π° удаляСмыС строки Π² Flights.
  2. ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ PK строк Boarding_passes, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΡΡΡ‹Π»Π°ΡŽΡ‚ΡΡ Π½Π° Ticket_flights.
  3. УдаляСм строки ΠΏΠΎ PK ΠΈΠ· ΠΏ.2 Π² Ρ‚Π°Π±Π»ΠΈΡ†Π΅ Boarding_passes.
  4. УдаляСм строки ΠΏΠΎ PK ΠΈΠ· ΠΏ.1 Π² Ticket_flights.
  5. УдаляСм строки ΠΈΠ· Flights.

Π’ ΠΈΡ‚ΠΎΠ³Π΅ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»Π°ΡΡŒ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Π° ΠΏΠΎΠ΄ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ PgGraph, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ ΠΌΡ‹ Ρ€Π΅ΡˆΠΈΠ»ΠΈ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ open source.

Как ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ

Π£Ρ‚ΠΈΠ»ΠΈΡ‚Π° ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ Π΄Π²Π° Ρ€Π΅ΠΆΠΈΠΌΠ° использования:

  • Π’Ρ‹Π·ΠΎΠ² ΠΈΠ· ΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΎΠΉ строки (pggraph …).
  • ИспользованиС Π² ΠΊΠΎΠ΄Π΅ Python (класс PgGraphApi).

Установка ΠΈ настройка

Π‘Π½Π°Ρ‡Π°Π»Π° Π½ΡƒΠΆΠ½ΠΎ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρƒ ΠΈΠ· Pypi-рСпозитория:

pip3 install pggraph

Π—Π°Ρ‚Π΅ΠΌ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½Π° локальной машинС Ρ„Π°ΠΉΠ» config.ini с ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠ΅ΠΉ Π‘Π” ΠΈ скрипта Π°Ρ€Ρ…ΠΈΠ²Π°Ρ†ΠΈΠΈ:

[db]
host = localhost
port = 5432
user = postgres
password = postgres
dbname = postgres
schema = public ; ΠΠ΅ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€, ΡƒΠΊΠ°Π·Π°Π½ΠΎ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ

[archive]  ; Π”Π°Π½Π½Ρ‹ΠΉ Ρ€Π°Π·Π΄Π΅Π» Π·Π°ΠΏΠΎΠ»Π½ΡΡ‚ΡŒ Π½Π΅ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ, Π½ΠΈΠΆΠ΅ ΡƒΠΊΠ°Π·Π°Π½Ρ‹ значСния ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ
is_debug = false
chunk_size = 1000
max_depth = 20
to_archive = true
archive_suffix = 'archive'

Запуск ΠΈΠ· консоли

ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹

$ pggraph -h
usage: pggraph action [-h] --table TABLE [--ids IDS] [--config_path CONFIG_PATH]
positional arguments:
  action        required action: archive_table, get_table_references, get_rows_references

optional arguments:
  -h, --help                    show this help message and exit
  --table TABLE                 table name
  --ids IDS                     primary key ids, separated by comma, e.g. 1,2,3
  --config_path CONFIG_PATH     path to config.ini
  --log_path LOG_PATH           path to log dir
  --log_level LOG_LEVEL         log level (debug, info, error)

ΠŸΠΎΠ·ΠΈΡ†ΠΈΠΎΠ½Π½Ρ‹Π΅ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹:

  • action β€” Ρ‚Ρ€Π΅Π±ΡƒΠ΅ΠΌΠΎΠ΅ дСйствиС: archive_table, get_table_references ΠΈΠ»ΠΈ get_rows_references.

Π˜ΠΌΠ΅Π½ΠΎΠ²Π°Π½Π½Ρ‹Π΅ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹:

  • --config_path β€” ΠΏΡƒΡ‚ΡŒ ΠΊ ΠΊΠΎΠ½Ρ„ΠΈΠ³-Ρ„Π°ΠΉΠ»Ρƒ;
  • --table β€” Ρ‚Π°Π±Π»ΠΈΡ†Π°, с ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Π½ΡƒΠΆΠ½ΠΎ ΡΠΎΠ²Π΅Ρ€ΡˆΠΈΡ‚ΡŒ дСйствиС;
  • --ids β€” список id Ρ‡Π΅Ρ€Π΅Π· Π·Π°ΠΏΡΡ‚ΡƒΡŽ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, 1,2,3 (Π½Π΅ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€);
  • --log_path β€” ΠΏΡƒΡ‚ΡŒ ΠΊ ΠΏΠ°ΠΏΠΊΠ΅ для Π»ΠΎΠ³ΠΎΠ² (Π½Π΅ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€, ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ β€” домашняя ΠΏΠ°ΠΏΠΊΠ°);
  • --log_level β€” ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ Турналирования (Π½Π΅ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€, ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ β€” INFO).

ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ ΠΊΠΎΠΌΠ°Π½Π΄

Архивация Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹

Основной функция ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹ β€” архивация Π΄Π°Π½Π½Ρ‹Ρ…, Ρ‚.Π΅. пСрСнос строк ΠΈΠ· основной Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Π² Π°Ρ€Ρ…ΠΈΠ²Π½ΡƒΡŽ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΈΠ· Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ books Π² books_archive).

Π’Π°ΠΊΠΆΠ΅ поддСрТиваСтся ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠ΅ Π±Π΅Π· Π°Ρ€Ρ…ΠΈΠ²Π°Ρ†ΠΈΠΈ: для этого Π½ΡƒΠΆΠ½ΠΎ Π² config.ini ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ to_archive = false).

ΠžΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ β€” config_path, table ΠΈ ids.

ПослС запуска Π±ΡƒΠ΄ΡƒΡ‚ рСкурсивно ΡƒΠ΄Π°Π»Π΅Π½Ρ‹ записи ids Π² Ρ‚Π°Π±Π»ΠΈΡ†Π΅ table ΠΈ Π²ΠΎ всСх ΡΡΡ‹Π»Π°ΡŽΡ‰ΠΈΡ…ΡΡ Π½Π° Π½Π΅Π΅ Ρ‚Π°Π±Π»ΠΈΡ†Π°Ρ….

$ pggraph archive_table --config_path config.hw.local.ini --table flights --ids 1,2,3
2020-06-20 19:27:44 INFO: flights - START
2020-06-20 19:27:44 INFO: flights - start archive_recursive 3 rows (depth=0)
2020-06-20 19:27:44 INFO:       START ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO:       ticket_flights - start archive_recursive 3 rows (depth=1)
2020-06-20 19:27:44 INFO:               START ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO:               boarding_passes - start archive_recursive 3 rows (depth=2)
2020-06-20 19:27:44 INFO:                       START ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO:                       END ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO:               boarding_passes - archive_by_ids 3 rows by ticket_no, flight_id
2020-06-20 19:27:44 INFO:               boarding_passes - start archive_recursive 3 rows (depth=2)
2020-06-20 19:27:44 INFO:                       START ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO:                       END ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO:               boarding_passes - archive_by_ids 3 rows by ticket_no, flight_id
2020-06-20 19:27:44 INFO:               boarding_passes - start archive_recursive 3 rows (depth=2)
2020-06-20 19:27:44 INFO:                       START ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO:                       END ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO:               boarding_passes - archive_by_ids 3 rows by ticket_no, flight_id
2020-06-20 19:27:44 INFO:               boarding_passes - start archive_recursive 3 rows (depth=2)
2020-06-20 19:27:44 INFO:                       START ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO:                       END ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO:               boarding_passes - archive_by_ids 3 rows by ticket_no, flight_id
2020-06-20 19:27:44 INFO:               END ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO:       ticket_flights - archive_by_ids 3 rows by ticket_no, flight_id
2020-06-20 19:27:44 INFO:       END ARCHIVE REFERRING TABLES
2020-06-20 19:27:44 INFO: flights - archive_by_ids 3 rows by id
2020-06-20 19:27:44 INFO: flights - END

Поиск зависимостСй для ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠΉ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹

Ѐункция для поиска зависимостСй ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠΉ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ table. ΠžΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ β€” config_path ΠΈ table.

ПослС запуска Π½Π° экран Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π²Π΅Π΄Π΅Π½ ΡΠ»ΠΎΠ²Π°Ρ€ΡŒ, Π³Π΄Π΅:

  • in_refs β€” ΡΠ»ΠΎΠ²Π°Ρ€ΡŒ ΡΡΡ‹Π»Π°ΡŽΡ‰ΠΈΡ…ΡΡ Ρ‚Π°Π±Π»ΠΈΡ† Π½Π° Π΄Π°Π½Π½ΡƒΡŽ, Π³Π΄Π΅ ΠΊΠ»ΡŽΡ‡ β€” Π½Π°Π·Π²Π°Π½ΠΈΠ΅ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹, Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ β€” список ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² Foreign Key (pk_main β€” ΠΏΠ΅Ρ€Π²ΠΈΡ‡Π½Ρ‹ΠΉ ΠΊΠ»ΡŽΡ‡ Π² основной Ρ‚Π°Π±Π»ΠΈΡ†Π΅, pk_ref β€” ΠΏΠ΅Ρ€Π²ΠΈΡ‡Π½Ρ‹ΠΉ ΠΊΠ»ΡŽΡ‡ Π² ΡΡΡ‹Π»Π°ΡŽΡ‰Π΅ΠΉΡΡ Ρ‚Π°Π±Π»ΠΈΡ†Π΅, fk_ref β€” Π½Π°Π·Π²Π°Π½ΠΈΠ΅ ΠΊΠΎΠ»ΠΎΠ½ΠΊΠΈ, ΡΠ²Π»ΡΡŽΡ‰Π΅ΠΉΡΡ foreign key Π½Π° ΠΈΡΡ…ΠΎΠ΄Π½ΡƒΡŽ Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ);
  • out_refs β€” ΡΠ»ΠΎΠ²Π°Ρ€ΡŒ Ρ‚Π°Π±Π»ΠΈΡ†, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ ссылаСтся данная.

$ pggraph get_table_references --config_path config.hw.local.ini --table flights
{'in_refs': {'ticket_flights': [ForeignKey(pk_main='flight_id', pk_ref='ticket_no, flight_id', fk_ref='flight_id')]},
 'out_refs': {'aircrafts': [ForeignKey(pk_main='aircraft_code', pk_ref='flight_id', fk_ref='aircraft_code')],
              'airports': [ForeignKey(pk_main='airport_code', pk_ref='flight_id', fk_ref='arrival_airport'),
                           ForeignKey(pk_main='airport_code', pk_ref='flight_id', fk_ref='departure_airport')]}}

Поиск ссылок Π½Π° строки с ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹ΠΌΠΈ Primary Key

Ѐункция для поиска строк Π² Π΄Ρ€ΡƒΠ³ΠΈΡ… Ρ‚Π°Π±Π»ΠΈΡ†Π°Ρ…, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΡΡΡ‹Π»Π°ΡŽΡ‚ΡΡ Ρ‡Π΅Ρ€Π΅Π· Foreign Key Π½Π° строки ids Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ table. ΠžΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ β€” config_path, table ΠΈ ids.

ПослС запуска Π½Π° экран Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π²Π΅Π΄Π΅Π½ ΡΠ»ΠΎΠ²Π°Ρ€ΡŒ со ΡΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ структурой:

{
	pk_id_1: {
		reffering_table_name_1: {
			foreign_key_1: [
				{row_pk_1: value, row_pk_2: value},
				...
			], 
			...
		},
		...
	},
	pk_id_2: {...},
	...
}

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ Π²Ρ‹Π·ΠΎΠ²Π°:

$ pggraph get_rows_references --config_path config.hw.local.ini --table flights --ids 1,2,3
{1: {'ticket_flights': {'flight_id': [{'flight_id': 1,
                                       'ticket_no': '0005432816945'},
                                      {'flight_id': 1,
                                       'ticket_no': '0005432816941'}]}},
 2: {'ticket_flights': {'flight_id': [{'flight_id': 2,
                                       'ticket_no': '0005433101832'},
                                      {'flight_id': 2,
                                       'ticket_no': '0005433101864'},
                                      {'flight_id': 2,
                                       'ticket_no': '0005432919715'}]}},
 3: {'ticket_flights': {'flight_id': [{'flight_id': 3,
                                       'ticket_no': '0005432817560'},
                                      {'flight_id': 3,
                                       'ticket_no': '0005432817568'},
                                      {'flight_id': 3,
                                       'ticket_no': '0005432817559'}]}}}

ИспользованиС в кодС

Помимо запуска Π² консоли, Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π² ΠΊΠΎΠ΄Π΅ Python. НиТС ΠΏΠΎΠΊΠ°Π·Π°Π½Ρ‹ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ Π²Ρ‹Π·ΠΎΠ²Π° Π² ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎΠΉ срСдС iPython.

Архивация Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹

>>> from pg_graph.main import setup_logging
>>> setup_logging(log_level='DEBUG')
>>> from pg_graph.api import PgGraphApi
>>> api = PgGraphApi('config.hw.local.ini')
>>> api.archive_table('flights', [4,5])
2020-06-20 23:12:08 INFO: flights - START
2020-06-20 23:12:08 INFO: flights - start archive_recursive 2 rows (depth=0)
2020-06-20 23:12:08 INFO: 	START ARCHIVE REFERRING TABLES
2020-06-20 23:12:08 DEBUG: 	ticket_flights - ForeignKey(pk_main='flight_id', pk_ref='flight_id, ticket_no', fk_ref='flight_id')
2020-06-20 23:12:08 DEBUG: 	SQL('SELECT flight_id, ticket_no FROM bookings.ticket_flights WHERE (flight_id) IN (%s, %s)')
2020-06-20 23:12:08 INFO: 	ticket_flights - start archive_recursive 30 rows (depth=1)
2020-06-20 23:12:08 INFO: 		START ARCHIVE REFERRING TABLES
2020-06-20 23:12:08 DEBUG: 		boarding_passes - ForeignKey(pk_main='flight_id, ticket_no', pk_ref='flight_id, ticket_no', fk_ref='flight_id, ticket_no')
2020-06-20 23:12:08 INFO: 		boarding_passes - archive_by_fk 30 rows by ForeignKey(pk_main='flight_id, ticket_no', pk_ref='flight_id, ticket_no', fk_ref='flight_id, ticket_no')
2020-06-20 23:12:08 DEBUG: 		SQL('CREATE TABLE IF NOT EXISTS bookings.boarding_passes_archive (LIKE bookings.boarding_passes)')
2020-06-20 23:12:08 DEBUG: 		DELETE FROM boarding_passes by FK flight_id, ticket_no - 30 rows
2020-06-20 23:12:08 INFO: 		END ARCHIVE REFERRING TABLES
2020-06-20 23:12:08 INFO: 	ticket_flights - archive_by_ids 30 rows by flight_id, ticket_no
2020-06-20 23:12:08 DEBUG: 	SQL('CREATE TABLE IF NOT EXISTS bookings.ticket_flights_archive (LIKE bookings.ticket_flights)')
2020-06-20 23:12:08 DEBUG: 	DELETE FROM ticket_flights by flight_id, ticket_no - 30 rows
2020-06-20 23:12:08 DEBUG: 	INSERT INTO ticket_flights_archive - 30 rows
2020-06-20 23:12:08 INFO: 	ticket_flights - start archive_recursive 30 rows (depth=1)
2020-06-20 23:12:08 INFO: 		START ARCHIVE REFERRING TABLES
2020-06-20 23:12:08 DEBUG: 		boarding_passes - ForeignKey(pk_main='flight_id, ticket_no', pk_ref='flight_id, ticket_no', fk_ref='flight_id, ticket_no')
2020-06-20 23:12:08 INFO: 		boarding_passes - archive_by_fk 30 rows by ForeignKey(pk_main='flight_id, ticket_no', pk_ref='flight_id, ticket_no', fk_ref='flight_id, ticket_no')
2020-06-20 23:12:08 DEBUG: 		SQL('CREATE TABLE IF NOT EXISTS bookings.boarding_passes_archive (LIKE bookings.boarding_passes)')
2020-06-20 23:12:08 DEBUG: 		DELETE FROM boarding_passes by FK flight_id, ticket_no - 30 rows
2020-06-20 23:12:08 INFO: 		END ARCHIVE REFERRING TABLES
2020-06-20 23:12:08 INFO: 	ticket_flights - archive_by_ids 30 rows by flight_id, ticket_no
2020-06-20 23:12:08 DEBUG: 	SQL('CREATE TABLE IF NOT EXISTS bookings.ticket_flights_archive (LIKE bookings.ticket_flights)')
2020-06-20 23:12:08 DEBUG: 	DELETE FROM ticket_flights by flight_id, ticket_no - 30 rows
2020-06-20 23:12:08 DEBUG: 	INSERT INTO ticket_flights_archive - 30 rows
2020-06-20 23:12:08 INFO: 	ticket_flights - start archive_recursive 30 rows (depth=1)
2020-06-20 23:12:08 INFO: 		START ARCHIVE REFERRING TABLES
2020-06-20 23:12:08 DEBUG: 		boarding_passes - ForeignKey(pk_main='flight_id, ticket_no', pk_ref='flight_id, ticket_no', fk_ref='flight_id, ticket_no')
2020-06-20 23:12:08 INFO: 		boarding_passes - archive_by_fk 30 rows by ForeignKey(pk_main='flight_id, ticket_no', pk_ref='flight_id, ticket_no', fk_ref='flight_id, ticket_no')
2020-06-20 23:12:08 DEBUG: 		SQL('CREATE TABLE IF NOT EXISTS bookings.boarding_passes_archive (LIKE bookings.boarding_passes)')
2020-06-20 23:12:08 DEBUG: 		DELETE FROM boarding_passes by FK flight_id, ticket_no - 30 rows
2020-06-20 23:12:08 INFO: 		END ARCHIVE REFERRING TABLES
2020-06-20 23:12:08 INFO: 	ticket_flights - archive_by_ids 30 rows by flight_id, ticket_no
2020-06-20 23:12:08 DEBUG: 	SQL('CREATE TABLE IF NOT EXISTS bookings.ticket_flights_archive (LIKE bookings.ticket_flights)')
2020-06-20 23:12:08 DEBUG: 	DELETE FROM ticket_flights by flight_id, ticket_no - 30 rows
2020-06-20 23:12:08 DEBUG: 	INSERT INTO ticket_flights_archive - 30 rows
2020-06-20 23:12:08 INFO: 	ticket_flights - start archive_recursive 3 rows (depth=1)
2020-06-20 23:12:08 INFO: 		START ARCHIVE REFERRING TABLES
2020-06-20 23:12:08 DEBUG: 		boarding_passes - ForeignKey(pk_main='flight_id, ticket_no', pk_ref='flight_id, ticket_no', fk_ref='flight_id, ticket_no')
2020-06-20 23:12:08 INFO: 		boarding_passes - archive_by_fk 3 rows by ForeignKey(pk_main='flight_id, ticket_no', pk_ref='flight_id, ticket_no', fk_ref='flight_id, ticket_no')
2020-06-20 23:12:08 DEBUG: 		SQL('CREATE TABLE IF NOT EXISTS bookings.boarding_passes_archive (LIKE bookings.boarding_passes)')
2020-06-20 23:12:08 DEBUG: 		DELETE FROM boarding_passes by FK flight_id, ticket_no - 3 rows
2020-06-20 23:12:08 INFO: 		END ARCHIVE REFERRING TABLES
2020-06-20 23:12:08 INFO: 	ticket_flights - archive_by_ids 3 rows by flight_id, ticket_no
2020-06-20 23:12:08 DEBUG: 	SQL('CREATE TABLE IF NOT EXISTS bookings.ticket_flights_archive (LIKE bookings.ticket_flights)')
2020-06-20 23:12:08 DEBUG: 	DELETE FROM ticket_flights by flight_id, ticket_no - 3 rows
2020-06-20 23:12:08 DEBUG: 	INSERT INTO ticket_flights_archive - 3 rows
2020-06-20 23:12:08 INFO: 	END ARCHIVE REFERRING TABLES
2020-06-20 23:12:08 INFO: flights - archive_by_ids 2 rows by flight_id
2020-06-20 23:12:09 DEBUG: SQL('CREATE TABLE IF NOT EXISTS bookings.flights_archive (LIKE bookings.flights)')
2020-06-20 23:12:09 DEBUG: DELETE FROM flights by flight_id - 2 rows
2020-06-20 23:12:09 DEBUG: INSERT INTO flights_archive - 2 rows
2020-06-20 23:12:09 INFO: flights - END

Поиск зависимостСй для ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠΉ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹

>>> from pg_graph.api import PgGraphApi
>>> from pprint import pprint
>>> api = PgGraphApi('config.hw.local.ini')
>>> res = api.get_table_references('flights')
>>> pprint(res)
{'in_refs': {'ticket_flights': [ForeignKey(pk_main='flight_id', pk_ref='flight_id, ticket_no', fk_ref='flight_id')]},
 'out_refs': {'aircrafts': [ForeignKey(pk_main='aircraft_code', pk_ref='flight_id', fk_ref='aircraft_code')],
              'airports': [ForeignKey(pk_main='airport_code', pk_ref='flight_id', fk_ref='arrival_airport'),
                           ForeignKey(pk_main='airport_code', pk_ref='flight_id', fk_ref='departure_airport')]}}

Поиск ссылок Π½Π° строки с ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹ΠΌΠΈ Primary Key

>>> from pg_graph.api import PgGraphApi
>>> from pprint import pprint
>>> api = PgGraphApi('config.hw.local.ini')
>>> rows = api.get_rows_references('flights', [1,2,3])
>>> pprint(rows)
{1: {'ticket_flights': {'flight_id': [{'flight_id': 1,
                                       'ticket_no': '0005432816945'},
                                      {'flight_id': 1,
                                       'ticket_no': '0005432816941'}]}},
 2: {'ticket_flights': {'flight_id': [{'flight_id': 2,
                                       'ticket_no': '0005433101832'},
                                      {'flight_id': 2,
                                       'ticket_no': '0005433101864'},
                                      {'flight_id': 2,
                                       'ticket_no': '0005432919715'}]}},
 3: {'ticket_flights': {'flight_id': [{'flight_id': 3,
                                       'ticket_no': '0005432817560'},
                                      {'flight_id': 3,
                                       'ticket_no': '0005432817568'},
                                      {'flight_id': 3,
                                       'ticket_no': '0005432817559'}]}}}

Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ доступСн Π½Π° GitHub ΠΏΠΎΠ΄ MIT Π»ΠΈΡ†Π΅Π½Π·ΠΈΠ΅ΠΉ, Π° Ρ‚Π°ΠΊΠΆΠ΅ Π² Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ PyPI.

Π‘ΡƒΠ΄Ρƒ Ρ€Π°Π΄ коммСнтариям, ΠΊΠΎΠΌΠΌΠΈΡ‚Π°ΠΌ ΠΈ прСдлоТСниям.

На вопросы ΠΏΠΎΡΡ‚Π°Ρ€Π°ΡŽΡΡŒ ΠΎΡ‚Π²Π΅Ρ‚ΠΈΡ‚ΡŒ ΠΏΠΎ ΠΌΠ΅Ρ€Π΅ возмоТностСй здСсь ΠΈ Π² Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com

Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ