Indexeringsprinciper i Azure Cosmos DB

GÄLLER FÖR: NoSQL

I Azure Cosmos DB har varje container en indexeringspolicy som avgör hur containerns objekt ska indexeras. Standardprincipen för indexering för nyligen skapade containrar indexerar alla egenskaper för alla objekt och tillämpar intervallindex för alla strängar och tal. På så sätt kan du få goda frågeprestanda utan att behöva tänka på indexering eller indexhantering från början.

I vissa fall kan det vara bra att åsidosätta det här automatiska beteendet så att det passar dina behov bättre. Du kan anpassa en containers indexeringsprincip genom att ange dess indexeringsläge och inkludera eller exkludera egenskapssökvägar.

Kommentar

Metoden för att uppdatera indexeringsprinciper som beskrivs i den här artikeln gäller endast för Azure Cosmos DB API för NoSQL. Lär dig mer om indexering i Azure Cosmos DB API för MongoDB

Indexeringsläge

Azure Cosmos DB stöder två indexeringslägen:

  • Konsekvent: Indexet uppdateras synkront när du skapar, uppdaterar eller tar bort objekt. Det innebär att konsekvensen för dina läsfrågor är den konsekvens som konfigurerats för kontot.
  • Ingen: Indexering är inaktiverat i containern. Det här läget används ofta när en container används som ett rent nyckelvärdeslager utan behov av sekundära index. Det kan också användas för att förbättra prestanda för massåtgärder. När massåtgärderna har slutförts kan indexläget ställas in på Konsekvent och sedan övervakas med hjälp av IndexTransformationProgress tills det är klart.

Kommentar

Azure Cosmos DB har också stöd för ett lazy-indexeringsläge. Lazy-indexering utför uppdateringar av indexet på en mycket lägre prioritetsnivå när motorn inte utför något annat arbete. Detta kan ge inkonsekventa eller ofullständiga frågeresultat. Om du planerar att köra frågor mot en Azure Cosmos DB-container bör du inte välja lat indexering. Nya containrar kan inte välja lat indexering. Du kan begära ett undantag genom att cosmosdbindexing@microsoft.com kontakta (förutom om du använder ett Azure Cosmos DB-konto i serverlöst läge som inte stöder lat indexering).

Som standard är indexeringsprincipen inställd på automatic. Det uppnås genom att ange automatic egenskapen i indexeringsprincipen till true. Om du anger den här egenskapen till true kan Azure Cosmos DB automatiskt indexera objekt när de skrivs.

Indexstorlek

I Azure Cosmos DB är den totala förbrukade lagringen kombinationen av både datastorleken och indexstorleken. Följande är några funktioner med indexstorlek:

  • Indexstorleken beror på indexeringsprincipen. Om alla egenskaper indexeras kan indexstorleken vara större än datastorleken.
  • När data tas bort komprimeras index nästan kontinuerligt. För små databorttagningar kanske du dock inte omedelbart ser en minskning av indexstorleken.
  • Indexstorleken kan tillfälligt öka när fysiska partitioner delas. Indexutrymmet frigörs när partitionsdelningen har slutförts.

Inkludera och exkludera sökvägar för egenskaper

En anpassad indexeringsprincip kan ange egenskapssökvägar som uttryckligen ingår eller undantas från indexering. Genom att optimera antalet sökvägar som indexeras kan du avsevärt minska svarstiden och RU-kostnaden för skrivåtgärder. Dessa sökvägar definieras enligt den metod som beskrivs i avsnittet indexeringsöversikt med följande tillägg:

  • en sökväg som leder till ett skalärt värde (sträng eller tal) slutar med /?
  • element från en matris åtgärdas tillsammans via notationen /[] (i stället för /0, /1 osv.)
  • jokertecknet /* kan användas för att matcha alla element under noden

Tar samma exempel igen:

    {
        "locations": [
            { "country": "Germany", "city": "Berlin" },
            { "country": "France", "city": "Paris" }
        ],
        "headquarters": { "country": "Belgium", "employees": 250 },
        "exports": [
            { "city": "Moscow" },
            { "city": "Athens" }
        ]
    }
  • sökvägen headquartersemployees är/headquarters/employees/?

  • sökvägen locationscountry är/locations/[]/country/?

  • sökvägen till något under headquarters är /headquarters/*

Vi kan till exempel inkludera /headquarters/employees/? sökvägen. Den här sökvägen skulle säkerställa att vi indexerade egenskapen employees men inte indexerade ytterligare kapslad JSON i den här egenskapen.

Inkludera/exkludera strategi

Alla indexeringsprinciper måste innehålla rotsökvägen /* som antingen en inkluderad eller en exkluderad sökväg.

  • Inkludera rotsökvägen för att selektivt exkludera sökvägar som inte behöver indexeras. Den här metoden rekommenderas eftersom Azure Cosmos DB proaktivt kan indexera alla nya egenskaper som kan läggas till i din modell.

  • Exkludera rotsökvägen för att selektivt inkludera sökvägar som måste indexeras. Egenskapssökvägen för partitionsnyckeln indexeras inte som standard med uteslutningsstrategin och bör uttryckligen inkluderas om det behövs.

  • För sökvägar med vanliga tecken som inkluderar: alfanumeriska tecken och _ (understreck) behöver du inte fly från sökvägssträngen runt dubbla citattecken (till exempel "/path/?"). För sökvägar med andra specialtecken måste du undvika sökvägssträngen runt dubbla citattecken (till exempel "/"path-abc"/?"). Om du förväntar dig specialtecken i din väg kan du fly från alla vägar för säkerhet. Funktionellt gör det ingen skillnad om du flyr från varje sökväg eller bara de som har specialtecken.

  • Systemegenskapen _etag undantas som standard från indexering, såvida inte etag läggs till i den inkluderade sökvägen för indexering.

  • Om indexeringsläget är inställt på konsekvent indexeras systemegenskaperna id och _ts indexeras automatiskt.

  • Om det inte finns någon explicit indexerad sökväg i ett objekt läggs ett värde till i indexet för att indikera att sökvägen är odefinierad.

Alla uttryckligen inkluderade sökvägar har värden som läggs till i indexet för varje objekt i containern, även om sökvägen är odefinierad för ett visst objekt.

Se det här avsnittet för indexering av principexempel för att inkludera och exkludera sökvägar.

Inkludera/exkludera prioritet

Om dina inkluderade sökvägar och exkluderade sökvägar har en konflikt har den mer exakta sökvägen företräde.

Här är ett exempel:

Inkluderad sökväg: /food/ingredients/nutrition/*

Utesluten sökväg: /food/ingredients/*

I det här fallet har den inkluderade sökvägen företräde framför den exkluderade sökvägen eftersom den är mer exakt. Baserat på dessa sökvägar skulle alla data i food/ingredients sökvägen eller kapslade inom undantas från indexet. Undantaget skulle vara data i den inkluderade sökvägen: /food/ingredients/nutrition/*, som skulle indexeras.

Här följer några regler för inkluderade och exkluderade sökvägar i Azure Cosmos DB:

  • Djupare vägar är mer exakta än smalare vägar. till exempel: /a/b/? är mer exakt än /a/?.

  • Är /? mer exakt än /*. Till exempel /a/? är mer exakt än /a/*/a/? har företräde.

  • Sökvägen /* måste antingen vara en inkluderad sökväg eller en utesluten sökväg.

Rumsliga index

När du definierar en rumslig sökväg i indexeringsprincipen bör du definiera vilket index type som ska tillämpas på den sökvägen. Möjliga typer för rumsliga index är:

  • Punkt

  • Polygon

  • MultiPolygon

  • LineString

Azure Cosmos DB skapar som standard inga rumsliga index. Om du vill använda inbyggda funktioner för spatial SQL bör du skapa ett rumsligt index för de egenskaper som krävs. Se det här avsnittet för indexering av principexempel för att lägga till rumsliga index.

Sammansatta index

Frågor som har en ORDER BY sats med två eller flera egenskaper kräver ett sammansatt index. Du kan också definiera ett sammansatt index för att förbättra prestanda för många likhets- och intervallfrågor. Som standard definieras inga sammansatta index, så du bör lägga till sammansatta index efter behov.

Till skillnad från inkluderade eller exkluderade sökvägar kan du inte skapa en sökväg med /* jokertecknet. Varje sammansatt sökväg har en implicit /? i slutet av sökvägen som du inte behöver ange. Sammansatta sökvägar leder till ett skalärt värde som är det enda värdet som ingår i det sammansatta indexet. Om en sökväg i ett sammansatt index inte finns i ett objekt eller leder till ett icke-skalärt värde läggs ett värde till i indexet för att indikera att sökvägen är odefinierad.

När du definierar ett sammansatt index anger du:

  • Två eller flera egenskapssökvägar. Sekvensen där egenskapssökvägar definieras spelar roll.

  • Ordningen (stigande eller fallande).

Kommentar

När du lägger till ett sammansatt index använder frågan befintliga intervallindex tills det nya sammansatta indextillägget har slutförts. När du lägger till ett sammansatt index kanske du därför inte omedelbart ser prestandaförbättringar. Du kan spåra förloppet för indextransformeringen med hjälp av en av SDK:erna.

ORDER BY-frågor om flera egenskaper:

Följande överväganden används när du använder sammansatta index för frågor med en ORDER BY sats med två eller flera egenskaper:

  • Om de sammansatta indexsökvägarna inte matchar sekvensen för egenskaperna i ORDER BY -satsen kan det sammansatta indexet inte stödja frågan.

  • Ordningen på sammansatta indexsökvägar (stigande eller fallande) bör också matcha order i ORDER BY -satsen.

  • Det sammansatta indexet stöder också en ORDER BY sats med motsatt ordning på alla sökvägar.

Tänk dig följande exempel där ett sammansatt index definieras för egenskapers namn, ålder och _ts:

Sammansatt index Exempelfråga ORDER BY Stöds av sammansatt index?
(name ASC, age ASC) SELECT * FROM c ORDER BY c.name ASC, c.age asc Yes
(name ASC, age ASC) SELECT * FROM c ORDER BY c.age ASC, c.name asc No
(name ASC, age ASC) SELECT * FROM c ORDER BY c.name DESC, c.age DESC Yes
(name ASC, age ASC) SELECT * FROM c ORDER BY c.name ASC, c.age DESC No
(name ASC, age ASC, timestamp ASC) SELECT * FROM c ORDER BY c.name ASC, c.age ASC, timestamp ASC Yes
(name ASC, age ASC, timestamp ASC) SELECT * FROM c ORDER BY c.name ASC, c.age ASC No

Du bör anpassa indexeringsprincipen så att du kan hantera alla nödvändiga ORDER BY frågor.

Frågor med filter för flera egenskaper

Om en fråga har filter för två eller flera egenskaper kan det vara bra att skapa ett sammansatt index för dessa egenskaper.

Tänk till exempel på följande fråga som har både ett likhets- och intervallfilter:

SELECT *
FROM c
WHERE c.name = "John" AND c.age > 18

Den här frågan blir effektivare, tar mindre tid och förbrukar färre RU:er om den kan utnyttja ett sammansatt index på (name ASC, age ASC).

Frågor med flera intervallfilter kan också optimeras med ett sammansatt index. Varje enskilt sammansatt index kan dock bara optimera ett enda intervallfilter. Intervallfilter inkluderar >, <, <=, >=och !=. Intervallfiltret ska definieras sist i det sammansatta indexet.

Överväg följande fråga med ett likhetsfilter och två intervallfilter:

SELECT *
FROM c
WHERE c.name = "John" AND c.age > 18 AND c._ts > 1612212188

Den här frågan blir effektivare med ett sammansatt index på (name ASC, age ASC) och (name ASC, _ts ASC). Frågan skulle dock inte använda ett sammansatt index på (age ASC, name ASC) eftersom egenskaperna med likhetsfilter måste definieras först i det sammansatta indexet. Två separata sammansatta index krävs i stället för ett enda sammansatt index eftersom (name ASC, age ASC, _ts ASC) varje sammansatt index bara kan optimera ett enda intervallfilter.

Följande överväganden används när du skapar sammansatta index för frågor med filter för flera egenskaper

  • Filteruttryck kan använda flera sammansatta index.
  • Egenskaperna i frågans filter ska matcha egenskaperna i det sammansatta indexet. Om en egenskap finns i det sammansatta indexet men inte ingår i frågan som ett filter använder frågan inte det sammansatta indexet.
  • Om en fråga har andra egenskaper i filtret som inte definieras i ett sammansatt index används en kombination av sammansatta index och intervallindex för att utvärdera frågan. Detta kräver färre RU:er än att endast använda intervallindex.
  • Om en egenskap har ett intervallfilter (>, <, <=, >=eller !=), bör den här egenskapen definieras sist i det sammansatta indexet. Om en fråga har fler än ett intervallfilter kan den dra nytta av flera sammansatta index.
  • När du skapar ett sammansatt index för att optimera frågor med flera filter påverkas ORDER inte resultatet av det sammansatta indexet. Den här egenskapen är valfri.

Tänk dig följande exempel där ett sammansatt index definieras för egenskapers namn, ålder och tidsstämpel:

Sammansatt index Exempelfråga Stöds av sammansatt index?
(name ASC, age ASC) SELECT * FROM c WHERE c.name = "John" AND c.age = 18 Yes
(name ASC, age ASC) SELECT * FROM c WHERE c.name = "John" AND c.age > 18 Yes
(name ASC, age ASC) SELECT COUNT(1) FROM c WHERE c.name = "John" AND c.age > 18 Yes
(name DESC, age ASC) SELECT * FROM c WHERE c.name = "John" AND c.age > 18 Yes
(name ASC, age ASC) SELECT * FROM c WHERE c.name != "John" AND c.age > 18 No
(name ASC, age ASC, timestamp ASC) SELECT * FROM c WHERE c.name = "John" AND c.age = 18 AND c.timestamp > 123049923 Yes
(name ASC, age ASC, timestamp ASC) SELECT * FROM c WHERE c.name = "John" AND c.age < 18 AND c.timestamp = 123049923 No
(name ASC, age ASC) and (name ASC, timestamp ASC) SELECT * FROM c WHERE c.name = "John" AND c.age < 18 AND c.timestamp > 123049923 Yes

Frågor med ett filter och ORDER BY

Om en fråga filtrerar på en eller flera egenskaper och har olika egenskaper i ORDER BY-satsen kan det vara bra att lägga till egenskaperna i filtret i ORDER BY -satsen.

Genom att till exempel lägga till egenskaperna i filtret i ORDER BY -satsen kan följande fråga skrivas om för att utnyttja ett sammansatt index:

Fråga med intervallindex:

SELECT *
FROM c 
WHERE c.name = "John" 
ORDER BY c.timestamp

Fråga med sammansatt index:

SELECT * 
FROM c 
WHERE c.name = "John"
ORDER BY c.name, c.timestamp

Samma frågeoptimeringar kan generaliseras för alla ORDER BY frågor med filter, med tanke på att enskilda sammansatta index endast kan stödja högst ett intervallfilter.

Fråga med intervallindex:

SELECT * 
FROM c 
WHERE c.name = "John" AND c.age = 18 AND c.timestamp > 1611947901 
ORDER BY c.timestamp

Fråga med sammansatt index:

SELECT * 
FROM c 
WHERE c.name = "John" AND c.age = 18 AND c.timestamp > 1611947901 
ORDER BY c.name, c.age, c.timestamp

Dessutom kan du använda sammansatta index för att optimera frågor med systemfunktioner och ORDER BY:

Fråga med intervallindex:

SELECT * 
FROM c 
WHERE c.firstName = "John" AND Contains(c.lastName, "Smith", true) 
ORDER BY c.lastName

Fråga med sammansatt index:

SELECT * 
FROM c 
WHERE c.firstName = "John" AND Contains(c.lastName, "Smith", true) 
ORDER BY c.firstName, c.lastName

Följande överväganden gäller när du skapar sammansatta index för att optimera en fråga med ett filter och ORDER BY en sats:

  • Om du inte definierar ett sammansatt index för en fråga med ett filter på en egenskap och en separat ORDER BY sats med en annan egenskap, kommer frågan fortfarande att lyckas. RU-kostnaden för frågan kan dock minskas med ett sammansatt index, särskilt om egenskapen i ORDER BY satsen har hög kardinalitet.
  • Om frågan filtrerar efter egenskaper bör dessa egenskaper inkluderas först i ORDER BY -satsen.
  • Om frågan filtrerar på flera egenskaper måste likhetsfiltren vara de första egenskaperna i ORDER BY -satsen.
  • Om frågan filtrerar på flera egenskaper kan du ha högst ett intervallfilter eller en systemfunktion som används per sammansatt index. Egenskapen som används i intervallfiltret eller systemfunktionen ska definieras sist i det sammansatta indexet.
  • Alla överväganden för att skapa sammansatta index för ORDER BY frågor med flera egenskaper samt frågor med filter på flera egenskaper gäller fortfarande.
Sammansatt index Exempelfråga ORDER BY Stöds av sammansatt index?
(name ASC, timestamp ASC) SELECT * FROM c WHERE c.name = "John" ORDER BY c.name ASC, c.timestamp ASC Yes
(name ASC, timestamp ASC) SELECT * FROM c WHERE c.name = "John" AND c.timestamp > 1589840355 ORDER BY c.name ASC, c.timestamp ASC Yes
(timestamp ASC, name ASC) SELECT * FROM c WHERE c.timestamp > 1589840355 AND c.name = "John" ORDER BY c.timestamp ASC, c.name ASC No
(name ASC, timestamp ASC) SELECT * FROM c WHERE c.name = "John" ORDER BY c.timestamp ASC, c.name ASC No
(name ASC, timestamp ASC) SELECT * FROM c WHERE c.name = "John" ORDER BY c.timestamp ASC No
(age ASC, name ASC, timestamp ASC) SELECT * FROM c WHERE c.age = 18 and c.name = "John" ORDER BY c.age ASC, c.name ASC,c.timestamp ASC Yes
(age ASC, name ASC, timestamp ASC) SELECT * FROM c WHERE c.age = 18 and c.name = "John" ORDER BY c.timestamp ASC No

Frågor med ett filter och en aggregering

Om en fråga filtrerar på en eller flera egenskaper och har en aggregerad systemfunktion kan det vara bra att skapa ett sammansatt index för egenskaperna i filter- och aggregerade systemfunktionen. Den här optimeringen gäller för sum- och AVG-systemfunktionerna .

Följande överväganden gäller när du skapar sammansatta index för att optimera en fråga med en filter- och aggregerad systemfunktion.

  • Sammansatta index är valfria när du kör frågor med aggregeringar. RU-kostnaden för frågan kan dock ofta minskas avsevärt med ett sammansatt index.
  • Om frågan filtrerar på flera egenskaper måste likhetsfiltren vara de första egenskaperna i det sammansatta indexet.
  • Du kan ha högst ett intervallfilter per sammansatt index och det måste finnas på egenskapen i den aggregerade systemfunktionen.
  • Egenskapen i den aggregerade systemfunktionen ska definieras sist i det sammansatta indexet.
  • ( orderASC eller DESC) spelar ingen roll.
Sammansatt index Exempelfråga Stöds av sammansatt index?
(name ASC, timestamp ASC) SELECT AVG(c.timestamp) FROM c WHERE c.name = "John" Yes
(timestamp ASC, name ASC) SELECT AVG(c.timestamp) FROM c WHERE c.name = "John" No
(name ASC, timestamp ASC) SELECT AVG(c.timestamp) FROM c WHERE c.name > "John" No
(name ASC, age ASC, timestamp ASC) SELECT AVG(c.timestamp) FROM c WHERE c.name = "John" AND c.age = 25 Yes
(age ASC, timestamp ASC) SELECT AVG(c.timestamp) FROM c WHERE c.name = "John" AND c.age > 25 No

Ändra indexeringsprincipen

En containers indexeringsprincip kan uppdateras när som helst med hjälp av Azure-portalen eller någon av de SDK:er som stöds. En uppdatering av indexeringsprincipen utlöser en transformering från det gamla indexet till det nya, som utförs online och på plats (så inget ytterligare lagringsutrymme förbrukas under åtgärden). Den gamla indexeringsprincipen omvandlas effektivt till den nya principen utan att påverka skrivtillgängligheten, lästillgängligheten eller dataflödet som etablerats i containern. Indextransformeringen är en asynkron åtgärd och den tid det tar att slutföra beror på det etablerade dataflödet, antalet objekt och deras storlek. Om flera indexeringsprincipuppdateringar måste göras rekommenderar vi att du gör alla ändringar som en enda åtgärd för att indextransformeringen ska slutföras så snabbt som möjligt.

Viktigt!

Indextransformering är en åtgärd som använder enheter för programbegäran. Enheter för programbegäran som används av en indextransformering debiteras för närvarande inte om du använder serverlösa containrar. Dessa enheter för begärande debiteras när serverlösa blir allmänt tillgängliga.

Kommentar

Du kan spåra förloppet för indextransformeringen i Azure-portalen eller med hjälp av någon av SDK:erna.

Skrivtillgängligheten påverkas inte under indextransformeringar. Indextransformeringen använder dina etablerade RU:er men med lägre prioritet än crud-åtgärder eller frågor.

Lästillgängligheten påverkas inte när nya indexerade sökvägar läggs till. Frågor använder bara nya indexerade sökvägar när en indextransformering är klar. När du lägger till en ny indexerad sökväg får med andra ord frågor som drar nytta av den indexerade sökvägen samma prestanda före och under indextransformeringen. När indextransformeringen är klar börjar frågemotorn använda de nya indexerade sökvägarna.

När du tar bort indexerade sökvägar bör du gruppera alla dina ändringar i en indexeringsprincipomvandling. Om du tar bort flera index och gör det i en enda ändring av indexeringsprincipen ger frågemotorn konsekventa och fullständiga resultat under indextransformeringen. Men om du tar bort index via flera indexeringsprincipändringar ger frågemotorn inte konsekventa eller fullständiga resultat förrän alla indextransformeringar har slutförts. De flesta utvecklare släpper inte index och försöker sedan omedelbart köra frågor som använder dessa index, så i praktiken är den här situationen osannolik.

När du släpper en indexerad sökväg slutar frågemotorn omedelbart att använda den och gör en fullständig genomsökning i stället.

Kommentar

Om möjligt bör du alltid försöka gruppera flera indexborttagningar i en enda ändring av indexeringsprincipen.

Viktigt!

Att ta bort ett index påverkar omedelbart, medan det tar lite tid att lägga till ett nytt index eftersom det kräver en indexeringstransformering. När du ersätter ett index med ett annat (till exempel ersätta ett enskilt egenskapsindex med ett sammansatt index) måste du lägga till det nya indexet först och sedan vänta tills indextransformeringen har slutförts innan du tar bort det tidigare indexet från indexeringsprincipen. Annars påverkar detta din möjlighet att fråga det tidigare indexet negativt och kan bryta alla aktiva arbetsbelastningar som refererar till det tidigare indexet.

Indexeringsprinciper och TTL

Användning av TTL-funktionen (Time-to-Live) kräver indexering. Detta innebär att:

  • det går inte att aktivera TTL på en container där indexeringsläget är inställt på none,
  • Det går inte att ange indexeringsläget till Ingen på en container där TTL är aktiverat.

För scenarier där ingen egenskapssökväg behöver indexeras, men TTL krävs, kan du använda en indexeringsprincip med indexeringsläget inställt på consistent, inga inkluderade sökvägar och /* som den enda undantagna sökvägen.

Nästa steg

Läs mer om indexering i följande artiklar: