Modelowanie danych w usłudze Azure Cosmos DB

DOTYCZY: interfejs API SQL

Chociaż bazy danych bez schematu, takie jak usługa Azure Cosmos DB, ułatwiają przechowywanie i wykonywanie zapytań względem danych bez struktury i częściowo ustrukturyzowanych, należy poświęcić trochę czasu na myślenie o modelu danych, aby uzyskać większość usług pod względem wydajności i skalowalności oraz najniższych kosztów.

Jak będą przechowywane dane? Jak aplikacja będzie pobierać i wykonywać zapytania dotyczące danych? Czy aplikacja jest ciężka do odczytu, czy z dużą liczbą operacji zapisu?

Po przeczytaniu tego artykułu będziesz w stanie odpowiedzieć na następujące pytania:

  • Co to jest modelowanie danych i dlaczego należy obchodzić?
  • W jaki sposób modelowanie danych w usłudze Azure Cosmos DB różni się od relacyjnej bazy danych?
  • Jak mogę wyrażać relacje danych w nierelacyjnej bazie danych?
  • Kiedy osadzam dane i kiedy mogę połączyć się z danymi?

Liczby w formacie JSON

Cosmos DB zapisuje dokumenty w formacie JSON. Co oznacza, że przed zapisaniem ich w formacie json należy dokładnie określić, czy konieczne jest przekonwertowanie liczb na ciągi. Wszystkie liczby powinny zostać przekonwertowane na wartość , jeśli istnieje prawdopodobieństwo, że znajdują się one poza granicami podwójnej dokładności liczb zgodnie ze standardem StringIEEE 754 binary64. Specyfikacja JSON wywołuje przyczyny, dla których używanie liczb spoza tej granicy jest w ogóle złym rozwiązaniem w formacie JSON z powodu prawdopodobnych problemów z współdziałaniem. Te problemy są szczególnie istotne w przypadku kolumny klucza partycji, ponieważ jest niezmienna i wymaga późniejszej zmiany migracji danych.

Osadzanie danych

Po rozpoczęciu modelowania danych w usłudze Azure Cosmos DB spróbuj traktować jednostki jako elementy samodzielne reprezentowane jako dokumenty JSON.

Aby porównać, najpierw zobaczmy, jak możemy modelać dane w relacyjnej bazie danych. W poniższym przykładzie pokazano, jak osoba może być przechowywana w relacyjnej bazie danych.

Relational database model

Strategia, podczas pracy z relacyjnymi bazami danych, polega na normalizacji wszystkich danych. Normalizacja danych zwykle polega na przyjmowaniu jednostki, takiej jak osoba, i podzieleniu ich na odrębne składniki. W powyższym przykładzie osoba może mieć wiele rekordów szczegółów kontaktu i wiele rekordów adresów. Szczegóły kontaktu można dalej podzielić, wyodrębniając typowe pola, takie jak typ. To samo dotyczy adresu, każdy rekord może być typu Home lub Business.

W przypadku normalizacji danych należy unikać przechowywania nadmiarowych danych na każdym rekordzie, a raczej odwoływać się do danych. W tym przykładzie, aby odczytać osobę ze wszystkimi swoimi danymi kontaktowymi i adresami, musisz użyć funkcji JOINS, aby skutecznie utworzyć dane (lub zdenormalizować) dane w czasie wykonywania.

SELECT p.FirstName, p.LastName, a.City, cd.Detail
FROM Person p
JOIN ContactDetail cd ON cd.PersonId = p.Id
JOIN ContactDetailType cdt ON cdt.Id = cd.TypeId
JOIN Address a ON a.PersonId = p.Id

Operacje zapisu w wielu pojedynczych tabelach są wymagane do zaktualizowania danych kontaktowych i adresów pojedynczej osoby.

Teraz przyjrzyjmy się temu, jak modelujemy te same dane co samodzielna jednostka w usłudze Azure Cosmos DB.

{
    "id": "1",
    "firstName": "Thomas",
    "lastName": "Andersen",
    "addresses": [
        {
            "line1": "100 Some Street",
            "line2": "Unit 1",
            "city": "Seattle",
            "state": "WA",
            "zip": 98012
        }
    ],
    "contactDetails": [
        {"email": "thomas@andersen.com"},
        {"phone": "+1 555 555-5555", "extension": 5555}
    ]
}

Korzystając z powyższego podejścia , zdenormalizowaliśmy rekord osoby, osadzając wszystkie informacje związane z tą osobą, takie jak ich dane kontaktowe i adresy, w jednym dokumencie JSON . Ponadto, ponieważ nie jesteśmy ograniczone do stałego schematu, mamy elastyczność wykonywania takich czynności, jak posiadanie szczegółów kontaktowych różnych kształtów całkowicie.

Pobieranie kompletnego rekordu osoby z bazy danych jest teraz pojedynczą operacją odczytu dla pojedynczego kontenera i pojedynczego elementu. Aktualizowanie danych kontaktowych i adresów rekordu osoby jest również pojedynczą operacją zapisu względem pojedynczego elementu.

Dzięki denormalizacji danych aplikacja może wymagać wydania mniejszej liczby zapytań i aktualizacji w celu ukończenia typowych operacji.

Kiedy należy osadzić

Ogólnie rzecz biorąc, używaj modeli danych osadzonych, gdy:

  • Istnieją relacje między jednostkami.
  • Istnieją relacje jeden do kilku między jednostkami.
  • Istnieją osadzone dane, które zmieniają się rzadko.
  • Istnieją osadzone dane, które nie będą rosnąć bez ograniczenia.
  • Istnieją osadzone dane, do których często są wykonywane zapytania.

Uwaga

Zazwyczaj zdenormalizowane modele danych zapewniają lepszą wydajność odczytu .

Kiedy nie należy osadzać

Chociaż reguła kciuka w usłudze Azure Cosmos DB polega na denormalizacji wszystkich danych i osadzeniu wszystkich danych w jednym elemencie, może to prowadzić do niektórych sytuacji, których należy unikać.

Weźmy ten fragment kodu JSON.

{
    "id": "1",
    "name": "What's new in the coolest Cloud",
    "summary": "A blog post by someone real famous",
    "comments": [
        {"id": 1, "author": "anon", "comment": "something useful, I'm sure"},
        {"id": 2, "author": "bob", "comment": "wisdom from the interwebs"},
        …
        {"id": 100001, "author": "jane", "comment": "and on we go ..."},
        …
        {"id": 1000000001, "author": "angry", "comment": "blah angry blah angry"},
        …
        {"id": ∞ + 1, "author": "bored", "comment": "oh man, will this ever end?"},
    ]
}

Może to być tak, jak wyglądałaby jednostka postu z osadzonymi komentarzami, gdyby modelowaliśmy typowy blog lub system CMS. Problem z tym przykładem polega na tym, że tablica komentarzy jest niezwiązana, co oznacza, że nie ma (praktycznego) limitu liczby komentarzy, które mogą zawierać pojedyncze posty. Może to stać się problemem, ponieważ rozmiar elementu może rosnąć w nieskończoność, więc jest to projekt, którego należy unikać.

Wraz ze wzrostem rozmiaru elementu będzie mieć wpływ na przesyłanie danych za pośrednictwem przewodu i odczytywania i aktualizowania elementu na dużą skalę.

W takim przypadku lepiej byłoby rozważyć następujący model danych.

Post item:
{
    "id": "1",
    "name": "What's new in the coolest Cloud",
    "summary": "A blog post by someone real famous",
    "recentComments": [
        {"id": 1, "author": "anon", "comment": "something useful, I'm sure"},
        {"id": 2, "author": "bob", "comment": "wisdom from the interwebs"},
        {"id": 3, "author": "jane", "comment": "....."}
    ]
}

Comment items:
[
    {"id": 4, "postId": "1", "author": "anon", "comment": "more goodness"},
    {"id": 5, "postId": "1", "author": "bob", "comment": "tails from the field"},
    ...
    {"id": 99, "postId": "1", "author": "angry", "comment": "blah angry blah angry"},
    {"id": 100, "postId": "2", "author": "anon", "comment": "yet more"},
    ...
    {"id": 199, "postId": "2", "author": "bored", "comment": "will this ever end?"}   
]

Ten model zawiera dokument dla każdego komentarza z właściwością zawierającą identyfikator wpisu. Dzięki temu posty mogą zawierać dowolną liczbę komentarzy i wydajnie rosnąć. Użytkownicy, którzy chcą zobaczyć więcej niż najnowsze komentarze, będą wysyłać zapytania do tego kontenera przekazującego identyfikator postId, który powinien być kluczem partycji dla kontenera komentarzy.

Innym przypadkiem, w którym osadzanie danych nie jest dobrym pomysłem, jest to, że osadzone dane są często używane w różnych elementach i często się zmieniają.

Weźmy ten fragment kodu JSON.

{
    "id": "1",
    "firstName": "Thomas",
    "lastName": "Andersen",
    "holdings": [
        {
            "numberHeld": 100,
            "stock": { "symbol": "zbzb", "open": 1, "high": 2, "low": 0.5 }
        },
        {
            "numberHeld": 50,
            "stock": { "symbol": "xcxc", "open": 89, "high": 93.24, "low": 88.87 }
        }
    ]
}

Może to reprezentować portfel akcji osoby. Wybraliśmy osadzanie informacji o zapasach w każdym dokumencie portfela. W środowisku, w którym powiązane dane zmieniają się często, podobnie jak aplikacja do handlu giełdowego, osadzanie danych, które często zmieniają się, oznacza, że stale aktualizujesz każdy dokument portfela za każdym razem, gdy akcje są wymieniane.

Giełda zbzb może być handlowana setki razy w ciągu jednego dnia, a tysiące użytkowników może mieć zbzb na swoim portfelu. W przypadku modelu danych, takiego jak powyższe, musielibyśmy aktualizować wiele tysięcy dokumentów portfolio wiele razy dziennie, co prowadzi do systemu, który nie będzie dobrze skalowany.

Dane referencyjne

Osadzanie danych działa ładnie w wielu przypadkach, ale istnieją scenariusze, w których denormalizacja danych spowoduje więcej problemów niż warto. Co teraz robimy?

Relacyjne bazy danych nie są jedynym miejscem, w którym można tworzyć relacje między jednostkami. W bazie danych dokumentów mogą znajdować się informacje w jednym dokumencie, które odnoszą się do danych w innych dokumentach. Nie zalecamy tworzenia systemów, które lepiej nadają się do relacyjnej bazy danych w usłudze Azure Cosmos DB lub innej bazy danych dokumentów, ale proste relacje są poprawne i mogą być przydatne.

W poniższym formacie JSON wybraliśmy użycie przykładu portfela akcji z wcześniejszej wersji, ale tym razem odwołujemy się do pozycji akcji w portfelu zamiast jej osadzania. W ten sposób, gdy pozycja zapasów zmienia się często przez cały dzień jedynym dokumentem, który należy zaktualizować, jest pojedynczy dokument giełdowy.

Person document:
{
    "id": "1",
    "firstName": "Thomas",
    "lastName": "Andersen",
    "holdings": [
        { "numberHeld":  100, "stockId": 1},
        { "numberHeld":  50, "stockId": 2}
    ]
}

Stock documents:
{
    "id": "1",
    "symbol": "zbzb",
    "open": 1,
    "high": 2,
    "low": 0.5,
    "vol": 11970000,
    "mkt-cap": 42000000,
    "pe": 5.89
},
{
    "id": "2",
    "symbol": "xcxc",
    "open": 89,
    "high": 93.24,
    "low": 88.87,
    "vol": 2970200,
    "mkt-cap": 1005000,
    "pe": 75.82
}

Natychmiastową wadą tego podejścia jest jednak to, że aplikacja jest wymagana do pokazania informacji o każdej akcji przechowywanej podczas wyświetlania portfela osoby; w takim przypadku należy wykonać wiele podróży do bazy danych, aby załadować informacje dla każdego dokumentu zapasów. W tym miejscu podjęliśmy decyzję o poprawie wydajności operacji zapisu, które zdarzają się często przez cały dzień, ale z kolei naruszone na operacje odczytu, które potencjalnie mają mniejszy wpływ na wydajność tego konkretnego systemu.

Uwaga

Znormalizowane modele danych mogą wymagać większej liczby rund na serwerze.

Co z kluczami obcymi?

Ponieważ obecnie nie ma pojęcia ograniczenia, klucza obcego lub innego, wszelkie relacje między dokumentami, które znajdują się w dokumentach, są skutecznie "słabymi linkami" i nie zostaną zweryfikowane przez samą bazę danych. Jeśli chcesz upewnić się, że dane, do których odnosi się dokument, rzeczywiście istnieją, musisz to zrobić w aplikacji lub przy użyciu wyzwalaczy po stronie serwera lub procedur składowanych w usłudze Azure Cosmos DB.

Kiedy należy się odwołać

Ogólnie rzecz biorąc, użyj znormalizowanych modeli danych, gdy:

  • Reprezentowanie relacji jeden-do-wielu .
  • Reprezentowanie relacji wiele-do-wielu .
  • Powiązane zmiany danych są często zmieniane.
  • Przywoływane dane mogą być niezwiązane.

Uwaga

Zazwyczaj normalizacja zapewnia lepszą wydajność zapisu .

Gdzie mogę umieścić relację?

Wzrost relacji pomoże określić, w którym dokumencie ma być przechowywane odwołanie.

Jeśli przyjrzymy się poniższej kodzie JSON, modeluje wydawców i książki.

Publisher document:
{
    "id": "mspress",
    "name": "Microsoft Press",
    "books": [ 1, 2, 3, ..., 100, ..., 1000]
}

Book documents:
{"id": "1", "name": "Azure Cosmos DB 101" }
{"id": "2", "name": "Azure Cosmos DB for RDBMS Users" }
{"id": "3", "name": "Taking over the world one JSON doc at a time" }
...
{"id": "100", "name": "Learn about Azure Cosmos DB" }
...
{"id": "1000", "name": "Deep Dive into Azure Cosmos DB" }

Jeśli liczba książek na wydawcę jest niewielka z ograniczonym wzrostem, przechowywanie odwołania do książki w dokumencie wydawcy może być przydatne. Jeśli jednak liczba książek na wydawcę jest niezwiązana, ten model danych doprowadzi do niezmiennych, rosnących tablic, jak w powyższym przykładowym dokumencie wydawcy.

Przełączanie elementów wokół nieco spowodowałoby model, który nadal reprezentuje te same dane, ale teraz unika tych dużych kolekcji modyfikowalnych.

Publisher document:
{
    "id": "mspress",
    "name": "Microsoft Press"
}

Book documents:
{"id": "1","name": "Azure Cosmos DB 101", "pub-id": "mspress"}
{"id": "2","name": "Azure Cosmos DB for RDBMS Users", "pub-id": "mspress"}
{"id": "3","name": "Taking over the world one JSON doc at a time", "pub-id": "mspress"}
...
{"id": "100","name": "Learn about Azure Cosmos DB", "pub-id": "mspress"}
...
{"id": "1000","name": "Deep Dive into Azure Cosmos DB", "pub-id": "mspress"}

W powyższym przykładzie usunięto niezwiązaną kolekcję w dokumencie wydawcy. Zamiast tego mamy tylko odwołanie do wydawcy w każdym dokumencie książki.

Jak mogę modelu relacji wiele-do-wielu?

Relacje wiele-do-wielu w relacyjnej bazie danych są często modelowane przy użyciu tabel sprzężenia, które łączą rekordy z innych tabel.

Join tables

Możesz być kuszony, aby replikować to samo przy użyciu dokumentów i utworzyć model danych podobny do poniższego.

Author documents:
{"id": "a1", "name": "Thomas Andersen" }
{"id": "a2", "name": "William Wakefield" }

Book documents:
{"id": "b1", "name": "Azure Cosmos DB 101" }
{"id": "b2", "name": "Azure Cosmos DB for RDBMS Users" }
{"id": "b3", "name": "Taking over the world one JSON doc at a time" }
{"id": "b4", "name": "Learn about Azure Cosmos DB" }
{"id": "b5", "name": "Deep Dive into Azure Cosmos DB" }

Joining documents:
{"authorId": "a1", "bookId": "b1" }
{"authorId": "a2", "bookId": "b1" }
{"authorId": "a1", "bookId": "b2" }
{"authorId": "a1", "bookId": "b3" }

To zadziała. Jednak załadowanie autora za pomocą książek lub załadowanie książki z jego autorem zawsze wymagałoby co najmniej dwóch dodatkowych zapytań względem bazy danych. Jedno zapytanie do dokumentu dołączania, a następnie inne zapytanie, aby pobrać rzeczywisty dokument, który jest przyłączony.

Jeśli to sprzężenie jest przyklejane tylko do dwóch fragmentów danych, dlaczego nie upuść go całkowicie? Rozważmy następujący przykład.

Author documents:
{"id": "a1", "name": "Thomas Andersen", "books": ["b1", "b2", "b3"]}
{"id": "a2", "name": "William Wakefield", "books": ["b1", "b4"]}

Book documents:
{"id": "b1", "name": "Azure Cosmos DB 101", "authors": ["a1", "a2"]}
{"id": "b2", "name": "Azure Cosmos DB for RDBMS Users", "authors": ["a1"]}
{"id": "b3", "name": "Learn about Azure Cosmos DB", "authors": ["a1"]}
{"id": "b4", "name": "Deep Dive into Azure Cosmos DB", "authors": ["a2"]}

Teraz, gdybym miał autora, natychmiast wiem, które książki napisali, i odwrotnie, gdybym miał załadowany dokument książki, wiedziałbym identyfikatory autorów. Spowoduje to zapisanie zapytania pośredniczącego względem tabeli sprzężenia, co zmniejsza liczbę rund serwera, które aplikacja musi wykonać.

Modele danych hybrydowych

Zapoznaliśmy się teraz z osadzaniem (lub denormalizacją) i odwoływaniem się (lub normalizacją) danych. Każde podejście ma wady i kompromisy.

To nie zawsze musi być albo lub, nie boi się mieszać rzeczy trochę.

Na podstawie konkretnych wzorców użycia i obciążeń aplikacji mogą występować przypadki, w których mieszanie osadzonych i przywołynych danych ma sens i może prowadzić do prostszej logiki aplikacji z mniejszą liczbą rund serwera przy jednoczesnym zachowaniu dobrego poziomu wydajności.

Rozważmy następujący kod JSON.

Author documents:
{
    "id": "a1",
    "firstName": "Thomas",
    "lastName": "Andersen",
    "countOfBooks": 3,
    "books": ["b1", "b2", "b3"],
    "images": [
        {"thumbnail": "https://....png"}
        {"profile": "https://....png"}
        {"large": "https://....png"}
    ]
},
{
    "id": "a2",
    "firstName": "William",
    "lastName": "Wakefield",
    "countOfBooks": 1,
    "books": ["b1"],
    "images": [
        {"thumbnail": "https://....png"}
    ]
}

Book documents:
{
    "id": "b1",
    "name": "Azure Cosmos DB 101",
    "authors": [
        {"id": "a1", "name": "Thomas Andersen", "thumbnailUrl": "https://....png"},
        {"id": "a2", "name": "William Wakefield", "thumbnailUrl": "https://....png"}
    ]
},
{
    "id": "b2",
    "name": "Azure Cosmos DB for RDBMS Users",
    "authors": [
        {"id": "a1", "name": "Thomas Andersen", "thumbnailUrl": "https://....png"},
    ]
}

W tym miejscu (głównie) wykonaliśmy model osadzony, w którym dane z innych jednostek są osadzone w dokumencie najwyższego poziomu, ale przywoływane są inne dane.

Jeśli spojrzysz na dokument książki, zobaczymy kilka interesujących pól, gdy przyjrzymy się tablicy autorów. id Istnieje pole, które jest polem używanym do odwoływania się do dokumentu autora, standardowej praktyki w znormalizowanym modelu, ale mamy również i namethumbnailUrl. Moglibyśmy zablokować id i pozostawić aplikację, aby uzyskać dodatkowe informacje potrzebne z odpowiedniego dokumentu autora przy użyciu "linku", ale ponieważ nasza aplikacja wyświetla nazwę autora i obraz miniatury z każdą wyświetloną książką, możemy zapisać rundę na serwerze na liście, denormalizując niektóre dane od autora.

Oczywiście, jeśli nazwa autora zmieniła się lub chcieli zaktualizować swoje zdjęcie, musielibyśmy zaktualizować każdą książkę, którą kiedykolwiek opublikowali, ale dla naszej aplikacji, na podstawie założenia, że autorzy nie zmieniają swoich nazw często, jest to akceptowalna decyzja projektowa.

W tym przykładzie istnieją wstępnie obliczone wartości agregacji w celu zaoszczędzenia kosztownego przetwarzania na operacji odczytu. W tym przykładzie niektóre dane osadzone w dokumencie autora to dane obliczane w czasie wykonywania. Za każdym razem, gdy zostanie opublikowana nowa książka, zostanie utworzony dokument książki , a pole countOfBooks ma wartość obliczeniową na podstawie liczby dokumentów książki, które istnieją dla określonego autora. Ta optymalizacja byłaby dobra w systemach o dużym obciążeniu odczytu, w których możemy sobie pozwolić na wykonywanie obliczeń na zapisach w celu zoptymalizowania operacji odczytu.

Możliwość posiadania modelu ze wstępnie obliczonymi polami jest możliwa, ponieważ usługa Azure Cosmos DB obsługuje transakcje obejmujące wiele dokumentów. Wiele sklepów NoSQL nie może wykonywać transakcji w dokumentach i dlatego opowiada się za decyzjami projektowymi, takimi jak "zawsze osadź wszystko", ze względu na to ograniczenie. Za pomocą usługi Azure Cosmos DB można używać wyzwalaczy po stronie serwera lub procedur składowanych, które wstawią książki i aktualizują autorów w ramach transakcji ACID. Teraz nie musisz osadzać wszystkiego w jednym dokumencie, aby upewnić się, że dane pozostają spójne.

Rozróżnianie różnych typów dokumentów

W niektórych scenariuszach warto mieszać różne typy dokumentów w tej samej kolekcji; Zwykle jest tak, gdy chcesz, aby wiele powiązanych dokumentów siedziało w tej samej partycji. Można na przykład umieścić zarówno książki, jak i recenzje książek w tej samej kolekcji i podzielić ją na partycje według .bookId W takiej sytuacji zwykle chcesz dodać do dokumentów pole identyfikujące ich typ w celu ich odróżnienia.

Book documents:
{
    "id": "b1",
    "name": "Azure Cosmos DB 101",
    "bookId": "b1",
    "type": "book"
}

Review documents:
{
    "id": "r1",
    "content": "This book is awesome",
    "bookId": "b1",
    "type": "review"
},
{
    "id": "r2",
    "content": "Best book ever!",
    "bookId": "b1",
    "type": "review"
}

Azure Synapse Link dla usługi Azure Cosmos DB to natywna dla chmury funkcja hybrydowego przetwarzania transakcyjnego i analitycznego (HTAP), która umożliwia uruchamianie analizy niemal w czasie rzeczywistym na danych operacyjnych w usłudze Azure Cosmos DB. Azure Synapse Link tworzy ścisłą bezproblemową integrację między usługą Azure Cosmos DB i usługą Azure Synapse Analytics.

Ta integracja odbywa się za pośrednictwem magazynu analitycznego usługi Azure Cosmos DB— kolumnowej reprezentacji danych transakcyjnych, która umożliwia analizę na dużą skalę bez wpływu na obciążenia transakcyjne. Ten magazyn analityczny jest odpowiedni dla szybkich, tanich zapytań dotyczących dużych zestawów danych operacyjnych bez kopiowania danych i wpływania na wydajność obciążeń transakcyjnych. Po utworzeniu kontenera z włączonym magazynem analitycznym lub włączeniu magazynu analitycznego w istniejącym kontenerze wszystkie transakcyjne wstawki, aktualizacje i usunięcia są synchronizowane z magazynem analitycznym niemal w czasie rzeczywistym, nie są wymagane żadne zadania zestawienia zmian ani zadania ETL.

Dzięki usłudze Azure Synapse Link możesz teraz bezpośrednio łączyć się z kontenerami usługi Azure Cosmos DB z usługi Azure Synapse Analytics i uzyskiwać dostęp do magazynu analitycznego bez kosztów jednostek żądania (jednostek żądania). usługa Azure Synapse Analytics obsługuje obecnie usługę Azure Synapse Link z usługą Synapse Apache Spark i bezserwerowymi pulami SQL. Jeśli masz globalnie rozproszone konto usługi Azure Cosmos DB, po włączeniu magazynu analitycznego dla kontenera będzie ono dostępne we wszystkich regionach dla tego konta.

Automatyczne wnioskowanie schematu magazynu analitycznego

Chociaż magazyn transakcyjny usługi Azure Cosmos DB jest uważany za dane częściowo ustrukturyzowane zorientowane na wiersz, magazyn analityczny ma format kolumnowy i ustrukturyzowany. Ta konwersja jest automatycznie dokonana dla klientów przy użyciu reguł wnioskowania schematu dla magazynu analitycznego. Istnieją limity w procesie konwersji: maksymalna liczba zagnieżdżonych poziomów, maksymalna liczba właściwości, nieobsługiwane typy danych i nie tylko.

Uwaga

W kontekście magazynu analitycznego uważamy następujące struktury za właściwość:

  • JSON "elements" lub "string-value pairs rozdzielone przez : ".
  • Obiekty JSON, rozdzielane przez { i }.
  • Tablice JSON, rozdzielane przez [ i ].

Możesz zminimalizować wpływ konwersji wnioskowania schematu i zmaksymalizować możliwości analityczne, korzystając z poniższych technik.

Normalizacja

Normalizacja staje się bez znaczenia, ponieważ za pomocą Azure Synapse Link można połączyć się między kontenerami przy użyciu SQL T-SQL lub Spark SQL. Oczekiwane korzyści wynikające z normalizacji to:

  • Mniejszy ślad danych w magazynie transakcyjnym i analitycznym.
  • Mniejsze transakcje.
  • Mniej właściwości na dokument.
  • Struktury danych z mniejszą liczbą poziomów zagnieżdżonych.

Należy pamiętać, że te dwa ostatnie czynniki, mniejsze właściwości i mniej poziomów, pomagają w wydajności zapytań analitycznych, ale także zmniejszają prawdopodobieństwo, że części danych nie są reprezentowane w magazynie analitycznym. Zgodnie z opisem w artykule dotyczącym reguł automatycznego wnioskowania schematu istnieją ograniczenia dotyczące liczby poziomów i właściwości reprezentowanych w magazynie analitycznym.

Innym ważnym czynnikiem normalizacji jest to, że SQL bezserwerowe pule w Azure Synapse obsługują zestawy wyników z maksymalnie 1000 kolumnami i uwidacznianie zagnieżdżonych kolumn również liczy się w kierunku tego limitu. Innymi słowy, zarówno magazyn analityczny, jak i usługa Synapse SQL pule bezserwerowe mają limit 1000 właściwości.

Ale co zrobić, ponieważ denormalizacja jest ważną techniką modelowania danych dla usługi Azure Cosmos DB? Odpowiedź polega na tym, że musisz znaleźć właściwą równowagę dla obciążeń transakcyjnych i analitycznych.

Klucz partycji

Klucz partycji usługi Azure Cosmos DB (PK) nie jest używany w magazynie analitycznym. Teraz możesz użyć partycjonowania niestandardowego magazynu analitycznego do kopiowania magazynu analitycznego przy użyciu dowolnego klucza PK. Ze względu na tę izolację można wybrać klucz PK dla danych transakcyjnych z fokusem na pozyskiwaniu danych i odczytach punktów, podczas gdy zapytania obejmujące wiele partycji można wykonać za pomocą usługi Azure Synapse Link. Zobaczmy przykład:

W hipotetycznym globalnym scenariuszu IoT jest dobrym kluczem PK, device id ponieważ wszystkie urządzenia mają podobny wolumin danych i że nie będziesz mieć problemu z gorącą partycją. Jeśli jednak chcesz przeanalizować dane więcej niż jednego urządzenia, na przykład "wszystkie dane z wczoraj" lub "sumy na miasto", mogą wystąpić problemy, ponieważ są to zapytania obejmujące wiele partycji. Te zapytania mogą zaszkodzić wydajności transakcyjnej, ponieważ używają części przepływności w jednostkach żądań do uruchomienia. Jednak za pomocą usługi Azure Synapse Link można uruchamiać te zapytania analityczne bez kosztów jednostek żądań. Format kolumnowy magazynu analitycznego jest zoptymalizowany pod kątem zapytań analitycznych i Azure Synapse Link stosuje tę charakterystykę, aby zapewnić doskonałą wydajność w środowiskach uruchomieniowych usługi Azure Synapse Analytics.

Typy danych i nazwy właściwości

Artykuł dotyczący reguł wnioskowania automatycznego schematu zawiera listę obsługiwanych typów danych. Chociaż nieobsługiwany typ danych blokuje reprezentację w magazynie analitycznym, obsługiwane typy danych mogą być przetwarzane inaczej przez środowiska uruchomieniowe Azure Synapse. Jednym z przykładów jest: W przypadku używania ciągów typu DateTime, które są zgodne ze standardem ISO 8601 UTC, pule platformy Spark w Azure Synapse będą reprezentować te kolumny jako ciąg i SQL pule bezserwerowe w Azure Synapse będą reprezentować te kolumny jako varchar(8000).

Innym wyzwaniem jest to, że nie wszystkie znaki są akceptowane przez platformę Azure Synapse Spark. Podczas akceptowania białych spacji znaki, takie jak dwukropek, akcent grobowy i przecinek, nie są. Załóżmy, że dokument ma właściwość o nazwie "Imię, Nazwisko". Ta właściwość będzie reprezentowana w magazynie analitycznym, a pula bezserwerowa synapse SQL może ją odczytać bez problemu. Ponieważ jednak znajduje się ona w magazynie analitycznym, Azure Synapse platforma Spark nie może odczytać żadnych danych z magazynu analitycznego, w tym wszystkich innych właściwości. Na koniec dnia nie można używać Azure Synapse Spark, gdy masz jedną właściwość, używając nieobsługiwanych znaków w nazwach.

Spłaszczanie danych

Wszystkie właściwości na poziomie głównym danych Cosmos DB będą reprezentowane w magazynie analitycznym jako kolumnie, a wszystkie inne właściwości, które są na głębszych poziomach modelu danych dokumentu, będą reprezentowane jako dane JSON, również w zagnieżdżonych strukturach. Zagnieżdżone struktury wymagają dodatkowego przetwarzania ze środowisk uruchomieniowych Azure Synapse w celu spłaszczenia danych w formacie ustrukturyzowanym, co może być wyzwaniem w scenariuszach dotyczących danych big data.

Poniższy dokument będzie miał tylko dwie kolumny w magazynie id analitycznym i contactDetails. Wszystkie inne dane email i phone, będą wymagały dodatkowego przetwarzania za pomocą funkcji SQL, które będą odczytywane indywidualnie.


{
    "id": "1",
    "contactDetails": [
        {"email": "thomas@andersen.com"},
        {"phone": "+1 555 555-5555"}
    ]
}

Poniższy dokument będzie zawierać trzy kolumny w magazynie analitycznym, id, emaili phone. Wszystkie dane są bezpośrednio dostępne jako kolumny.


{
    "id": "1",
    "email": "thomas@andersen.com",
    "phone": "+1 555 555-5555"
}

Warstwy danych

Azure Synapse Link umożliwia zmniejszenie kosztów z następujących perspektyw:

  • Mniej zapytań uruchomionych w transakcyjnej bazie danych.
  • Klucz PK zoptymalizowany pod kątem pozyskiwania danych i odczytów punktów, zmniejszając ślad danych, scenariusze gorącej partycji i podziały partycji.
  • Obsługa warstw danych od czasu wygaśnięcia analitycznego (attl) jest niezależna od transakcyjnego czasu wygaśnięcia (tttl). Dane transakcyjne można przechowywać w magazynie transakcyjnym przez kilka dni, tygodni, miesięcy i przechowywać dane w magazynie analitycznym przez lata lub na zawsze. Format kolumnowy magazynu analitycznego zapewnia kompresję danych naturalnych z zakresu od 50% do 90%. A koszt za GB wynosi ok. 10% rzeczywistej ceny sklepu transakcyjnego. Aby uzyskać więcej informacji na temat bieżących ograniczeń kopii zapasowych, zobacz Omówienie magazynu analitycznego.
  • Brak zadań ETL uruchomionych w środowisku, co oznacza, że nie trzeba aprowizować dla nich jednostek żądań.

Kontrolowana nadmiarowość

Jest to świetna alternatywa dla sytuacji, w których model danych już istnieje i nie można go zmienić. Istniejący model danych nie pasuje do magazynu analitycznego ze względu na reguły automatycznego wnioskowania schematu, takie jak limit zagnieżdżonych poziomów lub maksymalna liczba właściwości. Jeśli tak jest, możesz użyć zestawienia zmian usługi Azure Cosmos DB, aby zreplikować dane do innego kontenera, stosując wymagane przekształcenia dla modelu danych przyjaznego Azure Synapse Link. Zobaczmy przykład:

Scenariusz

Kontener CustomersOrdersAndItems służy do przechowywania zamówień online, w tym szczegółów klienta i elementów: adres rozliczeniowy, adres dostawy, metoda dostawy, stan dostawy, cena elementów itp. Reprezentowane są tylko pierwsze 1000 właściwości, a kluczowe informacje nie są uwzględniane w magazynie analitycznym, co blokuje użycie linku Azure Synapse. Kontener zawiera rekordy, których nie można zmienić i zmienić modelu danych.

Inną perspektywą problemu jest ilość danych big data. Miliardy wierszy są stale używane przez dział analizy, co uniemożliwia im używanie czasu wygaśnięcia do starego usunięcia danych. Utrzymywanie całej historii danych w transakcyjnej bazie danych z powodu potrzeb analitycznych wymusza ich ciągłe zwiększanie aprowizacji jednostek żądań, co wpływa na koszty. Obciążenia transakcyjne i analityczne konkurują o te same zasoby w tym samym czasie.

Postępowanie

Rozwiązanie z zestawieniem zmian

  • Zespół inżynierów postanowił użyć zestawienia zmian, aby wypełnić trzy nowe kontenery: Customers, Ordersi Items. W przypadku zestawienia zmian normalizują i spłaszczają dane. Niepotrzebne informacje są usuwane z modelu danych, a każdy kontener ma blisko 100 właściwości, co pozwala uniknąć utraty danych z powodu automatycznych limitów wnioskowania schematu.
  • Te nowe kontenery mają włączony magazyn analityczny, a teraz dział analizy używa usługi Synapse Analytics do odczytywania danych, zmniejszając użycie jednostek żądań, ponieważ zapytania analityczne są wykonywane w usłudze Synapse Apache Spark i bezserwerowych pulach SQL.
  • Kontener CustomersOrdersAndItems ma teraz ustawiony czas wygaśnięcia, aby przechowywać dane tylko przez sześć miesięcy, co pozwala na zmniejszenie użycia jednostek żądań, ponieważ w usłudze Azure Cosmos DB istnieje co najmniej 10 jednostek żądań na GB. Mniej danych, mniejsza liczba jednostek żądań.

Wnioski

Najważniejsze wnioski z tego artykułu to zrozumienie, że modelowanie danych w świecie bez schematu jest tak ważne, jak zawsze.

Tak jak nie ma jednego sposobu reprezentowania fragmentu danych na ekranie, nie ma jednego sposobu modelowania danych. Musisz zrozumieć aplikację i jak będzie ona generować, wykorzystywać i przetwarzać dane. Następnie, stosując niektóre z przedstawionych tutaj wytycznych, można ustawić tworzenie modelu, który odpowiada bezpośrednim potrzebom aplikacji. Gdy aplikacje muszą ulec zmianie, możesz użyć elastyczności bazy danych bez schematu, aby łatwo wykorzystać tę zmianę i rozwinąć model danych.

Następne kroki