Queryprestaties afstemmen met Azure Cosmos DB
VAN TOEPASSING OP:
SQL-API
Azure Cosmos DB biedt een SQL-APIvoor het uitvoeren van query's op gegevens, zonder dat er schema- of secundaire indexen nodig zijn. Dit artikel bevat de volgende informatie voor ontwikkelaars:
- Details op hoog niveau over hoe Azure Cosmos DB query's SQL query's werkt
- Details over queryaanvraag- en antwoordheaders en client-SDK-opties
- Tips en best practices voor queryprestaties
- Voorbeelden van het gebruik van SQL uitvoeren van statistieken voor foutopsporing van queryprestaties
Over SQL uitvoeren van query's
In Azure Cosmos DB gegevens opgeslagen in containers, die kunnen worden gedijen tot elke opslaggrootte of aanvraagdoorvoer. Azure Cosmos DB gegevens naadloos over fysieke partities geschaald om gegevensgroei of een toename van de inrichtende doorvoer af te handelen. U kunt query'SQL elke container uitvoeren met behulp van de REST API of een van de ondersteunde SQL SDK's.
Een kort overzicht van partitioneren: u definieert een partitiesleutel zoals 'plaats', die bepaalt hoe gegevens worden verdeeld over fysieke partities. Gegevens die deel uitmaken van één partitiesleutel (bijvoorbeeld 'stad' == 'Seattle') worden opgeslagen in een fysieke partitie, maar doorgaans heeft één fysieke partitie meerdere partitiesleutels. Wanneer een partitie de opslaggrootte bereikt, splitst de service de partitie naadloos op in twee nieuwe partities en verdeelt de partitiesleutel gelijkmatig over deze partities. Omdat partities tijdelijk zijn, gebruiken de API's een abstractie van een 'partitiesleutelbereik', waarmee de reeksen van partitiesleutelhashes worden aangeduid.
Wanneer u een query uitvoert om Azure Cosmos DB, voert de SDK de volgende logische stappen uit:
- Parseren van de SQL query om het uitvoeringsplan voor de query te bepalen.
- Als de query een filter op de partitiesleutel bevat, zoals
SELECT * FROM c WHERE c.city = "Seattle", wordt deze gerouteerd naar één partitie. Als de query geen filter op de partitiesleutel heeft, wordt deze uitgevoerd in alle partities en worden de resultaten samengevoegd aan de clientzijde. - De query wordt uitgevoerd binnen elke partitie in reeks of parallel, op basis van clientconfiguratie. Binnen elke partitie kan de query een of meer retouren maken, afhankelijk van de complexiteit van de query, de geconfigureerde paginagrootte en de inrichtende doorvoer van de verzameling. Elke uitvoering retourneert het aantal aanvraageenheden dat wordt verbruikt door het uitvoeren van query's, en optioneel statistieken over query-uitvoering.
- De SDK voert een samenvatting uit van de queryresultaten over meerdere partities. Als de query bijvoorbeeld een ORDER BY tussen partities omvat, worden de resultaten van afzonderlijke partities samengevoegd om resultaten in globaal gesorteerde volgorde te retourneren. Als de query een aggregatie is zoals , worden de tellingen van afzonderlijke partities
COUNTopgeteld om het totale aantal te produceren.
De SDK's bieden verschillende opties voor het uitvoeren van query's. In .NET zijn deze opties bijvoorbeeld beschikbaar in de FeedOptions klasse . In de volgende tabel worden deze opties beschreven en hoe deze van invloed zijn op de uitvoeringstijd van query's.
| Optie | Beschrijving |
|---|---|
EnableCrossPartitionQuery |
Moet worden ingesteld op true voor elke query die moet worden uitgevoerd op meer dan één partitie. Dit is een expliciete vlag waarmee u bewuste prestatie-afwegingen kunt maken tijdens de ontwikkeling. |
EnableScanInQuery |
Moet worden ingesteld op true als u voor indexering hebt gekozen, maar de query toch wilt uitvoeren via een scan. Alleen van toepassing als indexeren voor het aangevraagde filterpad is uitgeschakeld. |
MaxItemCount |
Het maximum aantal items dat per retour naar de server moet worden terug gestuurd. Door in te stellen op -1, kunt u de server het aantal items laten beheren. U kunt deze waarde ook verlagen om slechts een klein aantal items per retour op te halen. |
MaxBufferedItemCount |
Dit is een optie aan de clientzijde die wordt gebruikt om het geheugenverbruik te beperken bij het uitvoeren van ORDER BY op verschillende partities. Een hogere waarde helpt de latentie van het sorteren van partities te verminderen. |
MaxDegreeOfParallelism |
Hiermee wordt het aantal gelijktijdige bewerkingen dat aan de clientzijde wordt uitgevoerd tijdens parallelle uitvoering van query's in de Azure Cosmos-databaseservice, opgevraagd ofsets. Een positieve eigenschapswaarde beperkt het aantal gelijktijdige bewerkingen tot de setwaarde. Als deze is ingesteld op minder dan 0, bepaalt het systeem automatisch het aantal gelijktijdige bewerkingen dat moet worden uitgevoerd. |
PopulateQueryMetrics |
Maakt gedetailleerde logboekregistratie mogelijk van statistieken van de tijd die is besteed in verschillende fasen van het uitvoeren van query's, zoals compilatietijd, indexlustijd en laadtijd van documenten. U kunt uitvoer van querystatistieken delen met Ondersteuning voor Azure queryprestaties te diagnosticeren. |
RequestContinuation |
U kunt de uitvoering van query's hervatten door het ondoorzichtige vervolg-token door te geven dat door elke query wordt geretourneerd. Het vervolg-token kapselt alle status in die nodig is voor het uitvoeren van query's. |
ResponseContinuationTokenLimitInKb |
U kunt de maximale grootte beperken van het vervolg-token dat door de server wordt geretourneerd. Mogelijk moet u dit instellen als uw toepassingshost limieten heeft voor de grootte van de antwoordheader. Als u dit instelt, kunnen de totale duur en het aantal verbruikte AANVRAAG's voor de query toenemen. |
Laten we bijvoorbeeld een voorbeeldquery uitvoeren op de partitiesleutel die is aangevraagd voor een verzameling met als partitiesleutel en ingericht met /city 100.000 RU/s doorvoer. U vraagt deze query als volgt aan CreateDocumentQuery<T> met behulp van in .NET:
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();
Het bovenstaande SDK-fragment komt overeen met de volgende REST API aanvraag:
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'"}
Elke queryuitvoeringspagina komt overeen met een REST API met de header en de POST SQL query in de Accept: application/query+json hoofdtekst. Elke query maakt een of meer retouren naar de server met het token dat tussen de client en de server wordt echod om x-ms-continuation de uitvoering te hervatten. De configuratieopties in FeedOptions worden doorgegeven aan de server in de vorm van aanvraagheaders. Komt bijvoorbeeld MaxItemCount overeen met x-ms-max-item-count .
De aanvraag retourneert het volgende (afgekapt voor leesbaarheid) antwoord:
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
De belangrijkste antwoordheaders die door de query worden geretourneerd, zijn onder andere:
| Optie | Beschrijving |
|---|---|
x-ms-item-count |
Het aantal items dat in het antwoord wordt geretourneerd. Dit is afhankelijk van de opgegeven , het aantal items dat past binnen de maximale nettoladinggrootte van het antwoord, de inrichtende doorvoer en de uitvoeringstijd van x-ms-max-item-count de query. |
x-ms-continuation: |
Het vervolg-token om de uitvoering van de query te hervatten, als er aanvullende resultaten beschikbaar zijn. |
x-ms-documentdb-query-metrics |
De querystatistieken voor de uitvoering. Dit is een tekenreeks met scheidingstekens die statistieken bevat over de tijd die is besteed aan de verschillende fasen van het uitvoeren van query's. Geretourneerd als x-ms-documentdb-populatequerymetrics is ingesteld op True . |
x-ms-request-charge |
Het aantal aanvraageenheden dat door de query wordt verbruikt. |
Zie Querying resources using the REST API (Query'suitvoeren op resources met behulp van de REST API ) voor meer informatie over de REST API.
Best practices voor queryprestaties
Hier volgen de meest voorkomende factoren die van invloed zijn op Azure Cosmos DB queryprestaties. We gaan dieper in op elk van deze onderwerpen in dit artikel.
| Factor | Tip |
|---|---|
| Ingerichte doorvoer | Meet RU per query en zorg ervoor dat u de vereiste inrichtende doorvoer voor uw query's hebt. |
| Partitionering en partitiesleutels | Query's vervangen door de partitiesleutelwaarde in de filterclausule voor lage latentie. |
| SDK en queryopties | Volg de best practices voor de SDK, zoals directe connectiviteit, en stem de opties voor het uitvoeren van query's aan de clientzijde af. |
| Indexeringsbeleid | Zorg ervoor dat u de vereiste indexeringspaden/-beleid voor de query hebt. |
| Metrische gegevens voor het uitvoeren van query's | Analyseer de metrische gegevens voor het uitvoeren van query's om mogelijke herschrijven van query- en gegevensvormen te identificeren. |
Ingerichte doorvoer
In Cosmos DB maakt u containers met gegevens, elk met gereserveerde doorvoer uitgedrukt in aanvraageenheden (RU) per seconde. Een leesbewerking van een document van 1 kB is 1 RU en elke bewerking (inclusief query's) wordt genormaliseerd naar een vast aantal RU's op basis van de complexiteit. Als u bijvoorbeeld 1000 RU/s hebt ingericht voor uw container en u een query hebt zoals die 5 RU's verbruikt, kunt u SELECT * FROM c WHERE c.city = 'Seattle' (1000 RU/s) / (5 RU/query) = 200 query's per seconde uitvoeren.
Als u meer dan 200 query's per seconde indient, beperkt de service de snelheid van binnenkomende aanvragen tot meer dan 200/s. De SDK's verwerken deze case automatisch door een back-off/nieuwe poging uit te voeren, waardoor u mogelijk een hogere latentie voor deze query's ziet. Als u de inrichtende doorvoer naar de vereiste waarde verhoogt, verbetert u de latentie en doorvoer van uw query' s.
Zie Aanvraageenheden voor meer informatie over aanvraageenheden.
Partitionering en partitiesleutels
Met Azure Cosmos DB worden query's doorgaans in de volgende volgorde van snelst/efficiënt naar langzamer/minder efficiënt.
- GET op één partitiesleutel en itemsleutel
- Query uitvoeren met een filterclausule op één partitiesleutel
- Query uitvoeren zonder een gelijkheids- of bereikfilterclausule voor een eigenschap
- Query uitvoeren zonder filters
Query's die alle partities moeten raadplegen, hebben een hogere latentie nodig en kunnen hogere CPU's verbruiken. Omdat elke partitie automatisch indexeert op alle eigenschappen, kan de query in dit geval efficiënt worden uitgevoerd vanuit de index. U kunt query's die partities overspannen sneller maken met behulp van de parallelle-opties.
Zie Partitioneren in Azure Cosmos DB voor meer informatie over partitionering en partitiesleutels.
SDK en queryopties
Zie Performance Tips and Performance testing (Prestatietests en Prestatietests) voor de beste prestaties aan de clientzijde van Azure Cosmos DB. Dit omvat het gebruik van de nieuwste SDK's, het configureren van platformspecifieke configuraties zoals het standaard aantal verbindingen, de frequentie van garbage collection en het gebruik van lichtgewicht connectiviteitsopties zoals Direct/TCP.
Maximum aantal items
Voor query's kan de waarde van een aanzienlijke invloed hebben MaxItemCount op de end-to-end querytijd. Elke retour naar de server retourneren niet meer dan het aantal items in MaxItemCount (standaard 100 items). Als u deze waarde instelt op een hogere waarde (-1 is maximum en aanbevolen), wordt de queryduur in het algemeen verbeterd door het aantal retouren tussen server en client te beperken, met name voor query's met grote resultatensets.
IDocumentQuery<dynamic> query = client.CreateDocumentQuery(
UriFactory.CreateDocumentCollectionUri(DatabaseName, CollectionName),
"SELECT * FROM c WHERE c.city = 'Seattle'",
new FeedOptions
{
MaxItemCount = -1,
}).AsDocumentQuery();
Maximale graad van parallellisme
Voor query's moet u de afstemmen om de beste configuraties voor uw toepassing te identificeren, met name als u query's over verschillende partities (zonder filter op de MaxDegreeOfParallelism partitiesleutelwaarde) wilt uitvoeren. MaxDegreeOfParallelism bepaalt het maximum aantal parallelle taken, dat wil zeggen het maximum aantal partities dat parallel moet worden bezocht.
IDocumentQuery<dynamic> query = client.CreateDocumentQuery(
UriFactory.CreateDocumentCollectionUri(DatabaseName, CollectionName),
"SELECT * FROM c WHERE c.city = 'Seattle'",
new FeedOptions
{
MaxDegreeOfParallelism = -1,
EnableCrossPartitionQuery = true
}).AsDocumentQuery();
Laten we ervan uitgaan dat
- D = Standaard maximum aantal parallelle taken (= totaal aantal processoren op de clientmachine)
- P = door de gebruiker opgegeven maximum aantal parallelle taken
- N = het aantal partities dat moet worden bezocht voor het beantwoorden van een query
Hieronder volgen de gevolgen van hoe de parallelle query's zich zouden gedragen voor verschillende waarden van P.
- (P == 0) => Seriële modus
- (P == 1) => Maximum van één taak
- (P > 1) => Min(P, N) parallelle taken
- (P < 1) => Min(N, D) parallelle taken
Zie SDK's voor meer informatie over geïmplementeerde klassen en methoden SQL SDK's
Netwerklatentie
Zie Azure Cosmos DB wereldwijde distributie voor het instellen van wereldwijde distributie en het maken van verbinding met de dichtstbijzijnde regio. Netwerklatentie heeft een aanzienlijke invloed op de prestaties van query's wanneer u meerdere retouren wilt maken of een grote resultatenset uit de query moet ophalen.
In de sectie met metrische gegevens over het uitvoeren van query's wordt uitgelegd hoe u de uitvoeringstijd van query's ( ) van de server opvraagt, zodat u onderscheid kunt maken tussen de tijd die wordt besteed aan het uitvoeren van query's en de tijd die wordt besteed totalExecutionTimeInMs aan netwerkdoorvoering.
Indexeringsbeleid
Zie Indexeringsbeleid configureren voor het indexeren van paden, soorten en modi en hoe deze invloed hebben op de uitvoering van query's. Het indexeringsbeleid maakt standaard gebruik van bereikindexering voor tekenreeksen, wat effectief is voor gelijkheidsquery's. Als u bereikquery's voor tekenreeksen nodig hebt, raden we u aan het indextype Bereik op te geven voor alle tekenreeksen.
Standaard wordt Azure Cosmos DB automatische indexering toegepast op alle gegevens. Voor invoegscenario's met hoge prestaties kunt u paden uitsluiten, omdat dit de RU-kosten voor elke invoegbewerking vermindert.
Metrische gegevens voor het uitvoeren van query's
U kunt gedetailleerde metrische gegevens over het uitvoeren van query's verkrijgen door de optionele x-ms-documentdb-populatequerymetrics header ( in de FeedOptions.PopulateQueryMetrics .NET SDK) door te geven. De waarde die in wordt x-ms-documentdb-query-metrics geretourneerd, heeft de volgende sleutel-waardeparen die zijn bedoeld voor geavanceerde probleemoplossing voor het uitvoeren van query's.
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;
| Metrisch | Eenheid | Description |
|---|---|---|
totalExecutionTimeInMs |
milliseconden | Uitvoeringstijd van query |
queryCompileTimeInMs |
milliseconden | Compilatietijd van query |
queryLogicalPlanBuildTimeInMs |
milliseconden | Tijd om een logisch queryplan te maken |
queryPhysicalPlanBuildTimeInMs |
milliseconden | Tijd om een fysiek queryplan te maken |
queryOptimizationTimeInMs |
milliseconden | Tijd besteed aan het optimaliseren van query's |
VMExecutionTimeInMs |
milliseconden | Tijd besteed aan query-runtime |
indexLookupTimeInMs |
milliseconden | Tijd besteed aan de fysieke indexlaag |
documentLoadTimeInMs |
milliseconden | Tijd besteed aan het laden van documenten |
systemFunctionExecuteTimeInMs |
milliseconden | Totale tijd besteed aan het uitvoeren van systeemfuncties (ingebouwde) in milliseconden |
userFunctionExecuteTimeInMs |
milliseconden | Totale tijd besteed aan het uitvoeren van door de gebruiker gedefinieerde functies in milliseconden |
retrievedDocumentCount |
count | Totaal aantal opgehaalde documenten |
retrievedDocumentSize |
Bytes | Totale grootte van opgehaalde documenten in bytes |
outputDocumentCount |
count | Aantal uitvoerdocumenten |
writeOutputTimeInMs |
milliseconden | Tijd besteed aan het schrijven van de uitvoer in milliseconden |
indexUtilizationRatio |
ratio (<=1) | Verhouding tussen het aantal documenten dat is afgestemd op het filter en het aantal geladen documenten |
De client-SDK's kunnen intern meerdere querybewerkingen uitvoeren om de query in elke partitie te kunnen uitvoeren. De client maakt meer dan één aanroep per partitie als de totale resultaten groter zijn dan , als de query de inrichtende doorvoer voor de partitie overschrijdt, of als de nettolading van de query de maximale grootte per pagina bereikt, of als de query de door het systeem toegewezen x-ms-max-item-count time-outlimiet bereikt. Elke gedeeltelijke queryuitvoering retourneert een x-ms-documentdb-query-metrics voor die pagina.
Hier zijn enkele voorbeeldquery's en hoe u enkele van de metrische gegevens interpreteert die worden geretourneerd door het uitvoeren van query's:
| Query’s uitvoeren | Metrische voorbeeldgegevens | Description |
|---|---|---|
SELECT TOP 100 * FROM c |
"RetrievedDocumentCount": 101 |
Het aantal opgehaalde documenten is 100+1 om overeen te komen met de TOP-component. De querytijd wordt meestal besteed in WriteOutputTime en omdat het een scan DocumentLoadTime is. |
SELECT TOP 500 * FROM c |
"RetrievedDocumentCount": 501 |
RetrievedDocumentCount is nu hoger (500+1 om overeen te komen met de TOP-component). |
SELECT * FROM c WHERE c.N = 55 |
"IndexLookupTime": "00:00:00.0009500" |
Ongeveer 0,9 ms wordt besteed in IndexLookupTime voor een sleutelzoekactie, omdat het een indexzoekactie is op /N/? . |
SELECT * FROM c WHERE c.N > 55 |
"IndexLookupTime": "00:00:00.0017700" |
Iets meer tijd (1,7 ms) besteed aan IndexLookupTime tijdens een bereikscan, omdat het een indexzoekactie is op /N/? . |
SELECT TOP 500 c.N FROM c |
"IndexLookupTime": "00:00:00.0017700" |
Dezelfde tijd besteed aan DocumentLoadTime eerdere query's, maar lager WriteOutputTime omdat we slechts één eigenschap projecteren. |
SELECT TOP 500 udf.toPercent(c.N) FROM c |
"UserDefinedFunctionExecutionTime": "00:00:00.2136500" |
Ongeveer 213 ms wordt besteed aan het UserDefinedFunctionExecutionTime uitvoeren van de UDF op elke waarde van c.N . |
SELECT TOP 500 c.Name FROM c WHERE STARTSWITH(c.Name, 'Den') |
"IndexLookupTime": "00:00:00.0006400", "SystemFunctionExecutionTime": "00:00:00.0074100" |
Er wordt ongeveer 0,6 ms besteed aan IndexLookupTime /Name/? . Het grootste deel van de uitvoeringstijd van de query (ongeveer 7 ms) in SystemFunctionExecutionTime . |
SELECT TOP 500 c.Name FROM c WHERE STARTSWITH(LOWER(c.Name), 'den') |
"IndexLookupTime": "00:00:00", "RetrievedDocumentCount": 2491, "OutputDocumentCount": 500 |
De query wordt uitgevoerd als een scan omdat deze gebruikmaakt van , en LOWER 500 van de 2491 opgehaalde documenten worden geretourneerd. |
Volgende stappen
- Zie voor meer informatie over de SQL queryoperators en trefwoorden SQL query.
- Zie aanvraageenheden voor meer informatie over aanvraageenheden.
- Zie Indexeringsbeleid voor meer informatie over indexeringsbeleid