Datamodellering i Azure Cosmos DB

GÄLLER FÖR: NoSQL

Även om schemafria databaser, som Azure Cosmos DB, gör det superlätt att lagra och fråga ostrukturerade och halvstrukturerade data, bör du ägna lite tid åt att tänka på din datamodell för att få ut mesta möjliga av tjänsten vad gäller prestanda och skalbarhet och lägsta kostnad.

Hur ska data lagras? Hur kommer ditt program att hämta och fråga efter 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 gör jag för att uttrycka 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. Vilket innebär att det är nödvändigt att noggrant avgöra om det är nödvändigt att konvertera tal till strängar innan de lagras i json eller inte. Alla tal bör helst konverteras till en String, om det finns någon chans att de ligger utanför gränserna för dubbla precisionsnummer enligt IEEE 754 binary64. Json-specifikationen anger orsakerna till varför användning av siffror utanför den här gränsen i allmänhet är en dålig praxis i JSON på grund av sannolika samverkansproblem. Dessa problem är särskilt relevanta för partitionsnyckelkolumnen eftersom den inte kan ändras och kräver datamigrering för att kunna ändra den senare.

Bädda in data

När du börjar modellera data i Azure Cosmos DB försöker du behandla dina entiteter som självständiga 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.

Relationsdatabasmodell

Strategin när du arbetar med relationsdatabaser är att normalisera alla dina data. Normalisering av dina data innebär vanligtvis att ta en entitet, till exempel en person, och dela upp den i diskreta komponenter. I exemplet ovan kan en person ha flera kontaktinformationsposter och flera adressposter. Kontaktuppgifter kan delas upp ytterligare genom ytterligare extrahering av vanliga fält som en typ. Samma sak gäller för adress, varje post kan vara av typen Hem 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 skriva tillbaka (eller avnormalisera) dina data vid 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

Skrivåtgärder i många enskilda tabeller krävs för att uppdatera en enskild persons kontaktuppgifter och adresser.

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 metoden ovan 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 för olika former helt och hållet.

Att hämta en fullständig personpost från databasen är nu en enda läsåtgärd mot en enda container och för ett enda objekt. Att uppdatera kontaktinformationen och adresserna för en personpost är också en enda skrivåtgärd mot ett enskilt objekt.

Genom att avnormalisera data kan ditt program behöva utfärda färre frågor och uppdateringar 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.
  • Det finns inbäddade data som ändras sällan.
  • Det finns inbäddade data som inte växer utan bindning.
  • Det finns inbäddade data som efterfrågas ofta tillsammans.

Anteckning

Vanligtvis ger avnormaliserade datamodeller bättre läsprestanda .

När du inte ska bädda in

Tumregeln i Azure Cosmos DB är att avnormalisera allt och bädda in alla data i ett enda objekt, men detta kan leda till vissa situationer som bör undvikas.

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 kan vara så här en postentitet med inbäddade kommentarer skulle se ut om vi modellerade en typisk blogg, eller CMS, system. Problemet med det här exemplet är att kommentarsmatrisen är obegränsad, vilket innebär att det inte finns någon (praktisk) gräns för antalet kommentarer som ett enskilt inlägg kan ha. Detta kan bli ett problem eftersom storleken på objektet kan bli oändligt stort, så är en design som du bör undvika.

När objektets storlek växer påverkas möjligheten att överföra data via kabeln och läsa och uppdatera objektet i stor skala.

I det här fallet är det bättre att överväga 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 dokument för varje kommentar med en egenskap som innehåller postidentifieraren. Detta gör att inlägg kan innehålla valfritt antal kommentarer och kan växa effektivt. Användare som vill se mer än de senaste kommentarerna frågar den här containern och skickar postId, som ska 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 används ofta över 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 }
        }
    ]
}

Detta kan representera en persons aktieportfölj. Vi har valt att bädda in aktieinformationen i varje portföljdokument. I en miljö där relaterade data ändras ofta, till exempel ett aktiehandelsprogram, innebär inbäddning av data som ändras ofta att du ständigt uppdaterar varje portföljdokument varje gång en aktie handlas.

Lager zbzb kan handlas många hundratals gånger på en enda dag och tusentals användare kan ha zbzb på sin portfölj. Med en datamodell som ovanstående skulle vi behöva uppdatera tusentals portföljdokument många gånger varje dag, vilket leder till ett system som inte skalas bra.

Referensdata

Inbäddning av data fungerar bra i många fall, men det finns scenarier när avnormalisering av dina data kommer att orsaka fler problem än det är värt. Så vad gör vi nu?

Relationsdatabaser är inte den enda platsen där du kan skapa relationer mellan entiteter. I en dokumentdatabas kan du ha information i ett dokument som relaterar till data i andra dokument. Vi rekommenderar inte att du skapar system som passar bättre för en relationsdatabas i Azure Cosmos DB eller någon annan dokumentdatabas, men enkla relationer är bra och kan vara användbara.

I JSON nedan valde vi att använda 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 dokument 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 omedelbar nackdel med den här metoden är dock om ditt program krävs för att visa information om varje aktie som lagras när en persons portfölj visas; I det här fallet skulle du behöva göra flera resor till databasen för att läsa in informationen för varje lagerdokument. Här har vi fattat ett beslut om att förbättra effektiviteten i skrivåtgärder, vilket sker ofta under dagen, men i sin tur har komprometterat läsåtgärder som potentiellt har mindre inverkan på prestanda för det här specifika systemet.

Anteckning

Normaliserade datamodeller kan kräva fler turer till servern.

Hur är det med sekundärnycklar?

Eftersom det för närvarande inte finns något begrepp om en begränsning, sekundärnyckel eller på annat sätt, är alla relationer mellan dokument som du har i dokument i praktiken "svaga länkar" och kommer inte att verifieras av själva databasen. Om du vill se till att de data som ett dokument refererar till faktiskt finns måste du göra detta i ditt program, eller genom att använda utlösare på serversidan eller lagrade procedurer i Azure Cosmos DB.

När du ska referera till

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.

Anteckning

Normalisering ger vanligtvis bättre skrivprestanda .

Var placerar jag relationen?

Relationens tillväxt hjälper dig att avgöra i vilket dokument referensen ska lagras.

Om vi tittar på JSON nedan som modellerar förlag 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 med begränsad tillväxt kan det vara användbart att lagra bokreferensen i förlagsdokumentet. Men om antalet böcker per utgivare är obundet skulle den här datamodellen leda till föränderliga, växande matriser, som i utgivardokumentet ovan.

Att växla runt lite skulle resultera i en modell som fortfarande representerar samma data men nu undviker dessa 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 exemplet ovan har vi släppt den obundna samlingen i utgivardokumentet. I stället har vi bara en referens till utgivaren för varje bokdokument.

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, som bara kopplar ihop poster från andra tabeller.

Koppla tabeller

Du kan vara frestad att replikera samma sak med hjälp av dokument och skapa en datamodell som ser ut ungefär så här.

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

Detta skulle fungera. Men att läsa in antingen en författare med sina böcker eller läsa in en bok med sin författare, skulle alltid kräva minst två ytterligare frågor mot databasen. En fråga till det kopplade dokumentet och sedan en annan fråga för att hämta det faktiska dokumentet 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"]}

Nu, om jag hade en författare, vet jag omedelbart vilka böcker de har skrivit, och omvänt om jag hade en bok dokument läst jag skulle känna till ID:t för författaren (s). Detta sparar den mellanliggande frågan mot kopplingstabellen, vilket minskar antalet serverresor som programmet måste göra.

Hybriddatamodeller

Vi har nu tittat på inbäddning (eller avnormalisering) och refererar till (eller normaliserar) data. Varje metod har fördelar och kompromisser.

Det behöver inte alltid vara antingen eller, var inte rädd för att blanda ihop saker lite.

Baserat på programmets specifika användningsmönster och arbetsbelastningar kan det finnas fall där blandning av inbäddade och refererade data är meningsfullt och kan leda till enklare programlogik med färre serverresor och samtidigt upprätthålla en bra prestandanivå.

Ö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 (främst) följt den inbäddade modellen, där data från andra entiteter bäddas in i dokumentet på den översta nivån, men andra data refereras till.

Om du tittar på bokdokumentet kan vi se några intressanta fält när vi tittar på matrisen med författare. Det finns ett id fält som är det fält som vi använder för att referera tillbaka till ett redigeringsdokument, standardpraxis i en normaliserad modell, men sedan har name vi också och thumbnailUrl. Vi kunde ha fastnat med id och lämnat programmet för att få ytterligare information som behövs från respektive författare dokument med hjälp av "länk", men eftersom vårt program visar författarens namn och en miniatyrbild med varje bok visas kan vi spara en tur och retur till servern per bok i en lista genom att avnormalisera vissa data från författaren.

Visst, om författarens namn ändrades eller om de ville uppdatera sitt foto skulle vi behöva uppdatera varje bok de någonsin publicerade, men för vårt program, baserat på antagandet att författare inte ändrar sina namn ofta, är detta ett acceptabelt designbeslut.

I exemplet finns det förberäknade aggregeringsvärden för att spara dyr bearbetning på en läsåtgärd. I exemplet är en del av de data som är inbäddade i författarens dokument data som beräknas vid körning. Varje gång en ny bok publiceras skapas ett bokdokument 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, till exempel "bädda alltid 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 dokument bara för att vara säker på att dina data förblir konsekventa.

Skilja mellan olika dokumenttyper

I vissa fall kanske du vill blanda olika dokumenttyper i samma samling. Detta ä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 i dina dokument med ett fält 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"
}

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 att påverka dina transaktionsarbetsbelastningar. Det här analysarkivet är lämpligt för snabba och kostnadseffektiva frågor på stora driftdatauppsättningar, utan att kopiera data och påverka prestandan för dina transaktionsarbetsbelastningar. När du skapar en container med analysarkiv aktiverat, eller när du aktiverar analysarkiv på en befintlig container, synkroniseras alla transaktionella infogningar, uppdateringar och borttagningar med analysarkivet nästan i realtid, och inga ändringsflödes- eller ETL-jobb krävs.

Med Azure Synapse Link kan du nu ansluta direkt till dina Azure Cosmos DB-containrar från Azure Synapse Analytics och komma åt analysarkivet utan kostnader för enheter för programbegäran (enheter för programbegäran). 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 analysarkiv

Även om Azure Cosmos DB-transaktionsarkivet betraktas som radorienterade halvstrukturerade data, har analysarkivet ett kolumnformat och strukturerat format. Den här konverteringen görs automatiskt för kunder med hjälp av reglerna för schemainferens för analysarkivet. Det finns gränser i konverteringsprocessen: maximalt antal kapslade nivåer, maximalt antal egenskaper, datatyper som inte stöds med mera.

Anteckning

I samband med analysarkivet betraktar vi följande strukturer som en egenskap:

  • JSON-element eller sträng/värde-par avgränsade med " : .
  • JSON-objekt, avgränsade med { och }.
  • JSON-matriser, avgränsade med [ och ].

Du kan minimera effekten av schemainferenskonverteringar och maximera dina analysfunktioner med hjälp av följande tekniker.

Normalisering

Normaliseringen blir meningslös eftersom du med Azure Synapse Link kan ansluta mellan dina containrar med hjälp av T-SQL eller Spark SQL. De förväntade fördelarna med normalisering är:

  • Mindre datafotavtryck i både transaktions- och analysarkiv.
  • Mindre transaktioner.
  • Färre egenskaper per dokument.
  • Datastrukturer med färre kapslade nivåer.

Observera att de här två sista faktorerna, färre egenskaper och färre nivåer, bidrar till prestanda för dina analysfrågor men också minskar risken för att delar av dina data inte representeras i analysarkivet. Enligt beskrivningen 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 serverlösa SQL-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 serverlösa Synapse SQL-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.

Partition Key (Partitionsnyckel)

Din Azure Cosmos DB-partitionsnyckel (PK) används inte i analysarkivet. Och nu kan du använda anpassad partitionering i analysarkivet till kopior av analysarkivet med valfri PK. 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 är ett bra PK eftersom alla enheter har en liknande datavolym och med det kommer du inte att ha 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 det uppstå problem eftersom det är frågor mellan partitioner. Dessa frågor kan skada dina transaktionsprestanda eftersom de använder en del av ditt dataflöde i enheter för programbegäran för att köra. Men med Azure Synapse Link kan du köra dessa analysfrågor utan kostnad för enheter för programbegäran. Kolumnformatet för analysarkivet är optimerat för analysfrågor och Azure Synapse Link använder den här egenskapen för att ge 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 datatypen inte stöds blockerar representationen i analysarkivet, kan datatyper som stöds bearbetas på olika sätt av Azure Synapse-körningar. Ett exempel är: När du använder DateTime-strängar som följer STANDARDEN ISO 8601 UTC representerar Spark-pooler i Azure Synapse dessa kolumner som sträng- och SQL-serverlösa pooler i Azure Synapse representerar dessa kolumner som varchar(8000).

En annan utmaning är att inte alla tecken accepteras av Azure Synapse Spark. Även om blanksteg accepteras är tecken som kolon, grav accent och kommatecken inte det. Anta att dokumentet 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 slutet av dagen kan du inte använda Azure Synapse Spark när du har en egenskap med de tecken som inte stöds i deras namn.

Plattning av data

Alla egenskaper på rotnivån för dina Azure Cosmos DB-data representeras i analysarkivet som en kolumn och allt annat som finns på djupare nivåer i dokumentdatamodellen representeras som JSON, även det i kapslade strukturer. 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.

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

Dokumentet nedan innehåller tre kolumner i analysarkivet, id, emailoch phone. Alla data är direkt tillgängliga som kolumner.


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

Datanivåindelning

med Azure Synapse Link kan du minska kostnaderna från följande perspektiv:

  • Färre frågor som körs i transaktionsdatabasen.
  • En PK som är optimerad för datainmatning och punktläsningar, vilket minskar datafotavtrycket, scenarier med frekvent partition och partitionsdelningar.
  • Datanivåindelning eftersom time to live för analys (attl) är oberoende av transaktionell time to live (tttl). Du kan behålla dina transaktionsdata i transaktionsarkivet i några dagar, veckor, månader och behålla data i analysarkivet i flera år eller i evigheter. Kolumnformatet för analysarkiv ger en naturlig datakomprimering, från 50 % upp till 90 %. Och kostnaden per GB är ~10 % av transaktionsarkivets faktiska pris. Mer information om de aktuella begränsningarna för säkerhetskopiering finns i Översikt över analysarkiv.
  • Inga ETL-jobb körs i din miljö, vilket innebär att du inte behöver etablera enheter för programbegäran för dem.

Kontrollerad redundans

Det här är ett bra alternativ för situationer när det redan finns en datamodell och inte kan ändras. Och den befintliga datamodellen passar inte bra in i analysarkivet på grund av regler för automatisk schemainferens som gränsen för kapslade nivåer eller det maximala antalet egenskaper. Om så är fallet kan du använda Azure Cosmos DB-ändringsflöde för att replikera dina data till en annan container och tillämpa nödvändiga transformeringar för en Azure Synapse Länkvä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 PB:er med poster, det går inte att ändra programmet och bygga om data.

Ett annat perspektiv på problemet är stordatavolymen. Miljarder rader används ständigt av analysavdelningen, vilket hindrar dem från att använda tttl för gammal databorttagning. Att upprätthå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 bör jag göra?

Lösning med ändringsflöde

  • Teknikteamet bestämde sig för att använda Ändringsflöde för att fylla i tre nya containrar: Customers, Ordersoch Items. Med Ändringsflöde normaliserar och plattar de ut data. Onödig information tas bort från datamodellen och varje container har nära 100 egenskaper, vilket undviker dataförlust på grund av automatiska schemainferensgränser.
  • Dessa nya containrar har aktiverat analysarkiv och nu använder analysavdelningen Synapse Analytics för att läsa data, vilket minskar användningen av enheter för begäran eftersom analysfrågorna sker i Synapse Apache Spark och serverlösa SQL-pooler.
  • Containern CustomersOrdersAndItems har nu tttl inställd på att endast behålla data i sex månader, vilket gör det möjligt att minska användningen av andra enheter för programbegäran, eftersom det finns minst 10 enheter för begäranden per GB i Azure Cosmos DB. Mindre data, färre enheter för begäran.

Lärdomar

De största lärdomarna från den här artikeln är att förstå att datamodellering i en värld som är schemafri är lika viktig som någonsin.

På samma sätt som det inte finns något enda sätt att representera en del 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 kommer att producera, använda och bearbeta data. Genom att tillämpa några av de riktlinjer som presenteras här kan du sedan ange hur du skapar en modell som tillgodoser programmets omedelbara behov. När dina program behöver ändras kan du använda flexibiliteten i en schemafri databas för att enkelt omfamna den ändringen och utveckla datamodellen.

Nästa steg