Co się stało z ograniczeniami bazy danych?


46

Kiedy przeglądam modele baz danych dla RDBMS, zwykle jestem zaskoczony, że nie znam żadnych ograniczeń (oprócz PK / FK). Na przykład wartość procentowa jest często przechowywana w kolumnie typu int(choć tinyintbyłoby bardziej odpowiednie) i nie ma CHECKograniczenia, aby ograniczyć wartość do zakresu 0..100. Podobnie w przypadku SE.SE odpowiedzi sugerujące ograniczenia sprawdzania często otrzymują komentarze sugerujące, że baza danych jest nieodpowiednim miejscem dla ograniczeń.

Kiedy pytam o decyzję o niewdrożeniu ograniczeń, członkowie zespołu odpowiadają:

  • Albo, że nawet nie wiedzą, że takie funkcje istnieją w ich ulubionej bazie danych. Jest to zrozumiałe dla programistów używających tylko ORM, ale znacznie mniej od DBA, którzy twierdzą, że mają ponad 5-letnie doświadczenie w danym RDBMS.

  • Albo że egzekwują takie ograniczenia na poziomie aplikacji, a powielanie tych reguł w bazie danych nie jest dobrym pomysłem, ponieważ narusza SSOT.

Ostatnio widzę coraz więcej projektów, w których nawet klucze obce nie są używane. Podobnie, widziałem tutaj kilka komentarzy na temat SE.SE, które pokazują, że użytkownicy nie dbają zbytnio o integralność referencyjną, pozwalając aplikacji to obsłużyć.

Pytając drużyny o wybór, aby nie używać FK, mówią, że:

  • Jest to PITA, na przykład, gdy trzeba usunąć element, do którego odwołują się inne tabele.

  • Skały NoSQL i nie ma tam obcych kluczy. Dlatego nie potrzebujemy ich w RDBMS.

  • To nie jest wielka sprawa pod względem wydajności (kontekst to zwykle małe intranetowe aplikacje internetowe działające na małych zestawach danych, więc nawet indeksy nie miałyby większego znaczenia; nikogo nie obchodziło by, że wydajność danego zapytania przejdzie od 1,5 s . do 20 ms.)

Kiedy patrzę na samą aplikację, systematycznie zauważam dwa wzorce:

  • Aplikacja prawidłowo dezynfekuje dane i sprawdza je przed wysłaniem do bazy danych. Na przykład nie ma możliwości przechowywania wartości 102jako wartości procentowej przez aplikację.

  • Aplikacja zakłada, że ​​wszystkie dane pochodzące z bazy danych są całkowicie poprawne. To znaczy, jeśli 102przychodzi w procentach, albo coś, gdzieś się zawiesi, albo po prostu zostanie wyświetlone tak, jak jest dla użytkownika, co prowadzi do dziwnych sytuacji.

  • Podczas gdy ponad 99% zapytań jest wykonywanych przez pojedynczą aplikację, z czasem pojawiają się skrypty - albo skrypty uruchamiane ręcznie w razie potrzeby, albo zadania cron. Niektóre operacje na danych są również wykonywane ręcznie na samej bazie danych. Zarówno skrypty, jak i ręczne zapytania SQL mają wysokie ryzyko wprowadzenia nieprawidłowych wartości.

I tu pojawia się moje pytanie:

Jakie są powody modelowania relacyjnych baz danych bez ograniczeń sprawdzania, a ostatecznie nawet bez kluczy obcych?


To, co jest warte, to pytanie i odpowiedzi, które otrzymałem (szczególnie interesująca dyskusja z Thomasem Kilianem) skłoniły mnie do napisania artykułu z moimi wnioskami na temat ograniczeń bazy danych .


8
Współczuję tobie, ale wydaje się, że już wiesz, dlaczego ograniczenia są dobrym pomysłem, więc nie ma wiele do dodania w postaci odpowiedzi. Zauważę jednak, że brak ograniczeń nie jest nowym zjawiskiem, widziałem to od dziesięcioleci w bazach danych zaprojektowanych przez programistów bez silnego zrozumienia relacyjnych baz danych. Myślę, że rzadko jest to celowa decyzja projektowa.
JacquesB

1
@JacquesB: możesz opublikować odpowiedź, ponieważ „widziałem to od dziesięcioleci” daje zupełnie inną wizję tego, co miałem przed fenomenem, który pojawił się trzy cztery lata temu (biorąc pod uwagę, że pracowałem w branży IT krócej niż dekada, mój pogląd na to zjawisko jest prawdopodobnie błędny). Zatem wnioski byłyby również bardzo różne.
Arseni Mourzenko

1
Współpracujemy z wieloma klientami. Podczas gdy wprowadzanie nowej wersji naszego oprogramowania jest bułką z masłem, aktualizowanie wszystkich schematów baz danych wszędzie jest uciążliwe. Dlatego mamy najwięcej ograniczeń w oprogramowaniu. O tak, malutki procent nie zawsze jest dobrym pomysłem, ponieważ procenty mogą być ułamkami.
Pieter B

1
Głosowanie w celu ponownego otwarcia tego pytania, ponieważ zostało ono błędnie zamknięte jako „oparte głównie na opiniach”, gdy dotychczasowe odpowiedzi wskazują, że tak nie jest.
David Arno

3
Jestem z tobą 110%.
Periata Breatta

Odpowiedzi:


28

Ważne jest, aby rozróżniać różne przypadki użycia baz danych.

Dostęp do tradycyjnej biznesowej bazy danych uzyskuje wiele niezależnych aplikacji i usług oraz być może bezpośrednio autoryzowani użytkownicy. Kluczowe znaczenie ma dobrze przemyślany schemat i ograniczenia na poziomie bazy danych, aby błąd lub niedopatrzenie w jednej aplikacji nie uszkodziło bazy danych. Baza danych ma krytyczne znaczenie dla biznesu, co oznacza, że ​​niespójne lub uszkodzone dane mogą mieć katastrofalne skutki dla firmy. Dane będą żyły wiecznie, dopóki aplikacje pojawią się i znikną. Są to miejsca, które mogą mieć dedykowane DBA w celu zapewnienia spójności i kondycji bazy danych.

Ale są też systemy, w których baza danych jest ściśle zintegrowana z jedną aplikacją. Autonomiczne aplikacje lub aplikacja internetowa z jedną osadzoną bazą danych. Tak długo, jak dostęp do bazy danych ma wyłącznie jedna aplikacja, można uznać ograniczenia za zbędne - o ile aplikacja działa poprawnie. Systemy te są często opracowywane przez programistów z naciskiem na kod aplikacji i być może nie dogłębnie rozumieją modelu relacyjnego. Jeśli aplikacja używa ORM, ograniczenia mogą być deklarowane na poziomie ORM w formie bardziej znanej programistom aplikacji. W dolnej części mamy aplikacje PHP korzystające z MySQL i przez długi czas MySQL wcale nie obsługiwał podstawowych ograniczeń, więc trzeba było polegać na warstwie aplikacji, aby zapewnić spójność.

Gdy spotykają się programiści z różnych środowisk, dochodzi do starcia kulturowego.

Do tego miksu wprowadzamy nową falę rozproszonych baz danych „w chmurze”. Bardzo trudno jest zachować spójność rozproszonej bazy danych bez utraty wydajności, dlatego te bazy danych często unikają kontroli spójności na poziomie bazy danych i zasadniczo pozwalają programistom obsługiwać ją na poziomie aplikacji. Różne aplikacje mają różne wymagania dotyczące spójności, a chociaż wyszukiwarka Googles stawia na pierwszym miejscu dostępność zamiast spójności na swoich serwerach, jestem skłonna założyć się, że ich system płac działa na relacyjnej bazie danych z wieloma ograniczeniami.


5
+! 1 za wzmiankę o słoniu w pokoju: fałszywe założenie, że jedna aplikacja używa tylko jednego DB, a jeden DB jest używany tylko przez jedną aplikację
Tulains Córdova

4
@ TulainsCórdova, myślałem, że słoń w pokoju tutaj to system płac Google. :)
Machado

5
@Machado To genialne: „Jestem gotów się założyć, że ich system płac działa na relacyjnej bazie danych z wieloma ograniczeniami”.
Tulains Córdova

2
Przydatne jest również posiadanie odpowiednio ograniczonych baz danych, ponieważ kod aplikacji nie jest ACID.
Matthew Whited

3
Aby podkreślić komentarz autorstwa @MatthewWhited, aplikacje nie mogą wymuszać pewnych ograniczeń między wierszami / tabelami bez wykonywania blokowania i uruchamiania dodatkowych zapytań. RDBMS może to zrobić przy znacznie niższych kosztach.
David Aldridge,

15

Obecnie coraz więcej systemów działa w środowiskach rozproszonych, w chmurze i stosuje technikę „skalowania w górę” zamiast „skalowania w górę”. Jest to jeszcze ważniejsze, jeśli masz do czynienia z aplikacjami internetowymi, takimi jak aplikacje e-commerce.

To powiedziawszy, wszystkie aplikacje, które mają być skalowane, są ograniczone przez Twierdzenie CAP , w którym musisz wybrać 2 z 3: Spójność, dostępność i tolerancja partycji (tolerancja na awarie sieci).

Studiując Twierdzenie CAP, zobaczysz, że nie ma dużego wyboru, ale musisz stracić Dostępność lub Spójność, ponieważ NIGDY nie możesz naprawdę ufać sieci w 100%.

Zasadniczo niektóre aplikacje mogą być niespójne przez pewien rozsądny czas, ale nie mogą być niedostępne dla użytkowników. Na przykład nieco nieuporządkowana oś czasu na Facebooku lub Twitterze jest lepsza niż brak dostępu do osi czasu.

W związku z tym kilka aplikacji decyduje się na zniesienie ograniczeń relacyjnych baz danych, ponieważ relacyjne bazy danych są naprawdę dobre pod względem spójności, ale kosztem dostępności.

Osobista uwaga: jestem też staroświecki i pracuję z kilkoma naprawdę starymi systemami finansowymi, w których spójność danych jest przez większość czasu wymogiem najwyższej jakości, a ja jestem wielkim fanem ograniczeń bazy danych. Ograniczenia bazy danych są ostatnią linią obrony przed latami złego rozwoju i zespołami programistów, którzy przychodzą i odchodzą.

„Est modus in rebus”. Używajmy spójność „niskiego poziomu” DB, gdzie spójność jest wymogiem pierwszej klasy. Ale czasem odpuszczenie go wcale nie jest wielkim grzechem.

-- EDYTOWAĆ: --

Ponieważ w pytaniu jest niewielka zmiana, istnieje inny uzasadniony powód, aby porzucić ograniczenia w bazie danych, IMO. Jeśli projektujesz produkt od zera, w którym projektujesz system do obsługi technologii wielu baz danych, możesz zadowolić się najmniejszym wspólnym mianownikiem wśród obsługiwanych baz danych, a ostatecznie zrezygnować z jakichkolwiek ograniczeń, pozostawiając całą logikę sterowania Twoje zgłoszenie.

Chociaż jest to uzasadnione, dla mnie jest to również szara strefa, ponieważ po prostu nie mogę dziś znaleźć żadnego silnika bazy danych, który nie obsługuje prostych ograniczeń, takich jak ten zaproponowany w pierwotnym pytaniu.


„Po prostu nie mogę dziś znaleźć żadnego silnika bazy danych, który nie obsługuje prostych ograniczeń, takich jak ten zaproponowany w pierwotnym pytaniu”. Czy MySQL obsługuje już ograniczenia CHECK?
Vincent Savard

@VincentSavard, może nie jest to dokładnie KONTROLA MS SQL, ale pewne ograniczenia: dev.mysql.com/doc/refman/5.7/en/constraint-invalid-data.html
Machado

@ Machado - nie chodzi tu jednak o konkretne ograniczenia, ale o identyfikację, kiedy zapytania zawierają dane, których nie można przedstawić w odpowiednich typach. Jest to wyraźna poprawa sytuacji sprzed lat, kiedy MySQL po prostu cicho ignorował takie wartości.
Periata Breatta

1
@PeriataBreatta, na marginesie, nigdy w pełni nie rozumiałem, dlaczego MySQL była de facto bazą danych OSS wybraną przez twórców stron, kiedy PostgreSQL był w pełni dostępny i był bardziej zaawansowany. Może łatwiej było zainstalować, nie wiem.
Machado,

@machado - nie jestem pewien , ale wiem, że na początku (w połowie lat 90.) wolałem mysql od postgres (który później nie został przemianowany na postgresql) z powodu błędnego przekonania, że ​​postgres nie obsługiwał SQL (jego wczesne wersje nie - miał własny język zapytań o nazwie „postquel”), a ja nie śledziłem jego rozwoju, więc nie zdawałem sobie sprawy, że dodali obsługę SQL około w tym samym czasie, gdy mysql stał się dostępny). Jeśli to nieporozumienie było powszechne, możliwe, że mysql właśnie z tego powodu. A kiedy było już przed nami, przejęły ją efekty sieciowe.
Periata Breatta

10

Jakie są powody modelowania relacyjnych baz danych bez ograniczeń sprawdzania, a ostatecznie nawet bez kluczy obcych?

Najpierw wyjaśnijmy, że mówię tu tylko o RDBM, a nie o bazach danych bez SQL.

Widziałem kilka baz danych bez FK i PK, nie mówiąc już o sprawdzaniu ograniczeń, ale szczerze mówiąc, stanowią one mniejszość. Być może dlatego, że pracuję w dużej firmie.

Z mojego doświadczenia mogę stwierdzić, że niektóre powody mogą być:

  • W przypadku początkujących lub programistów hobbystycznych sprawdzenie umiejętności modelowania
  • Szerokie lub prawie wyłączne korzystanie z ORM bez rzeczywistego kontaktu ze światem baz danych
  • Brak DBA lub innego eksperta do modelowania danych w zespole lub małym projekcie
  • Brak zaangażowania eksperta DBA lub modelowania danych w pierwszych etapach rozwoju
  • Celowe decyzje projektowe przez część społeczności programistów, który uważa, że nawet ograniczenie wyboru, który wymusza, że pewna kolumna może mieć tylko 1,2 or 3jako wartość, albo że „wiek” kolumna musi być >= 0to „mieć logiki biznesowej w bazie danych” . Nawet klauzule domyślne są przez niektórych uważane za logikę biznesową, która nie należy do bazy danych, jak widać w kilku ostatnich pytaniach i odpowiedziach na tej samej stronie. Programiści, którzy tak rozważają, oczywiście wykorzystaliby jak najmniej ograniczeń i zrobią wszystko w kodzie, nawet referencyjną integralność i / lub jedność. Myślę, że to skrajna pozycja.
  • Wykorzystanie RDBM jako magazynów klucz-wartość , albo do emulacji zachowania bez SQL, ponieważ wymagania były wystarczająco proste, aby je spełnić, używając tabel RDBMS jako izolatorów repozytoriów klucz-wartość.
  • Zakładając, że baza danych będzie zawsze zapisywana przez „aplikację” i że nikt nigdy nie będzie musiał wykonywać masowego ładowania danych, ani edytować ani wstawiać wierszy za pomocą klienta SQL (w wielu przypadkach w celu poprawienia złych danych wstawiona aplikacja). W najlepszym przypadku escenario zawsze będzie inna aplikacja (oprócz „aplikacji”) wysyłająca instrukcje DML do bazy danych: klient SQL.
  • Nie zdaje sobie sprawy, że dane należą do właściciela firmy , a nie do aplikacji.

To powiedziawszy, chciałbym stwierdzić, że RDBMS to bardzo zaawansowane oprogramowanie, które zostało zbudowane na barkach gigantów i okazało się bardzo wydajne w przypadku wielu wymagań biznesowych, uwalniając programistów od przyziemnych zadań polegających na egzekwowaniu integralności referencyjnej w szeregu plików binarnych lub plików tekstowych. Jak zawsze mówię „nie żyjemy już w świecie jednej aplikacji i jednej bazy danych” . Przynajmniej klient SQL będzie wydawał pliki DML oprócz „aplikacji”. Baza danych powinna więc bronić się w rozsądnym stopniu przed błędami ludzkimi lub programowymi

W tych dobrze znanych typach wymagań, w których RDBMS nie skaluje się dobrze, zdecydowanie obejmuje technologię bez SQL . Niepokoi jednak rozprzestrzenianie się relacyjnych baz danych bez ograniczeń, w których tysiące linii kodu (generowanych lub wpisywanych) jest poświęconych egzekwowaniu tego, co RDBMS powinien dla Ciebie egzekwować w bardziej wydajny sposób.


3

Istnieją zewnętrzne ograniczenia, które wpływają na decyzje technologiczne. Jest tylko kilka sytuacji, w których masz potrzebę lub luksus korzystania z ograniczeń pola bazy danych na bieżąco.

  1. Przedsiębiorstwa mają programistów dla aplikacji i baz danych wraz z DBA, ale większość programistów nie działa w tego typu środowisku. Robią tyle, ile mogą w kodzie. Ponadto niektórzy po stronie bazy danych nie angażują się w reguły biznesowe. Są przede wszystkim po to, aby utrzymać działanie. Nigdy nie będą naciskać na ograniczenia w db. W przypadku starszych aplikacji, integracji, migracji, fuzji i przejęć ograniczenie bazy danych może być najlepszym rozwiązaniem.
  2. Przeładowanie bazy danych może stworzyć wąskie gardło, którego nie można łatwo rozwiązać, rzucając więcej maszyn na problem. Istnieją sytuacje, w których język db nie radzi sobie z niektórymi problemami programistycznymi bez poważnego spadku wydajności, więc nie można planować używania ograniczenia do wszystkiego. Stackoverflow ma jeden serwer bazy danych, ponieważ rzucenie 2 w problem jest wyzwaniem.
  3. Zautomatyzowane testowanie - docierają tam, ale wielu programistów db spóźnia się na imprezę wraz z ramami IDE / testowania.
  4. Wdrażanie - więcej db db komplikuje to. Co się stanie, gdy aktualizacja bazy danych klienta nie jest dozwolona, ​​ponieważ istnieją dane, które naruszają to ograniczenie? Koniec gry, chyba że masz sposób na rozwiązanie tego problemu. W aplikacji możesz zezwolić użytkownikowi na obsługę tego w razie potrzeby lub poinstruować administratora o zrobieniu tego wsadowo.
  5. Tylko aplikacja / api / usługa będzie kiedykolwiek zapisywać dane w bazie danych, więc po co się tym przejmować? To utrzymuje się przez większość czasu, dlatego nie jest powszechne.
  6. Obsługa błędów db jest wystarczająco trudna bez setek naruszeń ograniczeń, z którymi trzeba sobie poradzić, jeśli wszystko wymknie się spod kontroli. Większość osób chętnie nawiązuje połączenie i poprawia nazwę tabeli.

Wiele zespołów programistycznych nie chce zbytnio kontrolować dewelopera db. Masz szczęście, jeśli dostaniesz więcej niż jeden, więc wakacje są świetną zabawą. Niewielu wymaga absolutnej kontroli nad domeną bazy danych i bierze odpowiedzialność za każde zapytanie, regułę biznesową, wydajność, dostępność, bezpieczeństwo i jakie dane trafiają do jakiej macierzy RAID. Oto procedury składowane, które możesz wykonać. Baw się dobrze. Nawet nie myśl o dotknięciu stołu.


2

Jest to problem, z którym zmagałem się przez całą karierę (prawie 40 lat), a także podczas pisania DBMS. Opis mojego punktu końcowego znajduje się tutaj: http://unibase.zenucom.com . Oto moje myśli.

  1. Ogólnie rzecz biorąc, większość ograniczeń jest lepiej obsługiwana w aplikacji, dzięki czemu różne części aplikacji mogą wymuszać różne ograniczenia. np. kod stanu może nie mieć zastosowania we wszystkich jurysdykcjach.
  2. Na bok uważaj na%. Narzuty są> 100%, albo się zepsujesz :)
  3. Ograniczenia najlepiej opisać negatywnie. tzn. czym nie mogą być, a nie czym powinny być. To zawsze prostsza lista.
  4. Klucze obce są zawsze dobre i powinny być używane. Fullstop. FK jest jedną z niewielu konstrukcji semantycznych w RDBMS i bardzo przydatną. Największą trudność stanowi decyzja, czy wartość może zwisać, jeśli FK zostanie usunięty, czy też użyć wierszy zależnych jako powodu, aby nie usuwać rekordu FK.
  5. Ograniczenia w świecie rzeczywistym są zwykle bardziej złożone niż ograniczenie wartości pojedynczego pola.
  6. Niektóre ograniczenia, nawet na poziomie aplikacji, działają przeciwko dobrym operacjom. np. agresywne sprawdzanie daty ukrywa błędy w pozornie dobrych datach. Potrzebujesz błędu operatora, aby uzyskać miarę błędów w rozsądnie wyglądających terminach.

1

Ograniczenia bazy danych mogły być dobrym pomysłem, ale co z ich praktycznym wykorzystaniem? Weź swoje ograniczenie procentowe. Jeśli to zastosujesz, twoja baza danych z radością odrzuci nieprawidłowe wartości procentowe. I wtedy? Do obsługi wyjątku potrzebna będzie logika biznesowa. Co właściwie oznacza, że ​​logika biznesowa zapisująca nieprawidłowy odsetek już się nie udała gdzie indziej. W skrócie: jedynym praktycznym ograniczeniem są te, które widzisz (jak PK / FK).


15
Grzecznie się z tym nie zgadzam. Jeśli naprawdę potrzebujesz spójności danych, konieczne są ograniczenia bazy danych, zwłaszcza jeśli zawodzi logika biznesowa. Sposób, w jaki opisujesz scenariusz, w którym wystąpiłaby cicha awaria, w której szkody wyrządzone przez nieprawidłową procentową awarię byłyby propagowane dalej w systemie. Jeśli masz na to ograniczenie DB, szybko się nie powiedzie, a tym samym dadzą programiści logiki biznesowej szansę na wczesne zobaczenie błędu i załatanie systemu logiki biznesowej, zamiast pozwalać na uszkodzenie danych.
Machado

5
Rozumiem, że jeśli naruszenie ograniczenia procentowego zostanie naruszone, nie musisz obsługiwać tego wyjątku, ponieważ takie naruszenie wskazuje, że w twoim kodzie jest błąd (albo ktoś użył prostej liczby całkowitej zamiast instancji Percentageklasy, lub występuje błąd w samej walidacji), w przeciwieństwie do wyjątkowego przypadku (takiego jak połączenie sieciowe jest wyłączone). Dla mnie naruszenie powinno doprowadzić do HTTP 500 dla aplikacji internetowej lub awarii aplikacji komputerowej, a następnie powinno zostać zarejestrowane i naprawione.
Arseni Mourzenko

7
@ThomasKilian: nope; dokładnie odwrotnie. Nieprawidłowe dane nie zostaną wprowadzone, szczególnie dlatego, że istnieją ograniczenia bazy danych. Jeśli logika biznesowa jest poprawna w kodzie, nigdy nie naruszysz tych ograniczeń. Jeśli wystąpi błąd w kodzie, ograniczenia te powiadomią cię o tym błędzie, jednocześnie chroniąc bazę danych przed złomem.
Arseni Mourzenko

9
@ThomasKilian: Nie sądzę, aby ktokolwiek argumentował przeciwko „poprawieniu go w pierwszej kolejności” - prawdopodobnie bardziej niż ktokolwiek z pewnym doświadczeniem wie, że zaprojektowanie systemu przy założeniu, że będzie dostaniesz wszystko za pierwszym razem, a przez cały okres istnienia systemu nie pojawią się żadne błędy ani pomyłki . Ograniczenia DB zapewniają, że błąd lub pomyłka nie uszkodzi bazy danych.
JacquesB

3
@JacquesB Walczę z wiatrakami. Jeśli umieścisz logikę biznesową w bazie danych, może ona równie dobrze zawieść jak w pierwszej kolejności i nie uratować cię w ten sam sposób. Ale (!) Masz teraz logikę biznesową, do której ona nie należy. Wiara w to, że DB może uratować zgniłą logikę biznesową, jest po prostu błędna. Logika w DB musi przestrzegać tych samych zasad, co cała logika biznesowa.
qwerty_so

1

W dzisiejszych czasach ludzie częściej używają oprogramowania (np. Entity Framework) do automatycznego generowania tabel i kolumn. Chodzi o to, że nie potrzebują oni umiejętności SQL, co zwalnia mózg.

Oczekiwania, że ​​oprogramowanie „sprawdzi”, są często nierealistyczne i nie stawiają ograniczeń, jakich wymagałby człowiek.

Aby uzyskać najlepsze wyniki, utwórz tabele za pomocą SQL i ręcznie dodaj ograniczenia, ale czasem ludzie nie mogą tego zrobić.


Oczywiście niektóre frameworki obsługują automatyczne dodawanie PK i FK (pół).
David Aldridge,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.