Ze względu na to, że temat hurtowni danych (ang. data warehouse) nie jest powszechnie znany, chciałbym go nieco przybliżyć. Z praktycznego punktu widzenia hurtownia jest normalną bazą danych – posiada jednak pewne mechanizmy, które odróżniają ją od baz operacyjnych. W tym artykule przybliżę nieco teorię budowania hurtowni danych oraz mechanizmy, które są niezbędne do jej działania. Zwrócę uwagę na to, czym różni się Azure SQL Data Warehouse od klasycznej hurtowni danych.
Czym jest hurtownia danych?
Według definicji, którą proponuje Wikipedia, hurtownia danych to „rodzaj bazy danych, która jest zorganizowana i zoptymalizowana pod kątem pewnego wycinka rzeczywistości”.
Co to oznacza w praktyce? Otóż jest to baza, która służy przede wszystkim do odczytu danych i jest do tego celu zbudowana. Ma ona integrować dane z różnych systemów, a dostęp do danych mają mieć osoby, które podejmują decyzje biznesowe (aby na podstawie historycznych danych dokonywać bardziej trafnych wyborów).
Różne podejścia do modelowania schematu hurtowni danych
Żeby rozpocząć ten temat należy przybliżyć trzy istotne pojęcia związane z hurtowniami danych. Pierwszym z nich jest fakt, czyli informacja, która może podlegać analizie. Przykładem może być tutaj fakt sprzedaży, fakt odbycia wizyty u lekarza czy fakt przeprowadzenia ankiety. Te wydarzenia możemy analizować w różnym kontekście (np. jaka była sprzedaż w danym sklepie, albo która grupa klientów robi największe zakupy. Taki kontekst nazywamy wymiarem. Trzecim pojęciem jest miara, czyli w pewnym sensie jakaś wartość liczbowa przypisana do faktu, np. liczba sztuk towaru jaką zakupił klient w sklepie. Wszystkie dane o sprzedaży, klientach czy sklepach przechowujemy w tabelach hurtowni danych, co umożliwia dokładną analizę.
Przechodząc do sedna – istnieje kilka różnych sposobów modelowania hurtowni danych. Jednym z najpopularniejszych jest podejście wymiarowe zaproponowane przez Ralpha Kimballa. W tym przypadku opieramy się o tabele faktów i wymiarów. Struktury tabel faktów są znormalizowane, z kolei wymiarów – zdenormalizowane. Takie podejście zmniejsza liczę złączeń (join) w zapytaniach, co z kolei zwiększa wydajność, ale niestety także objętość danych przechowywanych w tabelach.
Kolejnym przykładem jest podejście relacyjne zaproponowane przez Billa Inmona. W tym przypadku wszystkie tabele są znormalizowane, co zwiększa liczbę złączeń w zapytaniach, a jednocześnie pozwala zaoszczędzić miejsce. Trzecim podejściem jest Data Vault, w którym wykorzystuje się takie elementy jak huby, linki i satelity.
Jak widać na powyższych przykładach – istnieją różne sposoby modelowania schematu hurtowni danych. Każdy ma swoje wady i zalety, o każdym można by wiele napisać, jednak w dalszej części artykułu bazował skupię się tylko na jednym z nich – zaproponowanym przez R. Kimballa.
Implementacja modelu hurtowni danych
Zakładając, że mamy już zaprojektowany model hurtowni danych i chcemy go zaimplementować, potrzebujemy do tego celu silnika bazodanowego. W klasycznym przypadku wykorzystalibyśmy SQL Server, który jak najbardziej się do tego celu nadaje. Zasadniczo do implementacji hurtowni danych można wykorzystać niemal każdy relacyjny silnik bazodanowy, jednak niektóre z nich posiadają bardziej rozbudowane funkcjonalności, przez co rozwiązania działają bardziej wydajnie.
Azure SQL Data Warehouse (ASDW) nie jest rodzajem zwykłego silnika bazodanowego. Działanie tej usługi opiera się o architekturę Massively Parallel Processing, która umożliwia rozproszone działanie zapytań. Każda instancja Azure SQL Data Warehouse składa się z 60 węzłów obliczeniowych, nad którymi czuwa jeden lub więcej węzłów sterujących. Węzeł jest instancją Azure SQL Database – najlepiej zobrazuje to schemat, który pochodzi z serwisu TechNet Microsoftu.
Jeżeli chcemy załadować tabelę danymi to z technicznego punktu widzenia proces ten wygląda następująco: dane trafiają najpierw do węzła sterującego, a następnie są dystrybuowane między 60 węzłów obliczeniowych i składowane w pamięci typu blob. Oznacza to, że każda tabela znajduje sie na 60 instancjach Azure SQL Database. Dzięki temu operacje można wykonywać równolegle, co znacznie wpływa na wydajność. Przykładowo – agregacja będzie uruchomiona jednoczenie na 60 węzłach, dzięki czemu proces przebiegnie znacznie szybciej, niż gdyby był uruchomiony tylko na jednej instancji.
Dystrybucja danych
Jak wspomniałem w poprzednim akapicie – każda tabela znajduje się na 60 węzłach. Warto tutaj wspomnieć, że nie zawsze jest to zwykła kopia danych z tabeli na każdym węźle. Dane są odpowiednio dystrybuowane, co oznacza, że są najpierw dzielone na porcje i umieszczane w odpowiednim węźle. O tym w jaki sposób przebiega ten proces decyduje algorytm dystrybucji. Dostępne są trzy takie algorytmy:
- Round Robin (karuzelowy) – najprostszy i domyślny, umieszcza dane po kolei w każdym węźle. Jeżeli porcja danych zostaje załadowana, to jest ona po prostu dzielona między 60 węzłów.
- Hash – dane są dzielone i dystrybuowane na podstawie funkcji skrótu, której argumentem może być wartość z danej kolumny tabeli. Jest on bardziej wydajną metodą w przypadku dużych zbiorów danych, na przykład dla tabel faktów, gdzie możemy rozmieszczać dane dzieląc je względem klucza surogatkowego lub biznesowego.
- Replicated– w każdym węźle składowana jest kompletna kopia tabeli, przez co ta metoda nie powinna być stosowana do dużych zbiorów danych, a jedynie do niewielkich objętościowo tabel, np. wymiarów.
Indeksowanie tabel
ASDW oferuje kilka metod składowania danych w tabelach:
- Heap– czyli zwykła sterta, gdzie dane nie są indeksowane, ale składowane w takiej samej formie, jak zostały załadowane. Takie podejście należy wykorzystać do tabel, w których dane przechowywane są tylko tymczasowo lub gdy ich ilość nie jest duża. Szybkość ładowania do tabel bez indeksu jest z reguły wyższa niż do indeksowanych.
- Indeks kolumnowy klastrowany – ten typ indeksu omówię w oddzielnym artykule, ze względu na złożoność tematu. W skrócie – w tym przypadku dane przechowywane są kolumnowo, a nie wierszowo. Dzięki temu, w przypadku agregacji, silnik bazodanowy pobiera tylko niezbędne kolumny z tabeli. Zmniejsza to liczbę danych niezbędnych to przetworzenia, dzięki czemu wydajność wzrasta. Co więcej, dane poddane są kompresji. Taki typ indeksu zakładany jest domyślnie na każdą nową tabelę w ASDW. To podejście powinno być stosowane w przypadku dużych tabel (>100M rekordów), w których nie mamy kolumn w typie nvarchar(max) lub varchar(max).
- Indeks klastrowany i nieklastrowany – typy indeksów znane z klasycznego SQL Servera, powinny być używane do tabel, na których często wykonywane będą operacje filtrowania danych.
W tym miejscu warto również wspomnieć nieco o utrzymaniu indeksów. Co jakiś czas należy reorganizować lub przebudowywać indeksy, ponieważ dodawanie nowych danych i usuwanie starych powoduje defragmentację, która negatywnie wpływa na wydajność. Konkluzja jest taka, że zakładanie indeksów wszędzie, gdzie to możliwe nie jest dobrą praktyką 🙂
Dalsze kroki
W dzisiejszym artykule omówiłem w skrócie teorię hurtowni danych oraz wyjaśniłem dlaczego są one powszechnie używane. Omówiłem także podstawowe różnice między Azure SQL Database oraz Azure SQL Data Warehouse. Przybliżyłem mechanizmy, dzięki którym ASDW zapewnia wydajne działanie dla dużej ilości danych. W kolejnym artykule zaprezentuję, jak uruchomić instancję ASDW i załadować do niej dane korzystając z mechanizmu PolyBase i Azure Data Factory.