Ladění výkonu dotazů pomocí služby Azure Cosmos DB

PLATÍ PRO: SQL API

Azure Cosmos DB poskytuje rozhraní API SQL prodotazování dat bez vyžadování schématu nebo sekundárních indexů. Tento článek obsahuje následující informace pro vývojáře:

  • Podrobné informace o tom, jak Cosmos dotazování služby Azure SQL DB funguje
  • Podrobnosti o hlavičkách požadavku a odpovědi dotazu a možnostech klientské sady SDK
  • Tipy a osvědčené postupy pro výkon dotazů
  • Příklady využití statistik spouštění SQL k ladění výkonu dotazů

Informace SQL dotazu

Ve službě Azure Cosmos DB ukládáte data do kontejnerů, které se mohou zvětšovat na libovolnou velikost úložiště nebo propustnost požadavků. Azure Cosmos DB bezproblémově škáluje data napříč fyzickými oddíly na pokrývce, aby zvládla nárůst nebo zvýšení zřízené propustnosti. Dotazy na SQL kontejneru můžete vydávat pomocí REST API nebo jedné z podporovaných SQL SDK.

Stručný přehled dělení: Definujete klíč oddílu, jako je "město", který určuje, jak se data rozdělí mezi fyzické oddíly. Data patřící do jednoho klíče oddílu (například "city" == "Seattle") se ukládají v rámci fyzického oddílu, ale obvykle má jeden fyzický oddíl více klíčů oddílu. Když oddíl dosáhne velikosti úložiště, služba ho bezproblémově rozdělí na dva nové oddíly a rozdělí klíč oddílu rovnoměrně mezi tyto oddíly. Vzhledem k tomu, že oddíly jsou přechodné, rozhraní API používají abstrakci "rozsahu klíčů oddílů", která označuje rozsahy hodnot hash klíčů oddílů.

Když vydáte dotaz do služby Azure Cosmos DB, sada SDK provede tyto logické kroky:

  • Parsujte SQL dotazu a určete plán spuštění dotazu.
  • Pokud dotaz obsahuje filtr podle klíče oddílu, jako je SELECT * FROM c WHERE c.city = "Seattle" , je směrován do jednoho oddílu. Pokud dotaz nemá filtr na klíč oddílu, provede se ve všech oddílech a výsledky se sloučí na straně klienta.
  • Dotaz se provádí v rámci každého oddílu v řadě nebo paralelně na základě konfigurace klienta. V rámci každého oddílu může dotaz provést jednu nebo více cest round trips v závislosti na složitosti dotazu, nakonfigurované velikosti stránky a zřízené propustnosti kolekce. Každé spuštění vrátí počet jednotek žádostí spotřebovaných prováděním dotazu a volitelně statistiky provádění dotazů.
  • Sada SDK provede souhrn výsledků dotazu napříč oddíly. Pokud například dotaz zahrnuje ORDER BY napříč oddíly, výsledky z jednotlivých oddílů se seřadí sloučením, aby se výsledky vrátily v globálně seřazeném pořadí. Pokud je dotaz agregace, jako je , počty z jednotlivých oddílů se sečtou, aby COUNT se získal celkový počet.

Tyto sdk poskytují různé možnosti spouštění dotazů. Například v rozhraní .NET jsou tyto možnosti k dispozici ve FeedOptions třídě . Následující tabulka popisuje tyto možnosti a jejich vliv na dobu provádění dotazů.

Možnost Popis
EnableCrossPartitionQuery Pro všechny dotazy, které vyžadují spuštění napříč více než jedním oddílem, musí být nastavená hodnota true. Toto je explicitní příznak, který vám umožní při vývoji dělat vědomé kompromisy z výkonu.
EnableScanInQuery Pokud jste se odhlásit z indexování, ale přesto chcete spustit dotaz prostřednictvím kontroly, musí být nastavená na hodnotu true. Platí pouze v případě, že je indexování požadované cesty filtru zakázané.
MaxItemCount Maximální počet položek, které se vrátí za zpáteční cestu na server. Nastavením na -1 můžete nechat server spravovat počet položek. Nebo můžete tuto hodnotu snížit, aby se načítá pouze malý počet položek za zpáteční cestu.
MaxBufferedItemCount Jedná se o možnost na straně klienta, která slouží k omezení spotřeby paměti při provádění příkazu ORDER BY mezi oddíly. Vyšší hodnota pomáhá snížit latenci řazení napříč oddíly.
MaxDegreeOfParallelism Získá nebo nastaví počet souběžných operací spuštěných na straně klienta během paralelního spouštění dotazů ve službě Azure Cosmos database service. Kladná hodnota vlastnosti omezuje počet souběžných operací na nastavenou hodnotu. Pokud je nastavená menší než 0, systém automaticky rozhodne o počtu souběžných operací, které se budou spouštět.
PopulateQueryMetrics Umožňuje podrobné protokolování statistiky času stráveného v různých fázích provádění dotazů, jako je doba kompilace, doba smyčky indexu a doba načítání dokumentu. Výstup ze statistik dotazů můžete sdílet s Podpora Azure a diagnostikovat problémy s výkonem dotazů.
RequestContinuation Provádění dotazů můžete obnovit předáním neprůhledného tokenu pokračování vráceného libovolným dotazem. Pokračovací token zapouzdřuje všechny stavy potřebné ke spuštění dotazu.
ResponseContinuationTokenLimitInKb Můžete omezit maximální velikost pokračovacího tokenu vráceného serverem. Tuto možnost možná budete muset nastavit, pokud má hostitel aplikace omezení velikosti hlavičky odpovědi. Nastavením této možnosti se může zvýšit celková doba trvání a počet SPOTŘEBOVANÝCH PRO dotaz.

Podívejme se například na příklad dotazu na klíč oddílu požadovaný pro kolekci s klíčem oddílu a /city zřízením propustnosti 100 000 RU/s. Tento dotaz si vyžádáte CreateDocumentQuery<T> v .NET následujícím způsobem:

IDocumentQuery<dynamic> query = client.CreateDocumentQuery(
    UriFactory.CreateDocumentCollectionUri(DatabaseName, CollectionName), 
    "SELECT * FROM c WHERE c.city = 'Seattle'", 
    new FeedOptions 
    { 
        PopulateQueryMetrics = true, 
        MaxItemCount = -1, 
        MaxDegreeOfParallelism = -1, 
        EnableCrossPartitionQuery = true 
    }).AsDocumentQuery();

FeedResponse<dynamic> result = await query.ExecuteNextAsync();

Výše uvedený fragment kódu sady SDK odpovídá následujícímu REST API požadavku:

POST https://arramacquerymetrics-westus.documents.azure.com/dbs/db/colls/sample/docs HTTP/1.1
x-ms-continuation: 
x-ms-documentdb-isquery: True
x-ms-max-item-count: -1
x-ms-documentdb-query-enablecrosspartition: True
x-ms-documentdb-query-parallelizecrosspartitionquery: True
x-ms-documentdb-query-iscontinuationexpected: True
x-ms-documentdb-populatequerymetrics: True
x-ms-date: Tue, 27 Jun 2017 21:52:18 GMT
authorization: type%3dmaster%26ver%3d1.0%26sig%3drp1Hi83Y8aVV5V6LzZ6xhtQVXRAMz0WNMnUuvriUv%2b4%3d
x-ms-session-token: 7:8,6:2008,5:8,4:2008,3:8,2:2008,1:8,0:8,9:8,8:4008
Cache-Control: no-cache
x-ms-consistency-level: Session
User-Agent: documentdb-dotnet-sdk/1.14.1 Host/32-bit MicrosoftWindowsNT/6.2.9200.0
x-ms-version: 2017-02-22
Accept: application/json
Content-Type: application/query+json
Host: arramacquerymetrics-westus.documents.azure.com
Content-Length: 52
Expect: 100-continue

{"query":"SELECT * FROM c WHERE c.city = 'Seattle'"}

Každá stránka spuštění dotazu odpovídá REST API s hlavičkou a SQL POST Accept: application/query+json dotazu v těle. Každý dotaz provede jednu nebo více cest k serveru s tokenem, který se vyklenuje mezi klientem a serverem a x-ms-continuation pokračuje v provádění. Možnosti konfigurace v FeedOptions se předá serveru ve formě hlaviček požadavku. Například odpovídá MaxItemCount . x-ms-max-item-count

Požadavek vrátí následující odpověď (zkrácenou kvůli čitelnosti):

HTTP/1.1 200 Ok
Cache-Control: no-store, no-cache
Pragma: no-cache
Transfer-Encoding: chunked
Content-Type: application/json
Server: Microsoft-HTTPAPI/2.0
Strict-Transport-Security: max-age=31536000
x-ms-last-state-change-utc: Tue, 27 Jun 2017 21:01:57.561 GMT
x-ms-resource-quota: documentSize=10240;documentsSize=10485760;documentsCount=-1;collectionSize=10485760;
x-ms-resource-usage: documentSize=1;documentsSize=884;documentsCount=2000;collectionSize=1408;
x-ms-item-count: 2000
x-ms-schemaversion: 1.3
x-ms-alt-content-path: dbs/db/colls/sample
x-ms-content-path: +9kEANVq0wA=
x-ms-xp-role: 1
x-ms-documentdb-query-metrics: totalExecutionTimeInMs=33.67;queryCompileTimeInMs=0.06;queryLogicalPlanBuildTimeInMs=0.02;queryPhysicalPlanBuildTimeInMs=0.10;queryOptimizationTimeInMs=0.00;VMExecutionTimeInMs=32.56;indexLookupTimeInMs=0.36;documentLoadTimeInMs=9.58;systemFunctionExecuteTimeInMs=0.00;userFunctionExecuteTimeInMs=0.00;retrievedDocumentCount=2000;retrievedDocumentSize=1125600;outputDocumentCount=2000;writeOutputTimeInMs=18.10;indexUtilizationRatio=1.00
x-ms-request-charge: 604.42
x-ms-serviceversion: version=1.14.34.4
x-ms-activity-id: 0df8b5f6-83b9-4493-abda-cce6d0f91486
x-ms-session-token: 2:2008
x-ms-gatewayversion: version=1.14.33.2
Date: Tue, 27 Jun 2017 21:59:49 GMT

Mezi hlavičky klíčových odpovědí vrácené dotazem patří:

Možnost Popis
x-ms-item-count Počet položek vrácených v odpovědi To závisí na zadaném parametru , počtu položek, které se vejdou do maximální velikosti datové části odpovědi, zřízené propustnosti a x-ms-max-item-count doby provádění dotazu.
x-ms-continuation: Token pro pokračování, který obnoví provádění dotazu, pokud jsou k dispozici další výsledky.
x-ms-documentdb-query-metrics Statistika dotazu pro spuštění. Jedná se o řetězec s oddělovači obsahující statistiku času stráveného v různých fázích provádění dotazu. Vrátí x-ms-documentdb-populatequerymetrics se, pokud je nastavená hodnota True .
x-ms-request-charge Počet jednotek žádostí spotřebovaných dotazem

Podrobnosti o hlavičkách a REST API požadavku najdete v tématu Dotazování prostředků pomocí REST API.

Osvědčené postupy pro výkon dotazů

Níže jsou uvedené nejběžnější faktory, které ovlivňují výkon dotazů Azure Cosmos DB. Každé z těchto témat v tomto článku se budeme ponořit hlouběji.

Faktor Tip
Zřízená propustnost Změřte RU na dotaz a ujistěte se, že máte požadovanou zřízenou propustnost pro vaše dotazy.
Dělení a klíče oddílů Kvůli nízké latenci upřednostňujte dotazy s hodnotou klíče oddílu v klauzuli filter.
Možnosti sady SDK a dotazů Dodržujte osvědčené postupy sady SDK, jako je přímé připojení, a vylaďte možnosti spouštění dotazů na straně klienta.
Zásady indexování Ujistěte se, že pro dotaz máte požadované cesty nebo zásady indexování.
Metriky spouštění dotazů Analyzujte metriky spouštění dotazů a identifikujte potenciální přepsání tvarů dotazů a dat.

Zřízená propustnost

V Cosmos DB vytvoříte kontejnery dat, z nichž každý má rezervovanou propustnost vyjádřenou v jednotkách žádostí (RU) za sekundu. Čtení 1kB dokumentu je 1 RU a každá operace (včetně dotazů) se normalizuje na pevný počet RU na základě jeho složitosti. Pokud máte například pro kontejner zřízeno 1 000 RU/s a máte dotaz typu , který spotřebovává 5 RU, můžete takové dotazy SELECT * FROM c WHERE c.city = 'Seattle' provést (1 000 RU/s) / (5 RU/dotaz) = 200 dotazů za sekundu.

Pokud odešlete více než 200 dotazů za sekundu, služba začne omezovat rychlost příchozích požadavků nad 200/s. Sdk tento případ automaticky zvládá provedením opakování/opakování, takže si můžete všimnout vyšší latence pro tyto dotazy. Zvýšením zřízené propustnosti na požadovanou hodnotu se zvýší latence a propustnost dotazů.

Další informace o jednotkách žádostí najdete v tématu Jednotky žádostí.

Dělení a klíče oddílů

Při použití azure Cosmos DB se dotazy obvykle provádějí v následujícím pořadí od nejrychlejšího, nejúčinnějšího až po pomalejší a méně efektivní.

  • GET pro jeden klíč oddílu a klíč položky
  • Dotaz s klauzulí filtru na jeden klíč oddílu
  • Dotazování bez klauzule filtru rovnosti nebo rozsahu pro libovolnou vlastnost
  • Dotazování bez filtrů

Dotazy, které potřebují prostudovat všechny oddíly, potřebují vyšší latenci a mohou spotřebovávat vyšší počet DOTAZŮ. Vzhledem k tomu, že každý oddíl má automatické indexování proti všem vlastnostem, lze dotaz v tomto případě efektivně zpracovat z indexu. Pomocí možností paralelismus můžete vytvářet dotazy, které přesahují oddíly rychleji.

další informace o dělení a klíčích oddílů najdete v tématu dělení v Azure Cosmos DB.

Sada SDK a možnosti dotazu

informace o tom, jak dosáhnout nejlepšího výkonu na straně klienta z Azure Cosmos DB, najdete v tématu Tipy výkonu a testování výkonu . To zahrnuje použití nejnovějších sad SDK, konfigurace konfigurací specifických pro konkrétní platformu, jako je výchozí počet připojení, frekvence uvolňování paměti a použití zjednodušených možností připojení, jako je Direct/TCP.

Maximální počet položek

V případě dotazů MaxItemCount může mít hodnota významného vlivu na koncové časy dotazů. Při každé operaci odezvy na server nebude vráceno více než počet položek MaxItemCount (výchozí hodnota je 100 položek). Nastavení této hodnoty na vyšší hodnotu (-1 je maximum a doporučeno) vylepší celkovou dobu trvání dotazu tím, že omezí počet přenosů mezi serverem a klientem, zejména pro dotazy s velkými sadami výsledků.

IDocumentQuery<dynamic> query = client.CreateDocumentQuery(
    UriFactory.CreateDocumentCollectionUri(DatabaseName, CollectionName), 
    "SELECT * FROM c WHERE c.city = 'Seattle'", 
    new FeedOptions 
    { 
        MaxItemCount = -1, 
    }).AsDocumentQuery();

Maximální stupeň paralelismu

V případě dotazů můžete vyladit MaxDegreeOfParallelism a identifikovat nejlepší konfigurace pro vaši aplikaci, zejména pokud provádíte dotazy mezi oddíly (bez filtru na hodnotu klíče oddílu). MaxDegreeOfParallelism Určuje maximální počet paralelních úloh, tj. maximální počet oddílů, které mají být navštíveny paralelně.

IDocumentQuery<dynamic> query = client.CreateDocumentQuery(
    UriFactory.CreateDocumentCollectionUri(DatabaseName, CollectionName), 
    "SELECT * FROM c WHERE c.city = 'Seattle'", 
    new FeedOptions 
    { 
        MaxDegreeOfParallelism = -1, 
        EnableCrossPartitionQuery = true 
    }).AsDocumentQuery();

Pojďme předpokládat, že

  • D = výchozí maximální počet paralelních úloh (= celkový počet procesorů v klientském počítači)
  • P = uživatelem zadaný maximální počet paralelních úkolů
  • N = počet oddílů, které musí být navštíveny pro zodpovězení dotazu

Níže jsou uvedené důsledky, jak se paralelní dotazy budou chovat pro různé hodnoty P.

  • (P = = 0) => sériového režimu
  • (P = = 1) => maximálně jeden úkol
  • (P > 1) => min (P, N) Paralelní úlohy
  • (P < 1) => min (N, D) Paralelní úlohy

poznámky k verzi sady SDK a podrobnosti o implementovaných třídách a metodách naleznete v tématu SQL sdk .

Latence sítě

jak nastavit globální distribuci a připojit se k nejbližší oblasti, najdete v tématu Azure Cosmos DB globální distribuce . Latence sítě má významný dopad na výkon dotazů, pokud potřebujete udělat více přenosových cest nebo načíst velkou sadu výsledků dotazu.

Oddíl metriky spouštění dotazů vysvětluje, jak načíst dobu provádění dotazů ( totalExecutionTimeInMs ), takže můžete rozlišovat čas strávený při provádění dotazů a čas strávený při přenosu v síti.

Zásada indexování

Viz téma Konfigurace zásad indexování pro cesty, druhy a režimy indexování a to, jak ovlivňují provádění dotazů. Ve výchozím nastavení zásada indexování používá indexování rozsahu pro řetězce, které jsou platné pro dotazy na rovnost. Pokud pro řetězce potřebujete dotazy na rozsah, doporučujeme zadat typ indexu rozsahu pro všechny řetězce.

ve výchozím nastavení Azure Cosmos DB použije automatické indexování na všechna data. V případě scénářů vkládání s vysokým výkonem zvažte možnost vyloučení cest, protože se tím sníží náklady na RU za každou operaci vložení.

Metriky spuštění dotazu

Podrobné metriky pro provádění dotazů můžete získat předáním volitelné x-ms-documentdb-populatequerymetrics hlavičky ( FeedOptions.PopulateQueryMetrics v sadě .NET SDK). Hodnota vrácená v x-ms-documentdb-query-metrics má následující páry klíč-hodnota, které jsou určeny pro pokročilé řešení potíží s prováděním dotazů.

IDocumentQuery<dynamic> query = client.CreateDocumentQuery(
    UriFactory.CreateDocumentCollectionUri(DatabaseName, CollectionName), 
    "SELECT * FROM c WHERE c.city = 'Seattle'", 
    new FeedOptions 
    { 
        PopulateQueryMetrics = true, 
    }).AsDocumentQuery();

FeedResponse<dynamic> result = await query.ExecuteNextAsync();

// Returns metrics by partition key range Id
IReadOnlyDictionary<string, QueryMetrics> metrics = result.QueryMetrics;

Metric Jednotka Description
totalExecutionTimeInMs milisekundy Čas provedení dotazu
queryCompileTimeInMs milisekundy Čas kompilace dotazu
queryLogicalPlanBuildTimeInMs milisekundy Čas k sestavení plánu logického dotazu
queryPhysicalPlanBuildTimeInMs milisekundy Čas k sestavení fyzického plánu dotazu
queryOptimizationTimeInMs milisekundy Čas strávený v optimalizaci dotazu
VMExecutionTimeInMs milisekundy Čas strávený v modulu runtime dotazů
indexLookupTimeInMs milisekundy Čas strávený fyzickou indexovou vrstvou
documentLoadTimeInMs milisekundy Čas strávený načítáním dokumentů
systemFunctionExecuteTimeInMs milisekundy Celkový čas strávený prováděním systému (integrovaných) funkcí v milisekundách
userFunctionExecuteTimeInMs milisekundy Celkový čas strávený prováděním uživatelsky definovaných funkcí v milisekundách
retrievedDocumentCount count Celkový počet načtených dokumentů
retrievedDocumentSize psaný Celková velikost načtených dokumentů v bajtech
outputDocumentCount count Počet výstupních dokumentů
writeOutputTimeInMs milisekundy Čas strávený zápisem výstupu v milisekundách
indexUtilizationRatio poměr (<= 1) Poměr počtu dokumentů odpovídajících filtru na počet načtených dokumentů

Klientské sady SDK mohou interně provádět dotazy v rámci jednotlivých oddílů. Klient provede více než jedno volání na oddíl, pokud celkový výsledek překročí x-ms-max-item-count , pokud dotaz překračuje zřízenou propustnost pro oddíl, nebo pokud datová část dotazu dosáhne maximální velikosti na stránce nebo pokud dotaz dosáhne časového limitu přiděleného systému. Každé částečné spuštění dotazu vrátí x-ms-documentdb-query-metrics pro tuto stránku.

Tady je několik ukázkových dotazů a postup interpretace některých metrik vrácených spuštěním dotazu:

Dotaz Ukázková metrika Description
SELECT TOP 100 * FROM c "RetrievedDocumentCount": 101 Počet načtených dokumentů je 100 + 1, aby se shodovala s horní klauzulí. Čas dotazu se většinou stráví v WriteOutputTime a DocumentLoadTime vzhledem k tomu, že se jedná o kontrolu.
SELECT TOP 500 * FROM c "RetrievedDocumentCount": 501 RetrievedDocumentCount je teď vyšší (500 + 1 tak, aby odpovídalo horní klauzuli).
SELECT * FROM c WHERE c.N = 55 "IndexLookupTime": "00:00:00.0009500" Přibližně 0,9 MS vychází z IndexLookupTime pro vyhledávání klíčů, protože se jedná o vyhledávání v indexu /N/? .
SELECT * FROM c WHERE c.N > 55 "IndexLookupTime": "00:00:00.0017700" Ještě více času (1,7 MS) strávených IndexLookupTime nad kontrolou rozsahu, protože se jedná o vyhledávání v indexu /N/? .
SELECT TOP 500 c.N FROM c "IndexLookupTime": "00:00:00.0017700" Stejný čas strávený na DocumentLoadTime předchozích dotazech, ale nižší, WriteOutputTime protože probíhá projekce pouze jedné vlastnosti.
SELECT TOP 500 udf.toPercent(c.N) FROM c "UserDefinedFunctionExecutionTime": "00:00:00.2136500" Přibližně 213 MS se stráví UserDefinedFunctionExecutionTime spouštěním systému souborů UDF na každé hodnotě c.N .
SELECT TOP 500 c.Name FROM c WHERE STARTSWITH(c.Name, 'Den') "IndexLookupTime": "00:00:00.0006400", "SystemFunctionExecutionTime": "00:00:00.0074100" Přibližně v systému je vyčerpáno 0,6 MS IndexLookupTime /Name/? . Většina času provedení dotazu (~ 7 MS) v SystemFunctionExecutionTime .
SELECT TOP 500 c.Name FROM c WHERE STARTSWITH(LOWER(c.Name), 'den') "IndexLookupTime": "00:00:00", "RetrievedDocumentCount": 2491, "OutputDocumentCount": 500 Dotaz je proveden jako kontrola, protože používá LOWER a je vráceno 500 z 2491 načtených dokumentů.

Další kroky

  • další informace o podporovaných operátorech a klíčových slovech SQL dotazů naleznete v tématu SQL query.
  • Další informace o jednotkách žádostí najdete v tématu jednotky žádostí.
  • Další informace o zásadách indexování najdete v tématu indexování zásad .