Klucz obcy niewymuszany: dlaczego hurtownia danych wpuszcza sieroty
|
6
min. czyt.

Dodajesz w hurtowni danych klucz obcy z fact_sales.customer_id do dim_customer. DDL się wykonuje, nocne ładowanie też, a następnego ranka partia nowych wierszy sprzedaży wskazuje na klientów, którzy nie istnieją. Nic nie zawiodło, bo nic niczego nie sprawdzało. W Snowflake, BigQuery, Amazon Redshift i Databricks klucz obcy nie jest wymuszany: platforma zapisuje deklarację jako metadane, ale przyjmuje wiersze, których klucz nie ma dopasowania w tabeli nadrzędnej.
To samo dotyczy kluczy głównych i ograniczeń unikalności. Zaskakuje to osoby wychowane na PostgreSQL, Oracle czy SQL Server, gdzie zadeklarowany klucz obcy odrzuca błędny wiersz już przy wstawianiu. W chmurowej hurtowni danych deklaracja to obietnica, którą składasz Ty, a nie reguła, której baza danych pilnuje za Ciebie. Niektóre planery zapytań wręcz wierzą tej obietnicy i wykorzystują ją do upraszczania złączeń.
Ten artykuł zestawia, co wymusza każda z platform (z linkami do dokumentacji dostawców), wyjaśnia, dlaczego hurtownie danych idą na ten kompromis, pokazuje, jak naruszony klucz może zamienić się w błędną liczbę, i opisuje, co uruchamiać zamiast tego. Ogólną ideę wierszy nadrzędnych i podrzędnych oraz to, czym jest rekord osierocony, wyjaśnia nasz główny artykuł Czy Twoje dane wciąż odnajdują swoich rodziców? Integralność referencyjna w praktyce.
Najważniejsze wnioski
Snowflake (tabele standardowe), BigQuery, Redshift i Databricks przyjmują deklaracje kluczy głównych, obcych i unikalnych, ale ich nie wymuszają. Wyjątkiem są tabele hybrydowe (hybrid tables) w Snowflake.
NOT NULL jest wymuszane w Snowflake, Redshift i Databricks; Databricks wymusza także ograniczenia CHECK.
Redshift i BigQuery wykorzystują zadeklarowane klucze przy planowaniu zapytań. Jeśli klucze są błędne, niektóre zapytania mogą zwrócić nieprawidłowe wyniki bez żadnego błędu.
Deklaruj klucze tylko wtedy, gdy dane zostały zwalidowane, i waliduj je ponownie po każdym ładowaniu kontrolą integralności referencyjnej.
Traktuj NOT NULL jako osobną regułę i pilnuj odwołań przekraczających granice systemów, gdzie żadne ograniczenie w ogóle nie może istnieć.
Spis treści
Co oznacza „klucz obcy niewymuszany”?
Które hurtownie danych wymuszają klucze główne i obce?
Dlaczego hurtownie danych nie wymuszają kluczy obcych?
Jak niewymuszany klucz może dać błędne wyniki zapytań?
Jak chronić integralność referencyjną w hurtowni danych?
Kontrola złączeniem wykluczającym w SQL
Jak wygląda kontrola integralności referencyjnej w digna?
Co dalej
Co oznacza „klucz obcy niewymuszany”?
Niewymuszany klucz obcy to deklaracja, którą baza danych zapisuje, ale nigdy nie sprawdza. Możesz napisać FOREIGN KEY (customer_id) REFERENCES dim_customer (customer_id), a platforma ją zapisze, pokaże w katalogu i udostępni narzędziom, a mimo to załaduje wiersz, którego customer_id nie ma rekordu nadrzędnego.
Dostawcy nazywają je ograniczeniami informacyjnymi (informational constraints). Opisują one zamierzony kształt danych: która kolumna identyfikuje wiersz, która kolumna wskazuje na którą tabelę. Narzędzia BI, katalogi danych i narzędzia do modelowania odczytują je, by rysować diagramy i podpowiadać złączenia. Niektóre optymalizatory zapytań też je odczytują. Nie zatrzymują jednak ładowania, nie zgłaszają błędu i nie oznaczają sierot.
W hurtowni danych „klucz jest zadeklarowany” i „klucz jest spełniony” to więc dwa różne stwierdzenia. Pierwsze to fragment DDL. Drugie to fakt dotyczący danych, który może potwierdzić tylko kontrola – i który może się zmienić przy każdym ładowaniu.
Które hurtownie danych wymuszają klucze główne i obce?
Żadna z czterech głównych chmurowych hurtowni danych nie wymusza kluczy głównych, obcych ani unikalnych w swoich standardowych tabelach. Jedynym wyjątkiem na tej liście są tabele hybrydowe w Snowflake. NOT NULL jest wymuszane w Snowflake, Redshift i Databricks, a Databricks wymusza także ograniczenia CHECK. Tabela podsumowuje dokumentację każdego dostawcy; aktualne brzmienie znajdziesz pod linkami.
Platforma | Czy PK / FK / UNIQUE są wymuszane? | Co jest wymuszane | Co planer robi z zadeklarowanymi kluczami | Dokumentacja |
|---|---|---|---|---|
Snowflake | Nie w tabelach standardowych („opcjonalne, niewymuszane”). Tak w tabelach hybrydowych. | NOT NULL; PK, FK i UNIQUE w tabelach hybrydowych | Klucze w tabelach standardowych to metadane informacyjne; zanim zaczniesz na nich polegać przy optymalizacji, sprawdź dokumentację | |
Google BigQuery | Nie. „BigQuery nie wymusza ograniczeń klucza głównego i obcego”. | Niewymuszane dla PK/FK; „To Ty odpowiadasz za utrzymanie ograniczeń przez cały czas”. | Wykorzystuje zadeklarowane klucze do eliminowania złączeń wewnętrznych i zewnętrznych oraz do zmiany ich kolejności | |
Amazon Redshift | Nie. Ograniczenia unikalności, klucza głównego i klucza obcego mają wyłącznie charakter informacyjny. | NOT NULL | Wykorzystuje klucze jako wskazówki przy planowaniu i zakłada, że po załadowaniu są prawidłowe; nieprawidłowe klucze mogą sprawić, że niektóre zapytania zwrócą błędne wyniki | |
Databricks | Nie. „Ograniczenia klucza głównego, klucza obcego i unikalności mają wyłącznie charakter informacyjny i nie są wymuszane”. | NOT NULL i CHECK | Klucze są informacyjne; zanim zaczniesz na nich polegać przy optymalizacji, sprawdź dokumentację |
W praktyce ważne są dwa szczegóły. Po pierwsze, NOT NULL to ograniczenie, któremu zwykle można ufać: w Snowflake, Redshift i Databricks wartość NULL w kolumnie NOT NULL jest odrzucana. Po drugie, tabele hybrydowe w Snowflake to inny typ tabel o innym zachowaniu; klucz obcy na zwykłej tabeli Snowflake nie daje Ci żadnego z tych wymuszeń.
Klasyczne bazy danych OLTP, takie jak PostgreSQL, Oracle, SQL Server i MySQL z InnoDB, wymuszają zadeklarowane klucze obce. Jednak hurtownia ładowana z tych baz zwykle nie przenosi tych ograniczeń, a wiele zadań ładujących wyłącza ograniczenia dla szybkości. Integralność zapewniona w systemie źródłowym nie przenosi się sama razem z danymi.
Dlaczego hurtownie danych nie wymuszają kluczy obcych?
Wymuszanie klucza obcego oznacza wyszukanie każdego przychodzącego klucza w tabeli nadrzędnej przed przyjęciem wiersza. Hurtownie danych są zbudowane do szybkiego, równoległego ładowania bardzo dużych partii, a takie wyszukiwanie dla każdego wiersza działa przeciwko obu tym celom. Dokumentacja dostawców opisuje samo zachowanie; poniższe powody to ogólny kompromis inżynierski, a nie stanowisko dostawców.
Szybkość ładowania. Masowe ładowanie milionów wierszy faktów wymagałoby milionów wyszukiwań w tabeli nadrzędnej. Pominięcie ich sprawia, że czasy ładowania są przewidywalne.
Rozproszone, równoległe ładowanie. Pamięć i moc obliczeniowa są rozłożone na wiele węzłów i plików. Sprawdzanie klucza w tabeli nadrzędnej, która sama jest równolegle ładowana, wymaga koordynacji, a to spowalnia wszystko.
Kolejność ładowania. Potoki często ładują fakty przed wymiarami lub otrzymują spóźnione wiersze wymiarów. Ścisłe wymuszanie odrzucałoby wiersze, które godzinę później byłyby prawidłowe.
Potoki oparte na dopisywaniu. Do większości tabel w hurtowni dane są dopisywane, a nie edytowane wiersz po wierszu. Model zakłada, że dane zostały przygotowane wcześniej w potoku, więc baza danych ich ponownie nie sprawdza.
Ten kompromis jest rozsądny. Haczyk polega na tym, że kontrola nie znika, tylko się przenosi. Ktoś musi ją uruchomić po załadowaniu, a w wielu zespołach nikt tego nie robi.
Jak niewymuszany klucz może dać błędne wyniki zapytań?
Niewymuszany klucz staje się niebezpieczny, gdy ufa mu planer zapytań. Amazon Redshift dokumentuje, że jego planer zakłada, iż klucze po załadowaniu są prawidłowe, i że jeśli Twoja aplikacja dopuszcza nieprawidłowe klucze obce lub główne, niektóre zapytania mogą zwrócić błędne wyniki. Klucz zadeklarowany, ale naruszony, jest gorszy niż brak klucza.
BigQuery wykorzystuje zadeklarowane klucze główne i obce do eliminowania złączeń wewnętrznych i zewnętrznych oraz do zmiany ich kolejności, a jego dokumentacja przerzuca odpowiedzialność na Ciebie: „To Ty odpowiadasz za utrzymanie ograniczeń przez cały czas”.
Oto ogólny mechanizm. Weź zapytanie, które łączy fact_sales z dim_customer, ale wybiera tylko kolumny z fact_sales. Jeśli planer ufa kluczowi obcemu, może uznać, że złączenie nie usunie żadnych wierszy, i je pominąć. Uruchom to samo zapytanie bez zadeklarowanego klucza, a INNER JOIN odrzuci każdą osieroconą sprzedaż. Ten sam raport daje teraz dwie różne sumy w zależności od planu i żaden przebieg nie zgłasza błędu.
Zduplikowane klucze główne powodują pokrewny problem: złączenie, które według wszystkich zwraca jeden wiersz na klucz, zwraca kilka, a sumy się podwajają. W obu przypadkach dashboard wygląda normalnie. Liczba jest po prostu błędna, a dowiadujesz się o tym z uzgadniania danych kilka tygodni później – o ile w ogóle.
Jak chronić integralność referencyjną w hurtowni danych?
Integralność referencyjną w hurtowni danych chronisz, traktując zadeklarowane klucze jako twierdzenia i sprawdzając je po każdym ładowaniu. Deklaruj klucz tylko wtedy, gdy dane zostały zwalidowane, uruchamiaj kontrolę integralności referencyjnej w ramach każdego przebiegu potoku i alarmuj zespół odpowiedzialny, gdy kontrola zawiedzie. Te kroki działają na każdej z czterech platform.
Spisz zadeklarowane klucze. Wiedz, które klucze obce i główne istnieją w katalogu, bo właśnie im może zaufać planer i właśnie po nich może łączyć narzędzie BI.
Deklaruj klucze tylko po walidacji. Zanim dodasz klucz, udowodnij, że jest spełniony na bieżących danych. Jeśli nie możesz go stale sprawdzać, zastanów się dwa razy, zanim go zadeklarujesz.
Waliduj po każdym ładowaniu. Uruchamiaj kontrolę integralności referencyjnej dla każdej ważnej pary podrzędny–nadrzędny w ramach potoku, a nie jako jednorazowy audyt. Ładowanie, które wnosi sieroty, powinno być widoczne tego samego dnia.
Traktuj NOT NULL jako osobną regułę. Kontrola referencyjna zwykle ignoruje klucze NULL, bo NULL na nic nie wskazuje. Jeśli każdy wiersz musi mieć rekord nadrzędny, testuj
customer_id IS NOT NULLosobno albo polegaj na wymuszanym ograniczeniu NOT NULL tam, gdzie platforma je oferuje.Pilnuj odwołań między systemami. Kartoteka produktów może znajdować się w jednej bazie danych, a transakcje w innej. Żaden klucz obcy nie obejmie dwóch systemów, więc te odwołania chroni wyłącznie kontrola.
Ustal próg i właściciela. Zdecyduj, czy jedna sierota to już niepowodzenie, czy niewielki odsetek jest akceptowalny, i kieruj wynik do zespołu, który jest właścicielem danych.
Kontrola złączeniem wykluczającym w SQL
Rdzeniem każdej kontroli integralności referencyjnej jest złączenie wykluczające (anti join): znajdź wiersze podrzędne, których klucz nie ma dopasowania w tabeli nadrzędnej.
Filtr IS NOT NULL wyklucza klucze NULL z liczby sierot, zgodnie z krokiem 4. Klucze złożone, warianty z NOT EXISTS, wydajność na dużych tabelach oraz sposoby, by nie wpuszczać sierot już przy ładowaniu, opisujemy w artykule o rekordach osieroconych: jak znaleźć je w SQL i nie dopuścić do ich powstawania.
Napisanie zapytania to łatwa część. Uruchamianie go po każdym ładowaniu, dla każdego klucza, zapisywanie liczb, alarmowanie odpowiednich osób i udostępnianie błędnych wierszy temu, kto ma je naprawić – to tu ręcznie pisany SQL zwykle nie nadąża.
Jak wygląda kontrola integralności referencyjnej w digna?
W digna kontrola integralności referencyjnej to reguła w digna Data Validation: wybierasz kolumnę w jednym źródle danych, wskazujesz odpowiadającą jej kolumnę w innym i ustawiasz próg. Nie trzeba pisać SQL. digna generuje kontrolę i uruchamia ją w Twojej hurtowni danych przy każdej inspekcji tego źródła danych.
Konfiguracja to kilka pól w oknie Add Data Validation Rule (Configuration → źródło danych → Data Validation → Add Rule):
Name (nazwa) i Description (opis), na przykład
hc_product_in_master: „Każdy podany produkt istnieje w kartotece produktów apteki”.Type: Referential Integrity (pozostałe typy to Rule i Uniqueness).
Attributes: kolumna w tym źródle danych, tutaj
product_code.must exist in: nadrzędne Data Source (
hospital_medications) i jego Attributes (product_code). Dla klucza złożonego wybierz kilka kolumn po obu stronach w tej samej kolejności; niezgodne listy kolumn są odrzucane.Threshold Mode (tryb progu) Absolute lub Relative, z Info threshold i Warn threshold. Absolute, Info 0, Warn 1 oznacza, że już jedna sierota daje status Uncertain, a dwie lub więcej powodują niepowodzenie reguły; zostaw Warn na 0, jeśli jedna sierota ma oznaczać niepowodzenie.

Reguła integralności referencyjnej w digna: każdy product_code w źródle danych z podaniami leków musi istnieć w hospital_medications.
Przykład wykorzystuje fikcyjne dane demonstracyjne z Danubia Kliniken, fikcyjnej austriackiej grupy szpitali.
2026-04-22 na oddziałach zarejestrowano 82 podania leku Coavira 2.5 mg (kod produktu 3858646), zanim produkt trafił do kartoteki produktów apteki. Reguła zgłosiła, że kontrolę przeszło 4 244 z 4 326 wierszy, i przeszła w status Failed. W widoku Invalid Records ustawiasz filtr na Failed, wybierasz kontrolę i widzisz każdy osierocony wiersz ze szpitalem, oddziałem i kodem produktu, gotowy do wyeksportowania dla osoby, która poprawia dane główne. Bez tej kontroli każdy raport łączący dawki z produktami pokazywałby zero dawek tego produktu.
Trzy właściwości odpowiadają powyższym krokom. Kontrola działa w samej hurtowni danych: digna wysyła SQL, odbiera liczby i pobiera błędne wiersze tylko wtedy, gdy o nie poprosisz; żadna tabela nie jest kopiowana na zewnątrz, a Twoje dane nigdy nie opuszczają Twojej infrastruktury. Klucze NULL są pomijane, więc obecność wartości sprawdza osobna reguła typu Rule, np. product_code IS NOT NULL. A od Release 2026.01 tabela nadrzędna może leżeć w innym schemacie, a nawet w innym połączeniu bazodanowym w tym samym projekcie, co obejmuje odwołania między systemami, do których nie sięga żadne ograniczenie. Szerszy obraz łączenia źródeł w hurtowni danych znajdziesz w naszym przewodniku po integracji hurtowni danych; pełny opis reguły pole po polu – w artykule o konfigurowaniu kontroli integralności referencyjnej.
Co dalej
Niewymuszany klucz obcy nie jest błędem w Twojej hurtowni danych. To decyzja projektowa, która oddaje sprawdzanie w Twoje ręce. Deklaruj klucze tam, gdzie pomagają narzędziom i planerom, ale dopiero gdy udowodnisz, że dane do nich pasują – i udowadniaj to ponownie po każdym ładowaniu. Kontrola integralności referencyjnej uruchamiana przy każdej inspekcji, w hurtowni danych, z progiem i właścicielem, zamyka lukę, którą zostawiła platforma.
Jeśli chcesz zobaczyć to w działaniu na tabelach własnej hurtowni danych, umów się na demo z zespołem digna.
Najczęściej zadawane pytania
Czy Snowflake wymusza klucze obce?
Nie w tabelach standardowych. Snowflake opisuje tam klucze główne, obce i unikalne jako opcjonalne i niewymuszane, natomiast NOT NULL jest wymuszane. Wyjątkiem są tabele hybrydowe: w nich ograniczenia PK, FK i UNIQUE są wymuszane. Osierocone wiersze w tabeli standardowej ładują się więc bez żadnego błędu.
Czy niewymuszane klucze obce mogą powodować błędne wyniki zapytań?
Tak, gdy planer im ufa. Amazon Redshift stwierdza, że jego planer zakłada, iż klucze po załadowaniu są prawidłowe, więc nieprawidłowe klucze mogą sprawić, że niektóre zapytania zwrócą błędne wyniki. BigQuery wykorzystuje zadeklarowane klucze do eliminowania złączeń i zmiany ich kolejności i zaznacza, że to Ty odpowiadasz za utrzymanie ograniczeń.
Czym są ograniczenia informacyjne w hurtowni danych?
Ograniczenia informacyjne to klucze główne, obce lub unikalne, które platforma zapisuje jako metadane, ale ich nie sprawdza. Databricks i Amazon Redshift opisują swoje ograniczenia kluczy jako wyłącznie informacyjne. Narzędzia i planery mogą je odczytywać, a jednak wiersze, które je naruszają, nadal się ładują, dlatego potrzebna jest osobna kontrola walidacyjna.
Czy nadal warto deklarować klucze obce w Redshift lub BigQuery?
Deklaruj je tylko wtedy, gdy dane zostały zwalidowane i nadal je walidujesz. Obie platformy wykorzystują zadeklarowane klucze przy planowaniu zapytań, więc klucz zadeklarowany, ale naruszony, może zmienić wyniki. Zanim zaufasz deklaracji, uruchamiaj kontrolę integralności referencyjnej po każdym ładowaniu.
Jak sprawdzać integralność referencyjną, gdy hurtownia danych jej nie wymusza?
Uruchamiaj złączenie wykluczające po każdym ładowaniu: wybierz wiersze podrzędne, których klucz nie ma pasującego rekordu nadrzędnego, z pominięciem wartości NULL. W digna Data Validation jest to reguła Referential Integrity z progiem, wykonywana w hurtowni danych przy każdej inspekcji, a błędne wiersze pojawiają się w widoku Invalid Records.



