Blog JSystems - uwalniamy wiedzę!

Szukaj

PostgreSQL

Po co są schematy i jak je organizować w PostgreSQL

W skrócie

  • Wszystkie tabele lądują w jednym worku o nazwie public, robi się bałagan, a nazwy zaczynają się dublować między modułami czy zespołami.
  • PostgreSQL ma schematy - przestrzenie nazw wewnątrz jednej bazy - ale wielu ludzi ich nie używa i nie wie, jak działa search_path, który decyduje, co widać bez prefiksu.
  • Projektujemy podział na schematy pod moduły albo role, nadajemy uprawnienia na poziomie schematu i ustawiamy search_path, żeby zapytania były czytelne.

W młodej bazie wszystko trafia do schematu public i nikomu to nie przeszkadza. Problem pojawia się z czasem: setki tabel w jednym miejscu, kolizje nazw między modułami, brak sposobu na nadanie uprawnień "na cały obszar aplikacji". Rozwiązaniem, które PostgreSQL ma od zawsze, są schematy - lekkie przestrzenie nazw wewnątrz bazy. Dobrze użyte porządkują strukturę, upraszczają uprawnienia i pozwalają trzymać dane różnych modułów obok siebie bez konfliktów.

Jak to wygląda w praktyce

Aplikacja rośnie i w schemacie public masz już tabele sprzedaży, magazynu, raportowania i kilku integracji - kilkaset obiektów w jednym worku. Dwa moduły chcą mieć tabelę o nazwie zamowienia, ale nie mogą, bo nazwa musi być unikalna w obrębie schematu. Nadanie komuś dostępu tylko do części tabel wymaga wyliczania ich pojedynczo, bo nie ma naturalnej granicy, którą można objąć jednym GRANT. Do tego dochodzi zamieszanie z widocznością: piszesz SELECT * FROM cennik i dostajesz "relation cennik does not exist", choć tabela istnieje - tyle że w innym schemacie niż ten na Twojej ścieżce wyszukiwania. Bez uporządkowania w schematy każdy taki drobiazg mnoży się z liczbą obiektów.

Dlaczego tak się dzieje

Schemat w PostgreSQL to nazwana przestrzeń, wewnątrz której nazwy obiektów muszą być unikalne, ale między schematami mogą się powtarzać - dlatego sprzedaz.zamowienia i logistyka.zamowienia spokojnie współistnieją w jednej bazie. Każda nowa baza dostaje domyślny schemat public, więc jeśli nie zrobisz nic więcej, wszystko trafia właśnie tam. O tym, które schematy widać bez podawania pełnej nazwy, decyduje parametr search_path - lista schematów przeszukiwanych po kolei. Domyślnie zawiera on schemat o nazwie roli i public. Jeśli tabela leży poza ścieżką, musisz odwołać się do niej z prefiksem schematu, inaczej PostgreSQL jej nie znajdzie. To wyjaśnia zarówno "relation does not exist" przy istniejącej tabeli, jak i to, dlaczego uprawnienia warto nadawać na poziomie schematu: schemat jest naturalną, obejmowalną granicą, na której można ustawić dostęp i domyślne uprawnienia dla przyszłych obiektów.

Jak to rozwiązać krok po kroku

  1. Wybierz zasadę podziału i trzymaj się jej: albo schemat na moduł aplikacji (sprzedaz, magazyn, raporty), albo schemat na środowisko/zespół. Spójna konwencja jest ważniejsza niż to, którą wybierzesz.
  2. Twórz schematy jawnie, najlepiej od razu z właścicielem: CREATE SCHEMA sprzedaz AUTHORIZATION rola_sprzedaz;. Właściciel schematu może swobodnie zakładać w nim obiekty.
  3. Nadaj dostęp na poziomie schematu, zamiast wyliczać tabele: GRANT USAGE ON SCHEMA sprzedaz TO rola_raporty; pozwala wejść do schematu, a GRANT SELECT ON ALL TABLES IN SCHEMA sprzedaz TO rola_raporty; daje odczyt istniejących tabel.
  4. Zadbaj o przyszłe obiekty przez domyślne uprawnienia, żeby nowe tabele automatycznie były dostępne dla właściwych ról: ALTER DEFAULT PRIVILEGES IN SCHEMA sprzedaz GRANT SELECT ON TABLES TO rola_raporty;.
  5. Ustaw search_path tak, by codzienne zapytania nie wymagały prefiksów. Dla roli: ALTER ROLE analityk SET search_path = raporty, sprzedaz, public; - PostgreSQL będzie szukał obiektów w tej kolejności.
  6. W kodzie i migracjach o krytycznym znaczeniu odwołuj się do obiektów z pełną nazwą schemat.tabela, żeby wynik nie zależał od bieżącej ścieżki wyszukiwania.

Jak sprawdzić, że zadziałało

Listę schematów w bazie zobaczysz w psql poleceniem \dn albo zapytaniem SELECT schema_name FROM information_schema.schemata;. Rozłożenie obiektów sprawdzisz przez SELECT schemaname, count(*) FROM pg_tables GROUP BY schemaname; - powinno pokazać, że tabele faktycznie rozeszły się po schematach, a nie tkwią w public. Aktualną ścieżkę wyszukiwania odczytasz przez SHOW search_path;, a to, że działa zgodnie z zamiarem, potwierdzi udane zapytanie bez prefiksu do tabeli z pierwszego schematu na liście. Poprawność uprawnień najłatwiej zweryfikować, logując się jako dana rola i próbując odczytać tabelę: dostęp powinien działać na schematach, do których nadałeś USAGE i SELECT, a być odrzucony tam, gdzie roli nie dopuściłeś. Domyślne uprawnienia dla przyszłych obiektów obejrzysz przez \ddp.

Wróć do listy: 100 najczęstszych pytań i problemów z PostgreSQL

Szkolenie Administracja, replikacja i tuning baz danych PostgreSQL

Sprawdź szkolenie: Administracja, replikacja i tuning baz danych PostgreSQL

To szkolenie może być dofinansowane z KFS lub BUR.

★★★★★Średnia ocena naszych szkoleń w Google: 5/5

Szkolenie Zaawansowana administracja PostgreSQL - HA, DR, monitoring, skalowanie

Sprawdź szkolenie: Zaawansowana administracja PostgreSQL (HA, DR, monitoring, skalowanie)

To szkolenie może być dofinansowane z KFS lub BUR.

★★★★★Średnia ocena naszych szkoleń w Google: 5/5

Najczęściej zadawane pytania

Czym jest schemat w PostgreSQL?
To nazwana przestrzeń nazw wewnątrz jednej bazy danych. Nazwy obiektów muszą być unikalne w obrębie schematu, ale mogą się powtarzać między schematami, dzięki czemu sprzedaz.zamowienia i logistyka.zamowienia współistnieją w tej samej bazie. Każda nowa baza ma domyślny schemat public.
Do czego służy search_path?
To lista schematów przeszukiwanych po kolei przy odwołaniach do obiektów bez prefiksu. Jeśli tabela leży poza search_path, PostgreSQL jej nie znajdzie i zgłosi relation does not exist, mimo że tabela istnieje. Aktualną ścieżkę sprawdzisz przez SHOW search_path;.
Jak nadać dostęp do wszystkich tabel w schemacie bez wyliczania ich pojedynczo?
Najpierw GRANT USAGE ON SCHEMA schemat TO rola; aby wpuścić rolę do schematu, potem GRANT SELECT ON ALL TABLES IN SCHEMA schemat TO rola; dla istniejących tabel. Aby objąć też przyszłe tabele, ustaw ALTER DEFAULT PRIVILEGES IN SCHEMA schemat GRANT SELECT ON TABLES TO rola;.
Jak sprawić, żeby zapytania nie wymagały prefiksu schematu?
Ustaw search_path dla roli, na przykład ALTER ROLE analityk SET search_path = raporty, sprzedaz, public;. PostgreSQL będzie szukał obiektów w tej kolejności. W krytycznym kodzie i migracjach mimo to używaj pełnej nazwy schemat.tabela, żeby wynik nie zależał od bieżącej ścieżki.

Komentarze (0)

Musisz być zalogowany by móc dodać komentarz. Zaloguj się przez Google

Brak komentarzy...