Felsök förfrågningsprobelm när du använder Azure Cosmos DB för MongoDB
GÄLLER FÖR: MongoDB
Den här artikeln går igenom en allmän metod som rekommenderas för felsökning av frågor i Azure Cosmos DB. Även om du inte bör betrakta stegen som beskrivs i den här artikeln som ett fullständigt skydd mot potentiella frågeproblem har vi tagit med de vanligaste prestandatipsen här. Du bör använda den här artikeln som utgångspunkt för felsökning av långsamma eller dyra frågor i Azure Cosmos DB:s API för MongoDB. Om du använder Azure Cosmos DB för NoSQL kan du läsa felsökningsguiden för API för NoSQL-frågor.
Frågeoptimeringar i Azure Cosmos DB kategoriseras i stort sett enligt följande:
- Optimeringar som minskar RU-avgiften (Request Unit) för frågan
- Optimeringar som bara minskar svarstiden
Om du minskar RU-avgiften för en fråga minskar du vanligtvis även svarstiden.
Kommentar
Den här artikeln förutsätter att du använder Azure Cosmos DB:s API för MongoDB-konton med version 3.6 och senare. Vissa frågor som presterar dåligt i version 3.2 har betydande förbättringar i version 3.6+. Uppgradera till version 3.6 genom att lämna in en supportbegäran.
Använd kommandot $explain för att hämta mått
När du optimerar en fråga i Azure Cosmos DB är det första steget alltid att hämta RU-avgiften för din fråga. En riktlinje är att du bör utforska sätt att sänka RU-avgiften för frågor med högre avgift än 50 RU.
Förutom att hämta RU-avgiften bör du använda kommandot $explain
för att hämta användningsstatistiken för frågor och index. Här är ett exempel som kör en fråga och använder $explain
kommandot för att visa användningsstatistik för frågor och index:
$explain kommando:
db.coll.find({foodGroup: "Baby Foods"}).explain({"executionStatistics": true })
Utdata:
{
"stages" : [
{
"stage" : "$query",
"timeInclusiveMS" : 905.2888,
"timeExclusiveMS" : 905.2888,
"in" : 362,
"out" : 362,
"details" : {
"database" : "db-test",
"collection" : "collection-test",
"query" : {
"foodGroup" : {
"$eq" : "Baby Foods"
}
},
"pathsIndexed" : [],
"pathsNotIndexed" : [
"foodGroup"
],
"shardInformation" : [
{
"activityId" : "e68e6bdd-5e89-4ec5-b053-3dbbc2428140",
"shardKeyRangeId" : "0",
"durationMS" : 788.5867,
"preemptions" : 1,
"outputDocumentCount" : 362,
"retrievedDocumentCount" : 8618
}
],
"queryMetrics" : {
"retrievedDocumentCount" : 8618,
"retrievedDocumentSizeBytes" : 104963042,
"outputDocumentCount" : 362,
"outputDocumentSizeBytes" : 2553535,
"indexHitRatio" : 0.0016802042237178,
"totalQueryExecutionTimeMS" : 777.72,
"queryPreparationTimes" : {
"queryCompilationTimeMS" : 0.19,
"logicalPlanBuildTimeMS" : 0.14,
"physicalPlanBuildTimeMS" : 0.09,
"queryOptimizationTimeMS" : 0.03
},
"indexLookupTimeMS" : 0,
"documentLoadTimeMS" : 687.22,
"vmExecutionTimeMS" : 774.09,
"runtimeExecutionTimes" : {
"queryEngineExecutionTimeMS" : 37.45,
"systemFunctionExecutionTimeMS" : 10.82,
"userDefinedFunctionExecutionTimeMS" : 0
},
"documentWriteTimeMS" : 49.42
}
}
}
],
"estimatedDelayFromRateLimitingInMilliseconds" : 0.0,
"continuation" : {
"hasMore" : false
},
"ok" : 1.0
}
Kommandoutdata $explain
är långa och innehåller detaljerad information om frågekörning. I allmänhet finns det dock några avsnitt som du bör fokusera på när du optimerar frågeprestanda:
Mätvärde | Beskrivning |
---|---|
timeInclusiveMS |
Svarstid för serverdelsfråga |
pathsIndexed |
Visar index som frågan använde |
pathsNotIndexed |
Visar index som frågan kan ha använt, om det är tillgängligt |
shardInformation |
Sammanfattning av frågeprestanda för en viss fysisk partition |
retrievedDocumentCount |
Antal dokument som läses in av frågemotorn |
outputDocumentCount |
Antal dokument som returneras i frågeresultatet |
estimatedDelayFromRateLimitingInMilliseconds |
Beräknad ytterligare frågesvarstid på grund av hastighetsbegränsning |
När du har hämtat frågemåtten retrievedDocumentCount
jämför du med outputDocumentCount
för din fråga. Använd den här jämförelsen för att identifiera relevanta avsnitt som ska granskas i den här artikeln. retrievedDocumentCount
är antalet dokument som frågemotorn behöver läsa in. outputDocumentCount
är det antal dokument som behövdes för resultatet av frågan. retrievedDocumentCount
Om är betydligt högre än outputDocumentCount
fanns det minst en del av frågan som inte kunde använda ett index och som behövde utföra en genomsökning.
Se följande avsnitt för att förstå relevanta frågeoptimeringar för ditt scenario.
Frågans RU-avgift är för hög
Antalet hämtade dokument är betydligt högre än antalet utdatadokument
Antal hämtade dokument är ungefär lika med antal utdatadokument
Frågans RU-avgift är acceptabel men svarstiden är fortfarande för hög
Frågor där antalet hämtade dokument överskrider utdatadokument
retrievedDocumentCount
är antalet dokument som frågemotorn behövde läsa in. outputDocumentCount
är antalet dokument som returneras av frågan. retrievedDocumentCount
Om är betydligt högre än outputDocumentCount
fanns det minst en del av frågan som inte kunde använda ett index och som behövde utföra en genomsökning.
Här är ett exempel på en genomsökningsfråga som inte helt hanteras av indexet:
$explain kommando:
db.coll.find(
{
$and : [
{ "foodGroup" : "Cereal Grains and Pasta"},
{ "description" : "Oat bran, cooked"}
]
}
).explain({"executionStatistics": true })
Utdata:
{
"stages" : [
{
"stage" : "$query",
"timeInclusiveMS" : 436.5716,
"timeExclusiveMS" : 436.5716,
"in" : 1,
"out" : 1,
"details" : {
"database" : "db-test",
"collection" : "indexing-test",
"query" : {
"$and" : [
{
"foodGroup" : {
"$eq" : "Cereal Grains and Pasta"
}
},
{
"description" : {
"$eq" : "Oat bran, cooked"
}
}
]
},
"pathsIndexed" : [],
"pathsNotIndexed" : [
"foodGroup",
"description"
],
"shardInformation" : [
{
"activityId" : "13a5977e-a10a-4329-b68e-87e4f0081cac",
"shardKeyRangeId" : "0",
"durationMS" : 435.4867,
"preemptions" : 1,
"outputDocumentCount" : 1,
"retrievedDocumentCount" : 8618
}
],
"queryMetrics" : {
"retrievedDocumentCount" : 8618,
"retrievedDocumentSizeBytes" : 104963042,
"outputDocumentCount" : 1,
"outputDocumentSizeBytes" : 6064,
"indexHitRatio" : 0.0,
"totalQueryExecutionTimeMS" : 433.64,
"queryPreparationTimes" : {
"queryCompilationTimeMS" : 0.12,
"logicalPlanBuildTimeMS" : 0.09,
"physicalPlanBuildTimeMS" : 0.1,
"queryOptimizationTimeMS" : 0.02
},
"indexLookupTimeMS" : 0,
"documentLoadTimeMS" : 387.44,
"vmExecutionTimeMS" : 432.93,
"runtimeExecutionTimes" : {
"queryEngineExecutionTimeMS" : 45.36,
"systemFunctionExecutionTimeMS" : 16.86,
"userDefinedFunctionExecutionTimeMS" : 0
},
"documentWriteTimeMS" : 0.13
}
}
}
],
"estimatedDelayFromRateLimitingInMilliseconds" : 0.0,
"continuation" : {
"hasMore" : false
},
"ok" : 1.0
}
( retrievedDocumentCount
8618) är betydligt högre än outputDocumentCount
(1), vilket innebär att den här frågan krävde en dokumentgenomsökning.
Inkludera nödvändiga index
Du bör kontrollera matrisen pathsNotIndexed
och lägga till dessa index. I det här exemplet ska sökvägarna foodGroup
och description
indexeras.
"pathsNotIndexed" : [
"foodGroup",
"description"
]
Metodtips för indexering i Azure Cosmos DB:s API för MongoDB skiljer sig från MongoDB. I Azure Cosmos DB:s API för MongoDB används sammansatta index endast i frågor som effektivt behöver sorteras efter flera egenskaper. Om du har frågor med filter för flera egenskaper bör du skapa index för enskilda fält för var och en av dessa egenskaper. Frågepredikat kan använda flera enkla fältindex.
Jokerteckenindex kan förenkla indexeringen. Till skillnad från i MongoDB kan jokerteckenindex stödja flera fält i frågepredikat. Det blir ingen skillnad i frågeprestanda om du använder ett enda jokerteckenindex i stället för att skapa ett separat index för varje egenskap. Att lägga till ett jokerteckenindex för alla egenskaper är det enklaste sättet att optimera alla dina frågor.
Du kan lägga till nya index när som helst, utan att det påverkar skriv- eller lästillgängligheten. Du kan spåra indextransformeringens förlopp.
Förstå vilka aggregeringsåtgärder som använder indexet
I de flesta fall använder aggregeringsåtgärder i Azure Cosmos DB:s API för MongoDB delvis index. Vanligtvis tillämpar frågemotorn likhets- och intervallfilter först och använder index. När du har tillämpat dessa filter kan frågemotorn utvärdera ytterligare filter och använda för att läsa in återstående dokument för att beräkna aggregeringen om det behövs.
Här är ett exempel:
db.coll.aggregate( [
{ $match: { foodGroup: 'Fruits and Fruit Juices' } },
{
$group: {
_id: "$foodGroup",
total: { $max: "$version" }
}
}
] )
I det här fallet kan index optimera $match
fasen. Om du lägger till ett index för foodGroup
förbättras frågeprestanda avsevärt. Precis som i MongoDB bör du placera $match
så tidigt i aggregeringspipelinen som möjligt för att maximera användningen av index.
I Azure Cosmos DB:s API för MongoDB används inte index för den faktiska aggregeringen, som i det här fallet är $max
. Om du lägger till ett index på version
förbättras inte frågeprestandan.
Frågor där det hämtade antalet dokument är lika med antal utdatadokument
retrievedDocumentCount
Om är ungefär lika med outputDocumentCount
behövde frågemotorn inte skanna många onödiga dokument.
Minimera frågor mellan partitioner
Azure Cosmos DB använder partitionering för att skala enskilda containrar när begärandeenheten och datalagringsbehoven ökar. Varje fysisk partition har ett separat och oberoende index. Om frågan har ett likhetsfilter som matchar containerns partitionsnyckel behöver du bara kontrollera den relevanta partitionens index. Den här optimeringen minskar det totala antalet RU:er som frågan kräver. Läs mer om skillnaderna mellan partitionsfrågor och frågor mellan partitioner.
Om du har ett stort antal etablerade RU:er (mer än 30 000) eller en stor mängd data lagrade (mer än cirka 100 GB), har du förmodligen en tillräckligt stor container för att se en betydande minskning av ru-avgifter för frågor.
Du kan kontrollera matrisen shardInformation
för att förstå frågemåtten för varje enskild fysisk partition. Antalet unika shardKeyRangeId
värden är antalet fysiska partitioner där frågan behövde köras. I det här exemplet kördes frågan på fyra fysiska partitioner. Det är viktigt att förstå att körningen är helt oberoende av indexanvändning. Med andra ord kan frågor mellan partitioner fortfarande använda index.
"shardInformation" : [
{
"activityId" : "42f670a8-a201-4c58-8023-363ac18d9e18",
"shardKeyRangeId" : "5",
"durationMS" : 24.3859,
"preemptions" : 1,
"outputDocumentCount" : 463,
"retrievedDocumentCount" : 463
},
{
"activityId" : "a8bf762a-37b9-4c07-8ed4-ae49961373c0",
"shardKeyRangeId" : "2",
"durationMS" : 35.8328,
"preemptions" : 1,
"outputDocumentCount" : 905,
"retrievedDocumentCount" : 905
},
{
"activityId" : "3754e36b-4258-49a6-8d4d-010555628395",
"shardKeyRangeId" : "1",
"durationMS" : 67.3969,
"preemptions" : 1,
"outputDocumentCount" : 1479,
"retrievedDocumentCount" : 1479
},
{
"activityId" : "a69a44ee-db97-4fe9-b489-3791f3d52878",
"shardKeyRangeId" : "0",
"durationMS" : 185.1523,
"preemptions" : 1,
"outputDocumentCount" : 867,
"retrievedDocumentCount" : 867
}
]
Optimeringar som minskar frågefördröjningen
I många fall kan RU-avgiften vara acceptabel även om svarstiden för frågor är för lång. I följande avsnitt finns en översikt med tips om hur svarstiden för frågor kan minskas. Om du kör samma fråga flera gånger på samma datamängd får den vanligtvis samma RU-avgift varje gång. Frågesvarstiden kan dock variera mellan frågekörningar.
Förbättra närhet
Frågor som körs från en annan region än Azure Cosmos DB-kontot har högre svarstid än om de kördes i samma region. Om du till exempel kör kod på din stationära dator bör du förvänta dig att svarstiden blir tiotals eller hundratals millisekunder längre (eller mer) än om frågan kom från en virtuell dator i samma Azure-region som Azure Cosmos DB. Det är enkelt att distribuera data globalt i Azure Cosmos DB för att säkerställa att du kan föra dina data närmare din app.
Öka etablerat dataflöde
I Azure Cosmos DB mäts ditt etablerade dataflöde i enheter för programbegäran (RU:er). Anta att du har en fråga som förbrukar 5 RU av dataflödet. Om du till exempel etablerar 1 000 RU skulle du kunna köra frågan 200 gånger per sekund. Om du försökte köra frågan när det inte fanns tillräckligt med dataflöde tillgängligt begränsar Azure Cosmos DB antalet begäranden. Azure Cosmos DB:s API för MongoDB gör automatiskt ett nytt försök efter en kort stund. Begränsade begäranden tar längre tid, så att öka det etablerade dataflödet kan ge kortare svarstid för frågor.
Värdet estimatedDelayFromRateLimitingInMilliseconds
ger en uppfattning om de potentiella svarstidsfördelarna om du ökar dataflödet.
Nästa steg
- Felsöka frågeprestanda (API för NoSQL)
- Förhindra hastighetsbegränsning med SSR
- Hantera indexering i Azure Cosmos DB-API för MongoDB
- Försöker du planera kapacitet för en migrering till Azure Cosmos DB? Du kan använda information om ditt befintliga databaskluster för kapacitetsplanering.
- Om allt du vet är antalet virtuella kärnor och servrar i ditt befintliga databaskluster läser du om att uppskatta enheter för begäranden med virtuella kärnor eller virtuella kärnor
- Om du känner till vanliga begärandefrekvenser för din aktuella databasarbetsbelastning kan du läsa om att uppskatta enheter för begäranden med azure Cosmos DB-kapacitetshanteraren