2017-05-23 1 views
3

J'ai un scénario où je stocke de grandes quantités de données tierces pour l'analyse ad-hoc par les utilisateurs professionnels. La plupart des requêtes sur les données seront compliquées, utilisant plusieurs auto-jointures, projections et intervalles.DocumentDB PartitionKey et la performance

Quand il s'agit de choisir un PartitionKey pour une utilisation dans Azure DocumentDB, je vois des gens qui conseille d'utiliser un séparateur logique tel que TenantID, DeviceId, etc.

Compte tenu de la nature parallèle de DocumentDB, cependant, j'étais curieux comment il traiterait un PartitionKey basé sur une sorte de GUID ou de grand entier de sorte que, lors de lectures importantes, il serait hautement parellélisé.

Dans cet esprit, je mis au point un test avec deux collections:

  1. test-col-1
    • PartitionKey est-TenantID avec environ 100 valeurs possibles
  2. test-col-2
    • PartitionKey est une valeur unique attribuée par un tiers qui suit le modèle "AB1234568". Garanti d'être globalement unique par le tiers.

Les deux collections sont mis à 100 000 Ferroviaires.

Dans mon expérience, j'ai chargé les deux collections avec environ 2 000 documents. Chaque document a une taille d'environ 20 Ko et est fortement dénormalisé. Chaque document est un ordre, qui contient plusieurs emplois, qui contiennent chacun des utilisateurs, les prix, etc.

Exemple requête:

SELECT 
orders.Attributes.OrderNumber, 
orders.Attributes.OpenedStamp, 
jobs.SubOrderNumber, 
jobs.LaborTotal.Amount As LaborTotal, 
jobs.LaborActualHours As LaborHours, 
jobs.PartsTotal.Amount As PartsTotal, 
jobs.JobNumber, 
jobs.Tech.Number As TechNumber, 
orders.Attributes.OrderPerson.Number As OrderPersonNumber, 
jobs.Status 
FROM orders 
JOIN jobs IN orders.Attributes.Jobs 
JOIN tech IN jobs.Techs 
WHERE orders.TenantId = @TentantId 
    AND orders.Attributes.Type = 1 
    AND orders.Attributes.Status IN (4, 5)"; 

Dans mes tests j'ai ajusté les paramètres suivants:

  1. Par défaut ConnectionPolicy
  2. Best practices ConnectionPolicy
    • ConnectionMode.Direct, Protocol.Tcp
  3. Divers MaxDegreeOfParallelism valeurs
  4. Divers MaxBufferedItemCount

La collection avec le GUID PartitionKey a été interrogé avec EnableCrossPartitionQuery = true. J'utilise C# et le .NET SDK v1.14.0.

Dans mes premiers tests avec les paramètres par défaut, je trouve que la collection avec interroge TentantId comme PartitionKey était plus rapide, avec elle en prenant en moyenne 3765 ms par rapport à 4680 ms sur la collecte GUID-clé.

Quand je mets le ConnectionPolicy-Direct avec TCP, j'ai découvert TenantID fois la requête de collecte a diminué de près de 1000 ms à une moyenne de 2865 ms tandis que la collecte GUID a augmenté d'environ 800 ms à une moyenne de 5492 ms .

Les choses ont commencé à devenir intéressantes quand j'ai commencé à jouer avec MaxDegreeOfParellelism et MaxBufferedItemCount. Les temps de requête de collecte TentantID n'étaient généralement pas affectés car la requête n'était pas croisée, mais la collecte de GUID accélérait considérablement, atteignant des valeurs aussi rapides que 450 ms (MaxDegreeOfParellelism = 2000, MaxBufferedItemCount = 2000).


Compte tenu de ces observations, pourquoi voudriez-vous pas faire la PartitionKey aussi large que possible une valeur?

Répondre

2

Les choses ont commencé à devenir intéressantes quand j'ai commencé à jouer avec MaxDegreeOfParellelism et MaxBufferedItemCount. Les temps de requête de la collection TentantID n'étaient généralement pas affectés car la requête n'était pas une collection croisée, mais la collecte de GUID accélérait considérablement, atteignant des valeurs aussi rapides que 450 ms (MaxDegreeOfParellelism = 2000, MaxBufferedItemCount = 2000).

MaxDegreeOfParallelism peut définir le nombre maximal de tâches simultanées activées par l'instance ParallelOptions. Comme je le sais, il s'agit d'un parallélisme côté client et il en coûterait vos ressources CPU/mémoire que vous avez sur votre site. Étant donné ces observations, pourquoi ne voudriez-vous pas donner à PartitionKey une valeur aussi large que possible? Pour les opérations d'écriture, nous pourrions mettre à l'échelle les clés de partition, afin d'utiliser l'ensemble de ce que vous avez provisionné. Alors que pour les opérations de lecture, nous devons minimiser les recherches entre partitions pour une latence plus faible.

En outre, comme ce document officiel mentionné:

Le choix de la clé de partition est une décision importante que vous devez faire au moment de la conception. Vous devez choisir un nom de propriété ayant une large plage de valeurs et des modèles d'accès pairs.

Il est recommandé d'avoir une clé de partition avec de nombreuses valeurs distinctes (100s-1000s au minimum).

Pour atteindre le débit total du conteneur, vous devez choisir une clé de partition qui vous permet de répartir équitablement les demandes entre certaines valeurs de clé de partition distinctes.

Pour plus de détails, vous pourriez se référer à How to partition and scale in Azure Cosmos DB et ce canal 9 tutoriel sur Azure DocumentDB Elastic Scale - Partitioning.