Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Även om schemafria databaser, som Azure Cosmos DB, gör det enkelt att lagra och köra frågor mot ostrukturerade och halvstrukturerade data kan du tänka på din datamodell för att optimera prestanda, skalbarhet och kostnad.
Hur lagras data? Hur hämtar och frågar ditt program data? Är programmet läsintensivt eller skrivintensivt?
När du har läst den här artikeln kan du svara på följande frågor:
- Vad är datamodellering och varför ska jag bry mig?
- Hur skiljer sig modellering av data i Azure Cosmos DB från en relationsdatabas?
- Hur uttrycker du datarelationer i en icke-relationell databas?
- När bäddar jag in data och när länkar jag till data?
Tal i JSON
Azure Cosmos DB sparar dokument i JSON, så det är viktigt att avgöra om tal ska konverteras till strängar innan de lagras i JSON. Konvertera alla tal till en String om de kan överskrida gränserna för dubbelprecisionsnummer enligt definitionen i Institute of Electrical and Electronics Engineers (IEEE) 754 binary64.
JSON-specifikationen förklarar varför användning av siffror utanför den här gränsen är en felaktig metod på grund av samverkansproblem. Dessa problem är särskilt relevanta för kolumnen partitionsnyckel eftersom den är oföränderlig och kräver att datamigreringen ändras senare.
Bädda in data
När du modellerar data i Azure Cosmos DB behandlar du dina entiteter som fristående objekt som representeras som JSON-dokument .
Som jämförelse ska vi först se hur vi kan modellera data i en relationsdatabas. I följande exempel visas hur en person kan lagras i en relationsdatabas.
Strategin när du arbetar med relationsdatabaser är att normalisera alla dina data. Normalisering av dina data innebär vanligtvis att du tar en entitet, till exempel en person, och delar upp dem i diskreta komponenter. I exemplet kan en person ha flera kontaktinformationsposter och flera adressposter. Du kan ytterligare dela upp kontaktuppgifter genom att extrahera vanliga fält, till exempel typ. Samma metod gäller för adresser. Varje post kan klassificeras som Start eller Företag.
Den vägledande förutsättningen vid normalisering av data är att undvika att lagra redundanta data i varje post och i stället referera till data. I det här exemplet måste du använda JOINS för att effektivt återskapa (eller avnormalisera) dina data under körning för att kunna läsa en person med alla deras kontaktuppgifter och adresser.
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
Uppdatering av en enskild persons kontaktuppgifter och adresser kräver skrivåtgärder i många enskilda tabeller.
Nu ska vi ta en titt på hur vi skulle modellera samma data som en fristående entitet i 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}
]
}
Med den här metoden har vi avnormaliserat personposten genom att bädda in all information som är relaterad till den här personen, till exempel deras kontaktuppgifter och adresser, i ett enda JSON-dokument . Eftersom vi inte är begränsade till ett fast schema har vi dessutom flexibiliteten att göra saker som att ha kontaktuppgifter i helt olika format.
Att hämta en fullständig personpost från databasen är nu en enda läsåtgärd mot en enda container för ett enda objekt. Att uppdatera kontaktuppgifterna och adresserna för en personpost är också en enda skrivåtgärd mot ett enda objekt.
Att avnormalisera data kan minska antalet frågor och uppdateringar som programmet behöver för att slutföra vanliga åtgärder.
När du ska bädda in
I allmänhet använder du inbäddade datamodeller när:
- Det finns inneslutna relationer mellan entiteter.
- Det finns en-till-få-relationer mellan entiteter.
- Data ändras sällan.
- Data växer inte utan bindning.
- Data efterfrågas ofta tillsammans.
Kommentar
Vanligtvis ger avnormaliserade datamodeller bättre läsprestanda .
När du inte ska bädda in
Även om tumregeln i Azure Cosmos DB är att avnormalisera allt och bädda in alla data i ett enda objekt, kan den här metoden leda till situationer att undvika.
Ta det här JSON-kodfragmentet.
{
"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?"},
]
}
Det här exemplet kan vara hur en postentitet med inbäddade kommentarer skulle se ut om vi modellerade en typisk blogg eller ett system för innehållshantering (CMS). Problemet med det här exemplet är att kommentarsmatrisen är obundna, vilket innebär att det inte finns någon (praktisk) gräns för antalet kommentarer som ett enskilt inlägg kan ha. Den här designen kan orsaka problem eftersom objektets storlek kan bli oändligt stor, så undvik det.
När objektstorleken ökar blir det svårare att överföra, läsa och uppdatera data i stor skala.
I det här fallet är det bättre att tänka på följande datamodell.
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?"}
]
Den här modellen har ett objekt för varje kommentar med en egenskap som innehåller postidentifieraren. Med den här modellen kan inlägg innehålla valfritt antal kommentarer och växa effektivt. Användare som vill se mer än de senaste kommentarerna frågar denna container genom att ange postId, som bör vara partitionsnyckeln för kommentarscontainern.
Ett annat fall där inbäddning av data inte är en bra idé är när inbäddade data ofta används i objekt och ändras ofta.
Ta det här JSON-kodfragmentet.
{
"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 }
}
]
}
Det här exemplet kan representera en persons aktieportfölj. Vi valde att bädda in aktieinformationen i varje portföljdokument. I en miljö där relaterade data ändras ofta bäddar in data som ändras ofta innebär det att du ständigt uppdaterar varje portfölj. Med ett exempel på ett aktiehandelsprogram uppdaterar du varje portföljpost varje gång en aktie handlas.
Aktier zbzb kan handlas hundratals gånger på en enda dag, och tusentals användare kan ha zbzb i sina portföljer. Med en datamodell som exemplet måste systemet uppdatera tusentals portföljdokument många gånger varje dag, vilket inte skalas bra.
Referensdata
Inbäddning av data fungerar bra i många fall, men det finns scenarier där avnormalisering av dina data orsakar fler problem än det är värt. Så, vad kan du göra?
Du kan skapa relationer mellan entiteter i dokumentdatabaser, inte bara i relationsdatabaser. I en dokumentdatabas kan ett objekt innehålla information som ansluter till data i andra dokument. Azure Cosmos DB är inte utformat för komplexa relationer som de i relationsdatabaser, men enkla länkar mellan objekt är möjliga och kan vara till hjälp.
I JSON använder vi exemplet på en aktieportfölj från tidigare, men den här gången refererar vi till aktieposten i portföljen i stället för att bädda in den. På så sätt, när lagerartikeln ändras ofta under dagen, är det enda objekt som behöver uppdateras det enskilda lagerdokumentet.
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
}
En nackdel med den här metoden är att ditt program måste göra flera databasbegäranden för att få information om varje lager i en persons portfölj. Den här designen gör det snabbare att skriva data eftersom uppdateringar sker ofta. Det gör dock läsning eller frågekörning av data långsammare, vilket är mindre viktigt för det här systemet.
Kommentar
Normaliserade datamodeller kan kräva fler turer till servern.
Hur är det med främmande nycklar?
Eftersom det inte finns något begrepp om en begränsning, till exempel en sekundärnyckel, verifierar databasen inte några relationer mellan dokument i dokument. dessa länkar är i själva verket "svaga". Om du vill se till att de data som ett objekt refererar till faktiskt finns måste du göra det här steget i ditt program, eller genom att använda utlösare på serversidan eller lagrade procedurer i Azure Cosmos DB.
När du ska referera
I allmänhet använder du normaliserade datamodeller när:
- Representerar en-till-många-relationer .
- Representerar många-till-många-relationer .
- Relaterade data ändras ofta.
- Refererade data kan vara obundna.
Kommentar
Normalisering ger normalt bättre skrivprestanda .
Var placerar jag relationen?
Relationens tillväxt hjälper dig att avgöra i vilket objekt referensen ska lagras.
Om vi observerar JSON som modellerar utgivare och böcker.
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" }
Om antalet böcker per utgivare är litet och tillväxten är begränsad kan det vara användbart att lagra bokreferensen i förlagsobjektet. Men om antalet böcker per utgivare är obundet skulle den här datamodellen leda till föränderliga, växande matriser, som i exempelutgivardokumentet.
Om du byter struktur resulterar det i en modell som representerar samma data men undviker stora föränderliga samlingar.
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"}
I det här exemplet innehåller utgivardokumentet inte längre en obundna samling. I stället innehåller varje bokdokument en referens till utgivaren.
Hur gör jag för att modellera många-till-många-relationer?
I en relationsdatabas modelleras många-till-många-relationer ofta med kopplingstabeller. Dessa relationer kopplar bara samman poster från andra tabeller.
Du kan vara frestad att replikera samma sak med hjälp av dokument och skapa en datamodell som liknar följande.
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" }
Den här metoden fungerar, men att läsa in en författare med sina böcker eller en bok med författaren kräver alltid minst två extra databasfrågor. En fråga till kopplingsobjektet och sedan en annan fråga för att hämta det faktiska objektet som kopplas.
Om den här kopplingen bara sammanfogar två datadelar, varför inte släppa den helt? Betänk följande exempel.
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"]}
Med den här modellen kan du enkelt se vilka böcker en författare skrev genom att titta på deras dokument. Du kan också se vilka författare som skrev en bok genom att kontrollera bokdokumentet. Du behöver inte använda en separat kopplingstabell eller göra extra frågor. Den här modellen gör det snabbare och enklare för ditt program att hämta de data som behövs.
Hybriddatamodeller
Vi utforskar inbäddning (eller avnormalisering) och refererar till (eller normaliserar) data. Varje metod erbjuder fördelar och innebär kompromisser.
Det behöver inte alltid vara antingen eller. Tveka inte att blanda ihop saker och ting lite.
Baserat på programmets specifika användningsmönster och arbetsbelastningar kan det vara meningsfullt att blanda inbäddade och refererade data. Den här metoden kan förenkla programlogik, minska serverns tur och retur och upprätthålla bra prestanda.
Överväg följande 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"},
]
}
Här har vi (mestadels) följt den inbäddade modellen, där data från andra entiteter är inbäddade i dokumentet på den översta nivån, men andra data refereras till.
Om vi tittar på bokdokumentet kan vi se några intressanta fält när vi tittar på listan över författare. Det finns ett id fält som är det fältet vi använder för att referera tillbaka till ett författardokument, standardpraxis i en normaliserad modell, men sedan har vi också name och thumbnailUrl. Vi kan bara id använda och låta programmet hämta ytterligare information som behövs från motsvarande redigeringsobjekt med hjälp av "länken". Men eftersom programmet visar författarens namn och en miniatyrbild med varje bok, minskar avnormaliseringen av vissa data från författaren antalet serverresor per bok i en lista.
Om författarens namn ändras eller om de uppdaterar sitt foto måste du uppdatera varje bok som de publicerade. Men för det här programmet, förutsatt att författare sällan ändrar sina namn, är den här kompromissen ett acceptabelt designbeslut.
I exemplet finns det förberäknade aggregeringsvärden för att spara dyr bearbetning under en läsåtgärd. I exemplet är en del av de data som är inbäddade i redigeringsobjektet data som beräknas vid körning. Varje gång en ny bok publiceras skapas ett bokobjekt och fältet countOfBooks anges till ett beräknat värde baserat på antalet bokdokument som finns för en viss författare. Den här optimeringen skulle vara bra i läsintensiva system där vi har råd att göra beräkningar på skrivningar för att optimera läsningar.
Möjligheten att ha en modell med förberäknade fält är möjlig eftersom Azure Cosmos DB stöder transaktioner med flera dokument. Många NoSQL-butiker kan inte utföra transaktioner mellan dokument och förespråkar därför designbeslut som "alltid bädda in allt" på grund av den här begränsningen. Med Azure Cosmos DB kan du använda utlösare på serversidan eller lagrade procedurer som infogar böcker och uppdaterar författare i en ACID-transaktion. Nu behöver du inte bädda in allt i ett objekt bara för att vara säker på att dina data förblir konsekventa.
Skilja mellan olika objekttyper
I vissa scenarier kanske du vill blanda olika objekttyper i samma samling. Det här designvalet är vanligtvis fallet när du vill att flera relaterade dokument ska sitta i samma partition. Du kan till exempel placera både böcker och bokrecensioner i samma samling och partitioneras med bookId. I sådana fall vill du vanligtvis lägga till ett fält i dina dokument som identifierar deras typ för att särskilja dem.
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"
}
Datamodellering för Azure Synapse Link och Azure Cosmos DB-analysarkiv
Azure Synapse Link för Azure Cosmos DB är en molnbaserad HTAP-funktion (hybridtransaktions- och analysbearbetning) som gör att du kan köra analyser i nära realtid över driftdata i Azure Cosmos DB. Azure Synapse Link skapar en sömlös integrering mellan Azure Cosmos DB och Azure Synapse Analytics.
Den här integreringen sker via Azure Cosmos DB-analysarkivet, en kolumnrepresentation av dina transaktionsdata som möjliggör storskalig analys utan någon effekt på dina transaktionsarbetsbelastningar. Med analysarkivet kan du köra snabba och prisvärda frågor på stora datamängder. Du behöver inte kopiera data eller oroa dig för att sakta ned huvuddatabasen. När du aktiverar analysarkivet för en container kopieras varje ändring du gör i dina data till analysarkivet nästan direkt. Du behöver inte konfigurera ETL-jobb (Change Feed) eller köra jobb för att extrahera, transformera och läsa in. Systemet håller båda butikerna synkroniserade åt dig.
Med Azure Synapse Link kan du nu ansluta direkt till dina Azure Cosmos DB-containrar från Azure Synapse Analytics och få åtkomst till analyslagret utan kostnader för Request Units (request units). Azure Synapse Analytics stöder för närvarande Azure Synapse Link med Synapse Apache Spark och serverlösa SQL-pooler. Om du har ett globalt distribuerat Azure Cosmos DB-konto blir det tillgängligt i alla regioner för det kontot när du har aktiverat analysarkiv för en container.
Automatisk schemainferens för analyslager
Transaktionslagret i Azure Cosmos DB är radorienterade halvstrukturerade data, medan analysarkivet använder ett kolumnformat och ett strukturerat format. Den här konverteringen görs automatiskt för kunder med hjälp av reglerna för schemainferens i analyslagringen. Det finns gränser i konverteringsprocessen: maximalt antal kapslade nivåer, maximalt antal egenskaper, datatyper som inte stöds med mera.
Kommentar
I samband med analysarkivet betraktar vi följande strukturer som egenskap:
- JSON-element eller sträng/värde-par avgränsade med en
:" - JSON-objekt avgränsade av
{och} - JSON-matriser, avgränsade av
[och]
Du kan minimera effekten av schemainferenskonverteringar och maximera dina analysfunktioner med hjälp av följande tekniker.
Normalisering
Normaliseringen blir mindre relevant eftersom Du kan ansluta containrar med T-SQL eller Spark SQL i Azure Synapse Link. De förväntade fördelarna med normalisering är:
- Mindre datafotavtryck i både transaktions- och analyslager.
- Mindre transaktioner.
- Färre egenskaper per dokument.
- Datastrukturer med färre kapslade nivåer.
Att ha färre egenskaper och färre nivåer i dina data gör analysfrågor snabbare. Det hjälper också till att se till att alla delar av dina data ingår i analysarkivet. Som beskrivs i artikeln om regler för automatisk schemainferens finns det gränser för antalet nivåer och egenskaper som representeras i analysarkivet.
En annan viktig faktor för normalisering är att SQL-serverlösa pooler i Azure Synapse stöder resultatuppsättningar med upp till 1 000 kolumner, och att exponera kapslade kolumner också räknas mot den gränsen. Med andra ord har både analysarkiv och Synapse SQL-serverlösa pooler en gräns på 1 000 egenskaper.
Men vad ska man göra eftersom avnormalisering är en viktig datamodelleringsteknik för Azure Cosmos DB? Svaret är att du måste hitta rätt balans för dina transaktions- och analytiska arbetsbelastningar.
Partitionsnyckel
Azure Cosmos DB-partitionsnyckeln (PK) används inte i analysarkivet. Och nu kan du använda anpassad partitionering av analyslagret för att skapa kopior av analyslagret med valfri primärnyckel. På grund av den här isoleringen kan du välja en PK för dina transaktionsdata med fokus på datainmatning och punktläsningar, medan frågor mellan partitioner kan göras med Azure Synapse Link. Nu ska vi se ett exempel:
I ett hypotetiskt globalt IoT-scenario device id fungerar det som en bra partitionsnyckel eftersom alla enheter genererar en liknande datavolym, vilket förhindrar problem med frekvent partition. Men om du vill analysera data för mer än en enhet, till exempel "alla data från igår" eller "summor per stad", kan du ha problem eftersom dessa frågor är frågor mellan partitioner. Dessa frågor kan skada din transaktionsprestanda eftersom de använder en del av ditt dataflöde i enheter för begäranden för att köra. Men med Azure Synapse Link kan du köra dessa analysfrågor utan kostnader för enheter för begäranden. Kolumnformatet för analysarkivet är optimerat för analysfrågor och Azure Synapse Link har stöd för bra prestanda med Azure Synapse Analytics-körningar.
Namn på datatyper och egenskaper
Artikeln regler för automatisk schemainferens listar vilka datatyper som stöds. Även om Azure Synapse-körningar kan bearbeta datatyper som stöds på olika sätt, blockerar datatyper som inte stöds representationen i analysarkivet. Ett exempel är: När du använder DateTime-strängar som följer ISO 8601 UTC-standarden representerar Spark-pooler i Azure Synapse dessa kolumner som string och SQL-serverlösa pooler i Azure Synapse representerar dessa kolumner som varchar(8000).
En annan utmaning är att Azure Synapse Spark inte accepterar alla tecken. Även om blanksteg accepteras så görs det inte för tecken som kolon, grav accent-tecken och kommatecken. Anta att objektet har en egenskap med namnet "Förnamn, Efternamn". Den här egenskapen representeras i analysarkivet och Synapse SQL-serverlös pool kan läsa den utan problem. Men eftersom det finns i analysarkivet kan Azure Synapse Spark inte läsa några data från analysarkivet, inklusive alla andra egenskaper. I slutändan kan du inte använda Azure Synapse Spark när du har en egenskap med tecken som inte stöds i sitt namn.
Utplattade data
Varje egenskap på den översta nivån av dina Azure Cosmos DB-data blir en kolumn i analysarkivet. Egenskaper i kapslade objekt eller matriser lagras som JSON i analysarkivet och behåller sin struktur. Kapslade strukturer kräver extra bearbetning från Azure Synapse-körningar för att platta ut data i strukturerat format, vilket kan vara en utmaning i stordatascenarier.
Objektet har bara två kolumner i analysarkivet id och contactDetails. Alla andra data, email, och phone, kräver extra bearbetning via SQL-funktioner för att läsas individuellt.
{
"id": "1",
"contactDetails": [
{"email": "thomas@andersen.com"},
{"phone": "+1 555 555-5555"}
]
}
Objektet har tre kolumner i analysarkivet, id, emailoch phone. Alla data är direkt åtkomliga som kolumner.
{
"id": "1",
"email": "thomas@andersen.com",
"phone": "+1 555 555-5555"
}
Datanivåindelning
Med Azure Synapse Link kan du minska kostnaderna ur följande perspektiv:
- Färre frågor som körs i transaktionsdatabasen.
- Ett PK som är optimerat för datainmatning och punktläsningar, vilket minskar datafotavtrycket, scenarier med heta partitioner och partitionsuppdelningar.
- Datanivåindelning eftersom analytisk tidsgräns för live (attl) är oberoende av transaktionell tidsgräns för live (tttl). Du kan behålla dina transaktionsdata i transaktionslagret i några dagar, veckor, månader och lagra data i analysarkivet i flera år eller för alltid. Kolumnformatet för analysarkiv ger en naturlig datakomprimering, från 50 % upp till 90 %. Och kostnaden per GB är ~10 % av det faktiska priset för transaktionslagring. Mer information om de aktuella begränsningarna för säkerhetskopiering finns i översikten över analysarkivet.
- Inga ETL-jobb som körs i din miljö, vilket innebär att du inte behöver allokera enheter för begäranden för dem.
Kontrollerad redundans
Den här tekniken är ett bra alternativ för situationer när en datamodell redan finns och inte kan ändras. Den aktuella datamodellen fungerar inte bra med analysarkivet. Den här fördelen finns eftersom analysarkivet har regler som begränsar hur många nivåer du kan kapsla data och hur många egenskaper du kan ha i varje dokument. Om dina data är för komplexa eller har för många fält kanske viss viktig information inte ingår i analysarkivet. Om det här scenariot är ditt fall kan du använda Azure Cosmos DB-ändringsflödet för att replikera dina data till en annan container och tillämpa de nödvändiga omvandlingarna för en azure Synapse Link-vänlig datamodell. Nu ska vi se ett exempel:
Scenario
Containern CustomersOrdersAndItems används för att lagra onlinebeställningar, inklusive kund- och objektinformation: faktureringsadress, leveransadress, leveransmetod, leveransstatus, artikelpris osv. Endast de första 1 000 egenskaperna representeras och viktig information ingår inte i analysarkivet, vilket blockerar Azure Synapse Link-användning. Containern har petabyte med poster, det går inte att ändra programmet och bygga om data.
En annan aspekt av problemet är den stora datavolymen. Miljarder rader används ständigt av analysavdelningen, vilket hindrar dem från att använda tttl för gammal databorttagning. Att underhålla hela datahistoriken i transaktionsdatabasen på grund av analysbehov tvingar dem att ständigt öka etableringen av enheter för begäranden, vilket påverkar kostnaderna. Transaktions- och analysarbetsbelastningar konkurrerar om samma resurser samtidigt.
Vad kan du göra?
Lösning med förändringsflöde
- Teknikteamet bestämde sig för att använda ändringsflöde för att fylla i tre nya containrar:
Customers,OrdersochItems. Med Ändringsflöde normaliserar och plattas data ut. Onödig information tas bort från datamodellen och varje container har nära 100 egenskaper, vilket förhindrar dataförlust på grund av automatiska schemainferensgränser. - Dessa nya containrar har analysarkiv aktiverat och analysavdelningen använder Synapse Analytics för att läsa data. Detta minskar användningen av begärandeenheter eftersom analysfrågor körs i Synapse Apache Spark- och serverlösa SQL-pooler.
- Containern
CustomersOrdersAndItemshar nu TTL (time-to-live) inställd på att endast behålla data i sex månader, vilket möjliggör en annan minskning av användningsenheter för begärandeenheter, eftersom det finns minst en enhet för begäranden per GB i Azure Cosmos DB. Mindre data, färre enheter för begäranden.
Lärdomar
Den största slutsatsen i den här artikeln är att datamodellering i ett schemafritt scenario är lika viktigt som någonsin.
Precis som det inte finns något enda sätt att representera data på en skärm finns det inget enda sätt att modellera dina data. Du måste förstå ditt program och hur det producerar, förbrukar och bearbetar data. Genom att tillämpa riktlinjerna som presenteras här kan du skapa en modell som tillgodoser programmets omedelbara behov. När programmet ändras använder du flexibiliteten i en schemafri databas för att enkelt anpassa och utveckla datamodellen.