Як визначити яких файлів на диску відповідають postgresql таблиці

Іноді вам потрібно визначити якому файлу на диску відповідає таблиця. У вас є шлях, повний цифр, такий як base / 16499/19401 і ви хочете розібратися в ньому. Ви можете дивитися на повідомлення про помилку, яке згадує ім'я файлу, наприклад:

У пошуках шляху відносини

Ви можете побачити шлях до таблиці використовуючи:

але що щодо зворотного процесу, отримання назви об'єкта з шляху до нього? Існує функція pg_filenode_relation. яка здається підходящої для цього ... але щоб її використовувати, необхідно бути підключеним до конкретної бази даних, до якої відноситься цей файл, що має на увазі знання зв'язку з цим.

Структура шляху до файлу

Ось яким чином можна визначити шлях до таблиць і баз даних в сучасній версії PostgreSQL. (Більш старі версії використовують інший формат, про який можна почитати тут).

Є 3 основні варіанти шляху:

  • Для файлів в табличному просторі за замовчуванням, base / database_oid / filenode id for the relation
  • Для файлів з інших табличних просторів: pg_tblspc / tablespace_oid / tablespace_version_subdir / database_oid / filenode id відносини
  • Для загальних відносин: global / filenode id відносини

Загальні відносини будуть обговорюватися в кінці. Для перших же двох варіантів, які є найпоширенішими, з якими ви будете найчастіше стикатися, остання частина шляху ідентична, oid бази і oid відносини.

Зверніть увагу, я вжив формулювання "filenode id відносини", а не "oid відносини". Це пов'язано з тим, що PostgreSQL має карту relfilenode в файлі з ім'ям pg_relfilenode.map для кожної бази даних / табличного простору. Імена файлів таблиць зовсім не обов'язково збігаються з їх oid'амі з pg_class. і вони можуть змінитися після запуску VACUUM FULL, TRUNCATE та інших. Наприклад:

Отже. Як перетворити цей шлях назад в ім'я відносини?

Oid'и бази даних і filenode ids відносини

Припустимо, Ви отримали помилку з початку цієї статті. Її можна розбити на кілька частин:

  • base: в табличному просторі за замовчуванням
  • 16396: в базі даних з oid'ом 16396
  • 3720450 filenode id для таблиці з oid'ом 3720450

після чого розглянути що означає кожна з них.

Визначення бази даних по oid

По-перше, необхідно підключитися до будь-якої базі даних в цьому PostgreSQl процесі і виконати:

(Або будь-який інший oid бази, який ви маєте). Це поверне Вам ім'я бази даних.

Після цього необхідно підключитися до цієї бази.

Зворотне перетворення relfilenodes на 9.4 версії

Якщо Ви використовуєте версію 9.4, або більш свіжу, то для Вас наступна частина проста:

(0 означає «табличний простір за замовчуванням»)

Ця функція виконує зворотне перетворення relfilenode за вас. Таким чином, вона просто покаже Вам ім'я таблиці. Для нього не буде показаний зв'язок з якоюсь схемою, якщо отримане ім'я таблиці належить поточному search_path; Можна використовувати SET search_path = ''; перед виконанням функції, для того, щоб був зазначений шлях аж до схеми.

Ви повинні бути підключені до правильної базі даних, або буде отримано неправильну відповідь, або взагалі відповідь не буде отримана.

Зворотне перетворення relfilenodes на 9.3 версії

Якщо ви використовуєте версію 9.3, або старіше, необхідно підключитися до бази даних, в якій знаходиться таблиця і виконати наступний запит до pg_class:

(Або будь-який інший отриманий relfilenode id таблиці).

Це розповість Вам про те, до якої таблиці відноситься ця помилка.

Немає результатів?

Що ж, зазвичай це допомагає.

Relfilenode також може бути нулем, це в свою чергу означає, що файл розташований за допомогою pg_relfilenode.map. Це є типовим сценарієм для загальних і деяких системних каталогів, їх індексів, TOAST таблиць і т.д. Наприклад, це можуть бути pg_database. pg_class і pg_proc.

Що щодо схеми?

Ви звернули увагу, що схема (простір імен) не фігурує в дорозі?

У PostgreSQL схеми є тільки простором імен всередині бази даних. Вони не мають ніякого впливу на те, де фізично зберігаються таблиці на диску.

Інші шляхи табличних просторів

Недавній випадок, з яким я зіткнувся, був наступною помилкою:

Це не табличний простір за замовчуванням, так як шлях починається з pg_tblspc.

Сам процес знаходження таблиці насправді той же. Можна проігнорувати pg_tblspc / nnn / PG_n.n_nnnnnn / частина і сфокусуватися відразу наdatabase_oid / relation_oid. як описано вище для випадків з табличним простором за замовчуванням. Для цього варто розуміти що означає шлях.

Таким чином текст помилки розбивається на наступні частини:

Ми вже обговорювали частина про oid'е бази даних і табличному relfilenode id. Вони не відрізняються від табличного простору, тільки починаються в іншому місці.

Так що щодо частини з табличним простором?

Oid відноситься до pg_tablespace записи для табличного простору, як видно з:

Всередині директорії табличного простору, є ще одна директорія, що має назву, яка відповідає версії PostgreSQL. Воно статично для цієї версії і єдине застосування цього - це множинний доступ декількох PostgreSQL процесів до одного табличному простору, наприклад, під час pg_upgrade. Як правило, є тільки один запис.

В цілому ж, структура та ж як і для base / шляхів - спочатку oid бази даних, потім oid відносини.

Глобальні (загальні) таблиці

Шляхи до них починаються з global замість base і у них відсутній компонент з oid'ом бази даних.

Загальні каталоги не зазначені relfilenode в pg_class. Тобто Ви не зможете подивитися, наприклад, pg_database з pg_class. pg_filenode_relation повертає null, незалежно від того, чи викликати його з oid'ом табличного простору за замовчуванням, або ж з oid'ом глобального табличного простору 1664.

З'ясування цього є темою для наступної статті з розібраними зв'язками.

Звичайно ж, якщо ви відчуваєте проблеми з загальними каталогами, ви, швидше за все, не зможете в принципі запустити базу даних.

Маючи справу з ушкодженнями

Пошкодження бази даних не повинно траплятися. Але воно може відбутися в будь-якому випадку. Це можуть бути проблеми з залізом, баги ядра, або файлової системи, ССД, які брешуть про вчинення надійних дискових припливах, глючний мережі зберігання даних, ну і звичайно ж баги самого PostgreSQL. Якщо Ви підозрюєте пошкодження бази даних, перед тим як що небудь зробити, прочитайте і дійте за порадами з вікі сторінки про пошкодження.

нутрощі

Щоб побачити як все це працює, запустіть макрос relpathbackend в src / include / common / relpath.h. Він викликає GetRelationPath в src / common / relpath.c.