Gegevensmodellering in Azure Cosmos DB

VAN TOEPASSING OP: NoSQL

Hoewel schemavrije databases, zoals Azure Cosmos DB, het super eenvoudig maken om ongestructureerde en semi-gestructureerde gegevens op te slaan en op te vragen, moet u enige tijd besteden aan het nadenken over uw gegevensmodel om optimaal gebruik te maken van de service op het gebied van prestaties, schaalbaarheid en laagste kosten.

Hoe worden gegevens opgeslagen? Hoe gaat uw toepassing gegevens ophalen en er query's op uitvoeren? Is uw toepassing lees- of schrijfintensief?

Na het lezen van dit artikel kunt u de volgende vragen beantwoorden:

  • Wat is gegevensmodellering en waarom zou het mij schelen?
  • Hoe verschilt het modelleren van gegevens in Azure Cosmos DB van een relationele database?
  • Hoe kan ik gegevensrelaties uitdrukken in een niet-relationele database?
  • Wanneer sluit ik gegevens in en wanneer koppel ik aan gegevens?

Getallen in JSON

In Azure Cosmos DB worden documenten opgeslagen in JSON. Dit betekent dat u zorgvuldig moet bepalen of het nodig is om getallen te converteren naar tekenreeksen voordat u ze in json opslaat of niet. Alle getallen moeten idealiter worden geconverteerd naar een String, als er een kans is dat ze zich buiten de grenzen van dubbele precisie getallen volgens IEEE 754 binary64 bevinden. De Json-specificatie noemt de redenen waarom het gebruik van nummers buiten deze grens in het algemeen een slechte praktijk is in JSON vanwege waarschijnlijke interoperabiliteitsproblemen. Deze problemen zijn met name relevant voor de kolom partitiesleutel, omdat deze onveranderbaar is en gegevensmigratie vereist om deze later te wijzigen.

Gegevens insluiten

Wanneer u begint met het modelleren van gegevens in Azure Cosmos DB, probeert u uw entiteiten te behandelen als zelfstandige items die worden weergegeven als JSON-documenten .

Ter vergelijking gaan we eerst kijken hoe we gegevens in een relationele database kunnen modelleren. In het volgende voorbeeld ziet u hoe een persoon kan worden opgeslagen in een relationele database.

Relationeel databasemodel

De strategie bij het werken met relationele databases is om al uw gegevens te normaliseren. Het normaliseren van uw gegevens omvat doorgaans het nemen van een entiteit, zoals een persoon, en het opsplitsen ervan in afzonderlijke onderdelen. In het bovenstaande voorbeeld kan een persoon meerdere contactgegevensrecords en meerdere adresrecords hebben. Contactgegevens kunnen verder worden uitgesplitst door algemene velden, zoals een type, verder te extraheren. Hetzelfde geldt voor het adres. Elke record kan van het type Thuisgebruik of Zakelijk zijn.

Het uitgangspunt bij het normaliseren van gegevens is om te voorkomen dat redundante gegevens in elke record worden opgeslagen en verwijzen naar gegevens. Als u in dit voorbeeld een persoon met alle contactgegevens en adressen wilt lezen, moet u JOINS gebruiken om uw gegevens effectief op te stellen (of te denormaliseren) tijdens runtime.

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

Schrijfbewerkingen in veel afzonderlijke tabellen zijn vereist om de contactgegevens en adressen van één persoon bij te werken.

Laten we nu eens kijken hoe we dezelfde gegevens modelleren als een zelfstandige entiteit in 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}
    ]
}

Met behulp van de bovenstaande methode hebben we de persoonsrecord gedenormaliseerd door alle informatie met betrekking tot deze persoon, zoals contactgegevens en adressen, in één JSON-document in te sluiten. Omdat we niet beperkt zijn tot een vast schema, hebben we bovendien de flexibiliteit om dingen te doen zoals het volledig hebben van contactgegevens van verschillende shapes.

Het ophalen van een volledige persoonsrecord uit de database is nu één leesbewerking voor één container en voor één item. Het bijwerken van de contactgegevens en adressen van een persoonsrecord is ook één schrijfbewerking voor één item.

Door gegevens te denormaliseren, hoeft uw toepassing mogelijk minder query's en updates uit te voeren om algemene bewerkingen te voltooien.

Wanneer insluiten

Over het algemeen kunt u ingesloten gegevensmodellen gebruiken wanneer:

  • Er zijn ingesloten relaties tussen entiteiten.
  • Er zijn een-op-weinig-relaties tussen entiteiten.
  • Er zijn ingesloten gegevens die niet vaak worden gewijzigd.
  • Er zijn ingesloten gegevens die niet ongebonden kunnen groeien.
  • Er zijn ingesloten gegevens die regelmatig samen worden opgevraagd.

Notitie

Normaal gesproken gedenormaliseerde gegevensmodellen bieden betere leesprestaties .

Wanneer u niet wilt insluiten

Hoewel de vuistregel in Azure Cosmos DB is om alles te denormaliseren en alle gegevens in één item in te sluiten, kan dit leiden tot enkele situaties die moeten worden vermeden.

Neem dit JSON-fragment.

{
    "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?"},
    ]
}

Dit kan zijn hoe een postentiteit met ingesloten opmerkingen eruit zou zien als we een typisch blog- of CMS-systeem modelleren. Het probleem met dit voorbeeld is dat de opmerkingenmatrix niet afhankelijk is, wat betekent dat er geen (praktische) limiet is voor het aantal opmerkingen dat één bericht kan hebben. Dit kan een probleem worden omdat de grootte van het item oneindig groot kan worden, dus een ontwerp dat u moet vermijden.

Naarmate de grootte van het item toeneemt, wordt de mogelijkheid om de gegevens via de kabel te verzenden en het item op schaal te lezen en bij te werken, beïnvloed.

In dit geval is het beter om het volgende gegevensmodel te overwegen.

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?"}   
]

Dit model heeft een document voor elke opmerking met een eigenschap die de post-id bevat. Hierdoor kunnen berichten een willekeurig aantal opmerkingen bevatten en kunnen ze efficiënt groeien. Gebruikers die meer dan de meest recente opmerkingen willen zien, voeren een query uit op deze container die de postId doorgeeft. Dit moet de partitiesleutel zijn voor de opmerkingencontainer.

Een ander geval waarbij het insluiten van gegevens geen goed idee is, is wanneer de ingesloten gegevens vaak worden gebruikt in items en vaak worden gewijzigd.

Neem dit JSON-fragment.

{
    "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 }
        }
    ]
}

Dit kan de aandelenportefeuille van een persoon vertegenwoordigen. We hebben ervoor gekozen om de aandeleninformatie in elk portfoliodocument in te sluiten. In een omgeving waarin gerelateerde gegevens regelmatig veranderen, zoals een beurshandelstoepassing, betekent het insluiten van gegevens die regelmatig veranderen dat u elk portfoliodocument voortdurend bijwerkt telkens wanneer een aandeel wordt verhandeld.

Aandelen zbzb kunnen vele honderden keren op één dag worden verhandeld en duizenden gebruikers kunnen zbzb in hun portefeuille hebben. Met een gegevensmodel als het bovenstaande moeten we elke dag vele duizenden portfoliodocumenten bijwerken, wat leidt tot een systeem dat niet goed kan worden geschaald.

Referentiegegevens

Het insluiten van gegevens werkt in veel gevallen goed, maar er zijn scenario's waarin het denormaliseren van uw gegevens meer problemen veroorzaakt dan het waard is. Wat doen we nu?

Relationele databases zijn niet de enige plaats waar u relaties tussen entiteiten kunt maken. In een documentdatabase hebt u mogelijk informatie in het ene document die betrekking heeft op gegevens in andere documenten. Het is niet raadzaam systemen te bouwen die beter geschikt zijn voor een relationele database in Azure Cosmos DB of een andere documentdatabase, maar eenvoudige relaties zijn prima en kunnen nuttig zijn.

In de onderstaande JSON hebben we ervoor gekozen om het voorbeeld van een aandelenportefeuille van eerder te gebruiken, maar deze keer verwijzen we naar het aandelenitem in de portefeuille in plaats van het in te sluiten. Op deze manier is het enige document dat moet worden bijgewerkt, het enige document dat gedurende de dag wordt gewijzigd, het enige voorraaddocument.

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
}

Een onmiddellijk nadeel van deze aanpak is echter als uw toepassing informatie moet tonen over elke voorraad die wordt bewaard bij het weergeven van de portefeuille van een persoon; In dit geval moet u meerdere ritten naar de database maken om de informatie voor elk voorraaddocument te laden. Hier hebben we een beslissing genomen om de efficiëntie van schrijfbewerkingen te verbeteren, die vaak de hele dag plaatsvinden, maar op hun beurt gecompromitteerd zijn met de leesbewerkingen die mogelijk minder invloed hebben op de prestaties van dit specifieke systeem.

Notitie

Genormaliseerde gegevensmodellen kunnen meer retouren naar de server vereisen.

Hoe zit het met refererende sleutels?

Omdat er momenteel geen concept is van een beperking, refererende sleutel of anderszins, zijn alle relaties tussen documenten die u in documenten hebt in feite 'zwakke koppelingen' en worden ze niet geverifieerd door de database zelf. Als u ervoor wilt zorgen dat de gegevens waarnaar een document verwijst daadwerkelijk bestaan, moet u dit doen in uw toepassing of door triggers aan de serverzijde of opgeslagen procedures in Azure Cosmos DB te gebruiken.

Wanneer verwijzen

Gebruik in het algemeen genormaliseerde gegevensmodellen wanneer:

  • Vertegenwoordigt een-op-veel-relaties .
  • Veel-op-veelrelaties vertegenwoordigen.
  • Gerelateerde gegevens worden regelmatig gewijzigd.
  • Gegevens waarnaar wordt verwezen, kunnen niet-afhankelijk zijn.

Notitie

Normaliseren zorgt doorgaans voor betere schrijfprestaties .

Waar plaats ik de relatie?

De groei van de relatie bepaalt in welk document de verwijzing moet worden opgeslagen.

Als we naar de JSON hieronder kijken, worden uitgevers en boeken modelleert.

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" }

Als het aantal boeken per uitgever klein is met een beperkte groei, kan het handig zijn om de boekreferentie in het uitgeversdocument op te slaan. Als het aantal boeken per uitgever echter niet afhankelijk is, zou dit gegevensmodel leiden tot veranderlijke, groeiende matrices, zoals in het bovenstaande voorbeelddocument voor uitgevers.

Een beetje schakelen zou resulteren in een model dat nog steeds dezelfde gegevens vertegenwoordigt, maar nu deze grote veranderlijke verzamelingen vermijdt.

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"}

In het bovenstaande voorbeeld hebben we de niet-afhankelijke verzameling in het uitgeversdocument verwijderd. In plaats daarvan hebben we alleen een verwijzing naar de uitgever voor elk boekdocument.

Hoe kan ik veel-op-veel-relaties modelleren?

In een relationele database worden veel-op-veel-relaties vaak gemodelleerd met jointabellen, die alleen records uit andere tabellen samenvoegen.

Tabellen koppelen

U kunt in de verleiding komen om hetzelfde te repliceren met behulp van documenten en een gegevensmodel te maken dat er ongeveer als volgt uitziet.

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" }

Dit zou werken. Voor het laden van een auteur met de boeken of het laden van een boek met de auteur zijn echter altijd ten minste twee extra query's op de database vereist. Eén query naar het samenvoegdocument en vervolgens een andere query om het document op te halen dat daadwerkelijk wordt toegevoegd.

Als deze join slechts twee stukjes gegevens aan elkaar lijmt, waarom zou u deze dan niet volledig verwijderen? Bekijk het volgende voorbeeld.

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"]}

Als ik een auteur had, weet ik meteen welke boeken ze hebben geschreven, en omgekeerd als ik een boekdocument had geladen, zou ik de id's van de auteur(s) kennen. Hiermee wordt die tussenliggende query op de jointabel opgeslagen, waardoor het aantal retouren van de server door uw toepassing wordt verminderd.

Hybride gegevensmodellen

We hebben nu gekeken naar het insluiten (of denormaliseren) en verwijzen naar gegevens (of normaliseren). Elke aanpak heeft voordelen en compromissen.

Het hoeft niet altijd of-of te zijn, wees niet bang om dingen een beetje door elkaar te halen.

Op basis van de specifieke gebruikspatronen en workloads van uw toepassing kunnen er gevallen zijn waarin het combineren van ingesloten gegevens en waarnaar wordt verwezen, zinvol is en kan leiden tot eenvoudigere toepassingslogica met minder retouren van de server terwijl er nog steeds een goed prestatieniveau wordt gehandhaafd.

Houd rekening met de volgende 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"},
    ]
}

Hier hebben we (meestal) het ingesloten model gevolgd, waarbij gegevens van andere entiteiten worden ingesloten in het document op het hoogste niveau, maar waarnaar wordt verwezen naar andere gegevens.

Als u het boekdocument bekijkt, zien we een aantal interessante velden wanneer we kijken naar de matrix met auteurs. Er is een id veld dat het veld is dat we gebruiken om terug te verwijzen naar een auteursdocument, standaardpraktijk in een genormaliseerd model, maar dan hebben name we ook en thumbnailUrl. We hadden de toepassing kunnen blijven gebruiken id en de toepassing kunnen verlaten om aanvullende informatie te krijgen die nodig is van het betreffende auteursdocument met behulp van de 'koppeling', maar omdat onze toepassing de naam van de auteur en een miniatuurafbeelding weergeeft bij elk weergegeven boek, kunnen we een retour naar de server per boek in een lijst opslaan door enkele gegevens van de auteur te denormaliseren.

Natuurlijk, als de naam van de auteur verandert of als ze hun foto willen bijwerken, moeten we elk boek bijwerken dat ze ooit hebben gepubliceerd, maar voor onze toepassing, op basis van de veronderstelling dat auteurs hun namen niet vaak wijzigen, is dit een acceptabele ontwerpbeslissing.

In het voorbeeld zijn er vooraf berekende aggregatiewaarden om dure verwerking bij een leesbewerking te besparen. In het voorbeeld zijn sommige gegevens die zijn ingesloten in het auteursdocument gegevens die tijdens runtime worden berekend. Telkens wanneer een nieuw boek wordt gepubliceerd, wordt er een boekdocument gemaakt en wordt het veld countOfBooks ingesteld op een berekende waarde op basis van het aantal boekdocumenten dat voor een bepaalde auteur bestaat. Deze optimalisatie zou goed zijn in leesintensieve systemen waar we het ons kunnen veroorloven om berekeningen uit te voeren op schrijfbewerkingen om leesbewerkingen te optimaliseren.

De mogelijkheid om een model met vooraf berekende velden te hebben, wordt mogelijk gemaakt omdat Azure Cosmos DB transacties met meerdere documenten ondersteunt. Veel NoSQL-winkels kunnen geen transacties uitvoeren in documenten en zijn daarom voorstander van ontwerpbeslissingen, zoals 'altijd alles insluiten', vanwege deze beperking. Met Azure Cosmos DB kunt u triggers aan de serverzijde of opgeslagen procedures gebruiken waarmee boeken worden ingevoegd en auteurs worden bijgewerkt binnen een ACID-transactie. U hoeft nu niet alles in één document in te sluiten om er zeker van te zijn dat uw gegevens consistent blijven.

Onderscheid maken tussen verschillende documenttypen

In sommige scenario's wilt u mogelijk verschillende documenttypen in dezelfde verzameling combineren. dit is meestal het geval wanneer u wilt dat meerdere, gerelateerde documenten zich in dezelfde partitie bevinden. U kunt bijvoorbeeld zowel boeken als boekrecensies in dezelfde verzameling plaatsen en deze partitioneren op bookId. In dergelijke situaties wilt u meestal aan uw documenten toevoegen met een veld dat hun type identificeert om ze te onderscheiden.

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 voor Azure Cosmos DB is een cloudeigen HTAP-functie (Hybrid Transactional and Analytical Processing) waarmee u bijna realtime analyses kunt uitvoeren op operationele gegevens in Azure Cosmos DB. Azure Synapse Link zorgt voor een naadloze integratie tussen Azure Cosmos DB en Azure Synapse Analytics.

Deze integratie vindt plaats via de analytische opslag van Azure Cosmos DB, een kolomweergave van uw transactionele gegevens die grootschalige analyses mogelijk maakt zonder dat dit van invloed is op uw transactionele workloads. Deze analytische opslag is geschikt voor snelle, kosteneffectieve query's op grote operationele gegevenssets, zonder gegevens te kopiëren en de prestaties van uw transactionele workloads te beïnvloeden. Wanneer u een container maakt waarvoor analytische opslag is ingeschakeld, of wanneer u analytische opslag inschakelt voor een bestaande container, worden alle transactionele invoegingen, updates en verwijderingen in bijna realtime gesynchroniseerd met de analytische opslag, zijn er geen wijzigingenfeed- of ETL-taken vereist.

Met Azure Synapse Link kunt u nu rechtstreeks vanuit Azure Synapse Analytics verbinding maken met uw Azure Cosmos DB-containers en toegang krijgen tot de analytische opslag, zonder kosten voor aanvraageenheden (aanvraageenheden). Azure Synapse Analytics ondersteunt momenteel Azure Synapse Link met Synapse Apache Spark en serverloze SQL-pools. Als u een wereldwijd gedistribueerd Azure Cosmos DB-account hebt en u analytische opslag voor een container hebt ingeschakeld, is dit beschikbaar in alle regio's voor dat account.

Automatische schemadeductie van analytische opslag

Hoewel de transactionele opslag van Azure Cosmos DB wordt beschouwd als rijgeoriënteerde semi-gestructureerde gegevens, heeft de analytische opslag een kolomvormige en gestructureerde indeling. Deze conversie wordt automatisch uitgevoerd voor klanten, met behulp van de schemadeductieregels voor de analytische opslag. Er zijn limieten in het conversieproces: het maximum aantal geneste niveaus, het maximum aantal eigenschappen, niet-ondersteunde gegevenstypen en meer.

Notitie

In de context van analytische opslag beschouwen we de volgende structuren als eigenschap:

  • JSON 'elementen' of 'tekenreeks-waardeparen gescheiden door een : '.
  • JSON-objecten, gescheiden door { en }.
  • JSON-matrices, gescheiden door [ en ].

U kunt de impact van de conversies van schemadeductie minimaliseren en uw analytische mogelijkheden maximaliseren met behulp van de volgende technieken.

Normalisatie

Normalisatie wordt zinloos omdat u met Azure Synapse Link verbinding kunt maken tussen uw containers, met behulp van T-SQL of Spark SQL. De verwachte voordelen van normalisatie zijn:

  • Kleinere gegevensvoetafdruk in zowel transactionele als analytische opslag.
  • Kleinere transacties.
  • Minder eigenschappen per document.
  • Gegevensstructuren met minder geneste niveaus.

Houd er rekening mee dat deze laatste twee factoren, minder eigenschappen en minder niveaus, helpen bij de prestaties van uw analytische query's, maar verkleinen ook de kans dat delen van uw gegevens niet worden weergegeven in de analytische opslag. Zoals beschreven in het artikel over automatische schemadeductieregels, gelden er limieten voor het aantal niveaus en eigenschappen dat wordt weergegeven in de analytische opslag.

Een andere belangrijke factor voor normalisatie is dat serverloze SQL-pools in Azure Synapse resultatensets met maximaal 1000 kolommen ondersteunen, en het beschikbaar maken van geneste kolommen ook telt voor die limiet. Met andere woorden, zowel analytische opslag als Serverloze Synapse SQL-pools hebben een limiet van 1000 eigenschappen.

Maar wat moet u doen omdat denormalisatie een belangrijke techniek voor gegevensmodellering is voor Azure Cosmos DB? Het antwoord is dat u de juiste balans moet vinden voor uw transactionele en analytische workloads.

Partitiesleutel

Uw Azure Cosmos DB-partitiesleutel (PK) wordt niet gebruikt in de analytische opslag. En nu kunt u aangepaste partitionering van analytische opslag gebruiken om kopieën van analytische opslag te maken met behulp van elke gewenste PK. Vanwege deze isolatie kunt u een PK kiezen voor uw transactionele gegevens met de focus op gegevensopname en puntleesbewerkingen, terwijl query's tussen partities kunnen worden uitgevoerd met Azure Synapse Link. Laten we een voorbeeld bekijken:

In een hypothetisch globaal IoT-scenario is dit een goede PK omdat device id alle apparaten een vergelijkbaar gegevensvolume hebben en u daarmee geen probleem met dynamische partities hebt. Maar als u de gegevens van meer dan één apparaat wilt analyseren, zoals 'alle gegevens van gisteren' of 'totalen per plaats', kunt u problemen ondervinden omdat dit query's tussen partities zijn. Deze query's kunnen uw transactionele prestaties schaden, omdat ze een deel van uw doorvoer in aanvraageenheden gebruiken om uit te voeren. Maar met Azure Synapse Link kunt u deze analytische query's uitvoeren zonder kosten voor aanvraageenheden. De kolomindeling voor analytische opslag is geoptimaliseerd voor analytische query's en Azure Synapse Link past dit kenmerk toe om geweldige prestaties mogelijk te maken met Azure Synapse Analytics-runtimes.

Namen van gegevenstypen en eigenschappen

In het artikel Regels voor automatische schemadeductie wordt vermeld wat de ondersteunde gegevenstypen zijn. Hoewel niet-ondersteund gegevenstype de weergave in analytische opslag blokkeert, kunnen ondersteunde gegevenstypen anders worden verwerkt door de Azure Synapse runtimes. Een voorbeeld is: wanneer u Datum/tijd-tekenreeksen gebruikt die de ISO 8601 UTC-standaard volgen, vertegenwoordigen Spark-pools in Azure Synapse deze kolommen als tekenreeks en SQL serverloze pools in Azure Synapse deze kolommen als varchar(8000).

Een andere uitdaging is dat niet alle tekens worden geaccepteerd door Azure Synapse Spark. Hoewel witruimten worden geaccepteerd, zijn tekens zoals dubbele punt, accent grave en komma dat niet. Stel dat uw document een eigenschap heeft met de naam Voornaam, Achternaam. Deze eigenschap wordt weergegeven in de analytische opslag en de serverloze Synapse SQL-pool kan deze zonder problemen lezen. Maar omdat deze zich in de analytische opslag bevindt, kan Azure Synapse Spark geen gegevens lezen uit de analytische opslag, inclusief alle andere eigenschappen. Aan het einde van de dag kunt u Azure Synapse Spark niet gebruiken als u één eigenschap hebt die de niet-ondersteunde tekens in hun naam gebruikt.

Gegevens platmaken

Alle eigenschappen op het hoofdniveau van uw Azure Cosmos DB-gegevens worden weergegeven in de analytische opslag als een kolom en al het andere dat zich in diepere niveaus van uw documentgegevensmodel bevindt, wordt weergegeven als JSON, ook in geneste structuren. Geneste structuren vereisen extra verwerking van Azure Synapse runtimes om de gegevens in gestructureerde indeling plat te maken, wat een uitdaging kan zijn in big data-scenario's.

Het onderstaande document bevat slechts twee kolommen in de analytische opslag, id en contactDetails. Alle andere gegevens, email en phone, vereisen extra verwerking via SQL-functies om afzonderlijk te worden gelezen.


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

Het onderstaande document bevat drie kolommen in de analytische opslag, id, emailen phone. Alle gegevens zijn rechtstreeks toegankelijk als kolommen.


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

Gegevenslagen

met Azure Synapse Link kunt u de kosten verlagen vanuit de volgende perspectieven:

  • Er worden minder query's uitgevoerd in uw transactionele database.
  • Een PK die is geoptimaliseerd voor gegevensopname en puntleesbewerkingen, waardoor de gegevensvoetafdruk, dynamische partitiescenario's en partitiesplitsingen worden verkleind.
  • Gegevenslagen omdat analytische time-to-live (attl) onafhankelijk is van transactionele time-to-live (tttl). U kunt uw transactionele gegevens een paar dagen, weken of maanden in transactionele opslag bewaren en de gegevens jarenlang of voor altijd in analytische opslag bewaren. De kolomindeling voor analytische opslag biedt een compressie van natuurlijke gegevens, van 50% tot 90%. En de kosten per GB bedragen ~10% van de werkelijke prijs van de transactionele winkel. Zie Overzicht van analytische opslag voor meer informatie over de huidige beperkingen voor back-ups.
  • Er worden geen ETL-taken uitgevoerd in uw omgeving, wat betekent dat u er geen aanvraageenheden voor hoeft in te richten.

Gecontroleerde redundantie

Dit is een uitstekend alternatief voor situaties waarin een gegevensmodel al bestaat en niet kan worden gewijzigd. En het bestaande gegevensmodel past niet goed in de analytische opslag vanwege automatische schemadeductieregels, zoals de limiet van geneste niveaus of het maximum aantal eigenschappen. Als dit het geval is, kunt u Azure Cosmos DB-wijzigingenfeed gebruiken om uw gegevens te repliceren naar een andere container, waarbij u de vereiste transformaties toepast voor een Azure Synapse link-gebruiksvriendelijk gegevensmodel. Laten we een voorbeeld bekijken:

Scenario

Container CustomersOrdersAndItems wordt gebruikt voor het opslaan van online bestellingen, inclusief klant- en artikelgegevens: factuuradres, afleveradres, leveringsmethode, leveringsstatus, prijs van artikelen, enzovoort. Alleen de eerste 1000 eigenschappen worden weergegeven en de belangrijkste informatie wordt niet opgenomen in de analytische opslag, waardoor het gebruik van Azure Synapse Link wordt geblokkeerd. De container bevat EEN AANTAL records. Het is niet mogelijk om de toepassing te wijzigen en de gegevens te hermodelleren.

Een ander perspectief van het probleem is het volume van big data. Miljarden rijen worden voortdurend gebruikt door de afdeling Analyse, waardoor ze tttl niet kunnen gebruiken voor het verwijderen van oude gegevens. Het onderhouden van de volledige gegevensgeschiedenis in de transactionele database vanwege analytische behoeften dwingt hen om de inrichting van aanvraageenheden voortdurend te verhogen, wat van invloed is op de kosten. Transactionele en analytische workloads concurreren om dezelfde resources op hetzelfde moment.

Wat u moet doen?

Oplossing met wijzigingenfeed

  • Het technische team heeft besloten om wijzigingenfeed te gebruiken om drie nieuwe containers te vullen: Customers, Ordersen Items. Met wijzigingenfeed normaliseren en vlakken ze de gegevens af. Onnodige informatie wordt verwijderd uit het gegevensmodel en elke container heeft bijna 100 eigenschappen, waardoor gegevensverlies als gevolg van automatische schemadeductielimieten wordt voorkomen.
  • Voor deze nieuwe containers is analytische opslag ingeschakeld en nu gebruikt de afdeling Analyse Synapse Analytics om de gegevens te lezen, waardoor het gebruik van aanvraageenheden wordt verminderd omdat de analytische query's worden uitgevoerd in Synapse Apache Spark en serverloze SQL-pools.
  • Container CustomersOrdersAndItems heeft nu tttl ingesteld om gegevens slechts zes maanden te bewaren, waardoor het gebruik van nog een aanvraageenheid kan worden verminderd, omdat er minimaal 10 aanvraageenheden per GB in Azure Cosmos DB zijn. Minder gegevens, minder aanvraageenheden.

Opgedane kennis

De belangrijkste punten uit dit artikel zijn om te begrijpen dat gegevensmodellering in een wereld zonder schema's net zo belangrijk is als altijd.

Net zoals er geen enkele manier is om een stukje gegevens op een scherm weer te geven, is er geen enkele manier om uw gegevens te modelleren. U moet uw toepassing begrijpen en weten hoe deze de gegevens produceert, verbruikt en verwerkt. Vervolgens kunt u, door enkele van de hier weergegeven richtlijnen toe te passen, een model maken dat voldoet aan de onmiddellijke behoeften van uw toepassing. Wanneer uw toepassingen moeten worden gewijzigd, kunt u de flexibiliteit van een database zonder schema gebruiken om die wijziging te omarmen en uw gegevensmodel eenvoudig te ontwikkelen.

Volgende stappen