Guide de conception de table de stockage Table Azure : tables scalables et performantesAzure Table storage table design guide: Scalable and performant tables

S’APPLIQUE À : API Table

Sugerencia

Dans cet article, le contenu s’applique au stockage de Table Azure d’origine.The content in this article applies to the original Azure Table storage. Cependant, il existe désormais une autre offre pour le stockage de tables : l’API Table Azure Cosmos DB.However, there is now an alternative offering for table storage: the Azure Cosmos DB Table API. Cette API offre des performances plus élevées et une plus grande disponibilité, une distribution mondiale et des index secondaires automatiques.This API offers higher performance and availability, global distribution, and automatic secondary indexes. Elle est également disponible en mode serverless basé sur la consommation.It is also available in a consumption-based serverless mode. Il existe des différences de fonctionnalités entre l’API Table d’Azure Cosmos DB et celle du Stockage Table Azure.There are some feature differences between Table API in Azure Cosmos DB and Azure table storage. Pour plus d’informations, consultez API Table Azure Cosmos DB.For more information, see Azure Cosmos DB Table API.

Pour concevoir des tables scalables et performantes, vous devez prendre en compte divers facteurs, dont le coût.To design scalable and performant tables, you must consider a variety of factors, including cost. Si vous avez déjà conçu des schémas pour des bases de données relationnelles, ces considérations vous seront familières.If you've previously designed schemas for relational databases, these considerations will be familiar to you. Toutefois, bien qu’il existe des similarités entre le stockage Table Azure et les modèles relationnels, il existe également de nombreuses différences importantes.But while there are some similarities between Azure Table storage and relational models, there are also many important differences. Ces différences conduisent généralement à des conceptions différentes qui peuvent sembler absurdes ou incorrectes à une personne ayant une bonne connaissance des bases de données relationnelles, mais qui sont logiques pour une personne menant une conception pour un magasin de paires clé/valeur NoSQL comme celui du stockage Table.These differences typically lead to different designs that might look counter-intuitive or wrong to someone familiar with relational databases, but that do make sense if you're designing for a NoSQL key/value store, such as Table storage.

Le stockage Table est conçu pour prendre en charge des applications à l’échelle du cloud qui peuvent contenir des milliards d’entités (« lignes » dans la terminologie de base de données relationnelle) de données, ou pour des jeux de données devant prendre en charge des volumes de transactions très élevés.Table storage is designed to support cloud-scale applications that can contain billions of entities ("rows" in relational database terminology) of data, or for datasets that must support high transaction volumes. Vous devez donc concevoir différemment la façon dont vous stockez vos données et comprendre comment fonctionne le stockage Table.You therefore need to think differently about how you store your data, and understand how Table storage works. Un magasin de données NoSQL bien conçu améliore la scalabilité de votre solution (pour un coût inférieur) par rapport à une solution qui utilise une base de données relationnelle.A well-designed NoSQL data store can enable your solution to scale much further (and at a lower cost) than a solution that uses a relational database. Ce guide fournit une aide relative à ces sujets.This guide helps you with these topics.

À propos de Stockage Table AzureAbout Azure Table storage

Cette section présente certaines des principales fonctionnalités du stockage Table qui sont particulièrement adaptées aux conceptions orientées vers l’amélioration des performances et de la scalabilité.This section highlights some of the key features of Table storage that are especially relevant to designing for performance and scalability. Si vous ne connaissez pas Stockage Azure et le stockage Table, consultez Présentation du Stockage Microsoft Azure et Bien démarrer avec le stockage Table Azure à l’aide de .NET avant de lire le reste de cet article.If you're new to Azure Storage and Table storage, see Introduction to Microsoft Azure Storage and Get started with Azure Table storage by using .NET before reading the remainder of this article. Bien que ce guide porte sur le stockage Table, il aborde également le stockage File d’attente Azure et le stockage Blob Azure, en expliquant comment les utiliser avec le stockage Table dans une solution.Although the focus of this guide is on Table storage, it does include some discussion of Azure Queue storage and Azure Blob storage, and how you might use them along with Table storage in a solution.

Le stockage Table utilise un format tabulaire pour stocker les données.Table storage uses a tabular format to store data. Selon la terminologie standard, chaque ligne de la table représente une entité et les colonnes stockent les différentes propriétés de cette entité.In the standard terminology, each row of the table represents an entity, and the columns store the various properties of that entity. Chaque entité a une paire de clés qui permet de l’identifier de manière unique et une colonne d’horodatage que le stockage Table utilise pour suivre les dernières mises à jour de l’entité.Every entity has a pair of keys to uniquely identify it, and a timestamp column that Table storage uses to track when the entity was last updated. Le champ d’horodatage est ajouté automatiquement, et vous ne pouvez pas le remplacer manuellement par une valeur arbitraire.The timestamp field is added automatically, and you can't manually overwrite the timestamp with an arbitrary value. Le stockage Table utilise le dernier horodatage modifié (ou LMT, pour Last Modified Timestamp) afin de gérer l’accès concurrentiel optimiste.Table storage uses this last-modified timestamp (LMT) to manage optimistic concurrency.

Nota

Les opérations d’API REST du stockage Table retournent également une valeur ETag dérivée du dernier horodatage modifié (LMT).Table storage REST API operations also return an ETag value that it derives from the LMT. Dans ce document, nous utilisons indifféremment les termes ETag et LMT, car ils font référence aux mêmes données sous-jacentes.In this document, the terms ETag and LMT are used interchangeably, because they refer to the same underlying data.

L'exemple suivant présente la conception d'une table simple pour stocker des entités relatives à des employés (Employee) ainsi qu'à leurs services (Department).The following example shows a simple table design to store employee and department entities. Plusieurs des exemples présentés ultérieurement dans ce guide sont basés sur cette conception simple.Many of the examples shown later in this guide are based on this simple design.

PartitionKeyPartitionKey RowKeyRowKey TimestampTimestamp
MarketingMarketing 0000100001 2014-08-22T00:50:32Z2014-08-22T00:50:32Z
FirstNameFirstName LastNameLastName AgeAge E-mailEmail
DonDon HallHall 3434 donh@contoso.com
MarketingMarketing 0000200002 2014-08-22T00:50:34Z2014-08-22T00:50:34Z
FirstNameFirstName LastNameLastName AgeAge E-mailEmail
JuinJun CaoCao 4747 junc@contoso.com
MarketingMarketing departmentDepartment 2014-08-22T00:50:30Z2014-08-22T00:50:30Z
DepartmentNameDepartmentName EmployeeCountEmployeeCount
MarketingMarketing 153153
VentesSales 0001000010 2014-08-22T00:50:44Z2014-08-22T00:50:44Z
FirstNameFirstName LastNameLastName AgeAge E-mailEmail
KenKen KwokKwok 2323 kenk@contoso.com

Jusqu’à présent, cette conception ressemble à une table dans une base de données relationnelle.So far, this design looks similar to a table in a relational database. Les principales différences sont les colonnes obligatoires et la possibilité de stocker plusieurs types d’entité dans la même table.The key differences are the mandatory columns and the ability to store multiple entity types in the same table. En outre, chacune des propriétés définies par l’utilisateur, telles que FirstName ou Age , est caractérisée par un type de données, par exemple un nombre entier ou une chaîne, tout comme une colonne dans une base de données relationnelle.In addition, each of the user-defined properties, such as FirstName or Age , has a data type, such as integer or string, just like a column in a relational database. Toutefois, contrairement à une base de données relationnelle, la nature sans schéma du stockage Table signifie qu’une propriété n’a pas nécessairement besoin d’avoir les mêmes types de données pour chaque entité.Unlike in a relational database, however, the schema-less nature of Table storage means that a property need not have the same data type on each entity. Pour stocker des types de données complexes dans une seule propriété, vous devez utiliser un format sérialisé comme JSON ou XML.To store complex data types in a single property, you must use a serialized format such as JSON or XML. Pour plus d’informations, consultez Présentation du modèle de données du stockage Table.For more information, see Understanding Table storage data model.

Le choix de la valeur de PartitionKey et RowKey est fondamental pour une bonne conception de table.Your choice of PartitionKey and RowKey is fundamental to good table design. Toutes les entités stockées dans une table doivent avoir une combinaison unique de PartitionKey et RowKey.Every entity stored in a table must have a unique combination of PartitionKey and RowKey. Comme avec les clés dans une table de base de données relationnelle, les valeurs de PartitionKey et RowKey sont indexées pour créer un index cluster qui permet d’effectuer des recherches rapides.As with keys in a relational database table, the PartitionKey and RowKey values are indexed to create a clustered index that enables fast look-ups. Toutefois, le stockage Table ne crée pas d’index secondaires. Il s’agit donc des deux seules propriétés indexées (certains des modèles décrits plus loin montrent comment contourner cette limitation apparente).Table storage, however, doesn't create any secondary indexes, so these are the only two indexed properties (some of the patterns described later show how you can work around this apparent limitation).

Une table est constituée d’une ou plusieurs partitions, et la plupart des décisions de conception que vous prenez consistent à choisir une valeur de PartitionKey et RowKey convenable pour optimiser votre solution.A table is made up of one or more partitions, and many of the design decisions you make will be around choosing a suitable PartitionKey and RowKey to optimize your solution. Une solution peut être constituée d’une seule table contenant toutes vos entités organisées en partitions, mais généralement, une solution a plusieurs tables.A solution can consist of just a single table that contains all your entities organized into partitions, but typically a solution has multiple tables. Les tables vous aident à organiser logiquement vos entités et à gérer l’accès aux données à l’aide de listes de contrôle d’accès.Tables help you to logically organize your entities, and help you manage access to the data by using access control lists. Vous pouvez supprimer une table entière en une seule opération de stockage.You can drop an entire table by using a single storage operation.

Partitions de tableTable partitions

Le nom du compte, le nom de la table et la valeur de PartitionKey identifient la partition dans le service de stockage où le stockage Table stocke l’entité.The account name, table name, and PartitionKey together identify the partition within the storage service where Table storage stores the entity. Tout en appartenant au schéma d’adressage des entités, les partitions définissent une étendue pour les transactions (voir la section Transactions de groupe d’entités plus loin dans cet article) et constituent la base de la méthode de mise à l’échelle du stockage Table.As well as being part of the addressing scheme for entities, partitions define a scope for transactions (see the section later in this article, Entity group transactions), and form the basis of how Table storage scales. Pour plus d’informations sur les partitions, consultez Check-list des performances et de la scalabilité pour le stockage Table.For more information on table partitions, see Performance and scalability checklist for Table storage.

Dans le stockage Table, un nœud individuel traite une ou plusieurs partitions complètes, et le service se met à l’échelle en équilibrant la charge des partitions de manière dynamique parmi les nœuds.In Table storage, an individual node services one or more complete partitions, and the service scales by dynamically load-balancing partitions across nodes. Si un nœud est en cours de chargement, le stockage Table peut fractionner la plage de partitions servie par ce nœud sur des nœuds différents.If a node is under load, Table storage can split the range of partitions serviced by that node onto different nodes. Quand le trafic diminue, le stockage Table peut refusionner les plages de partitions des nœuds calmes sur un nœud unique.When traffic subsides, Table storage can merge the partition ranges from quiet nodes back onto a single node.

Pour plus d’informations sur les détails internes du stockage Table, et notamment la façon dont il gère les partitions, consultez Stockage Microsoft Azure : service de stockage cloud hautement disponible à cohérence forte.For more information about the internal details of Table storage, and in particular how it manages partitions, see Microsoft Azure Storage: A highly available cloud storage service with strong consistency.

Transactions de groupe d’entitésEntity group transactions

Dans le stockage Table, les transactions de groupe d’entités (EGT) constituent l’unique mécanisme intégré pour effectuer des mises à jour atomiques entre plusieurs entités.In Table storage, entity group transactions (EGTs) are the only built-in mechanism for performing atomic updates across multiple entities. Les EGT sont également appelées transactions par lots.EGTs are also referred to as batch transactions. Les transactions EGT peuvent uniquement utiliser des entités stockées dans la même partition (partageant la même clé de partition dans une table donnée). Par conséquent, quand vous avez besoin d’un comportement transactionnel atomique entre plusieurs entités, vérifiez que ces entités sont dans la même partition.EGTs can only operate on entities stored in the same partition (sharing the same partition key in a particular table), so anytime you need atomic transactional behavior across multiple entities, ensure that those entities are in the same partition. Ceci justifie souvent la conservation de plusieurs types d’entité dans la même table (et partition) plutôt que l’utilisation de plusieurs tables pour différents types d’entité.This is often a reason for keeping multiple entity types in the same table (and partition), and not using multiple tables for different entity types. Une seule EGT peut traiter jusqu'à 100 entités.A single EGT can operate on at most 100 entities. Si vous envoyez plusieurs EGT simultanées pour traitement, vérifiez bien que ces EGT n’opèrent pas sur des entités communes aux différentes EGT.If you submit multiple concurrent EGTs for processing, it's important to ensure that those EGTs don't operate on entities that are common across EGTs. Sinon, le traitement risque d’être retardé.Otherwise, you risk delaying processing.

Les EGT représentent également un éventuel compromis à prendre en compte dans votre conception.EGTs also introduce a potential trade-off for you to evaluate in your design. L’utilisation de plusieurs partitions augmente la scalabilité de votre application, car Azure a plus d’occasions d’équilibrer la charge des requêtes parmi les nœuds.Using more partitions increases the scalability of your application, because Azure has more opportunities for load-balancing requests across nodes. Toutefois, cela peut limiter la capacité de votre application à effectuer des transactions atomiques et à assurer une cohérence forte pour vos données.But this might limit the ability of your application to perform atomic transactions and maintain strong consistency for your data. Par ailleurs, il s’agit d’objectifs de scalabilité spécifiques au niveau d’une partition qui peuvent limiter le débit de transactions attendu pour un nœud unique.Furthermore, there are specific scalability targets at the level of a partition that might limit the throughput of transactions you can expect for a single node.

Pour plus d’informations sur les objectifs de scalabilité pour les comptes Stockage Azure, consultez Objectifs de scalabilité pour les comptes de stockage standard.For more information about scalability targets for Azure storage accounts, see Scalability targets for standard storage accounts. Pour plus d’informations sur les objectifs de scalabilité pour le stockage Table, consultez Objectifs de scalabilité et de performances pour le stockage Table.For more information about scalability targets for Table storage, see Scalability and performance targets for Table storage. Les sections ultérieures de ce guide présenteront différentes stratégies de conception pour vous aider à gérer les compromis tels que celui-ci et décrivent les meilleures méthodes pour choisir votre clé de partition en fonction des exigences spécifiques de votre application cliente.Later sections of this guide discuss various design strategies that help you manage trade-offs such as this one, and discuss how best to choose your partition key based on the specific requirements of your client application.

Considérations relatives à la capacitéCapacity considerations

Le tableau suivant présente certaines des valeurs de clés à connaître quand vous concevez une solution de stockage Table :The following table includes some of the key values to be aware of when you're designing a Table storage solution:

Capacité totale d'un compte de stockage AzureTotal capacity of an Azure storage account 500 To500 TB
Nombre de tables dans un compte de stockage AzureNumber of tables in an Azure storage account Limité uniquement par la capacité du compte de stockageLimited only by the capacity of the storage account.
Nombre de partitions dans une tableNumber of partitions in a table Limité uniquement par la capacité du compte de stockageLimited only by the capacity of the storage account.
Nombre d'entités dans une partitionNumber of entities in a partition Limité uniquement par la capacité du compte de stockageLimited only by the capacity of the storage account.
Taille d'une entité individuelleSize of an individual entity Jusqu’à 1 Mo, avec un maximum de 255 propriétés (y compris PartitionKey, RowKey et Timestamp)Up to 1 MB, with a maximum of 255 properties (including the PartitionKey, RowKey, and Timestamp).
Taille de la PartitionKeySize of the PartitionKey Chaîne jusqu’à 1 KoA string up to 1 KB in size.
Taille de la RowKeySize of the RowKey Chaîne jusqu’à 1 KoA string up to 1 KB in size.
Taille d’une transaction ETGSize of an entity group transaction Une transaction peut inclure au plus 100 entités, et la charge utile doit être inférieure à 4 Mo.A transaction can include at most 100 entities, and the payload must be less than 4 MB in size. Une transaction EGT ne peut mettre à jour une entité qu'une seule fois.An EGT can only update an entity once.

Pour plus d’informations, consultez Présentation du modèle de données du service de Table.For more information, see Understanding the Table service data model.

Considérations relatives au coûtCost considerations

Le stockage Table est relativement peu coûteux, mais vous devez y inclure les estimations de coût pour l’utilisation des capacités et la quantité de transactions dans le cadre de l’évaluation d’une solution qui utilise le stockage Table.Table storage is relatively inexpensive, but you should include cost estimates for both capacity usage and the quantity of transactions as part of your evaluation of any solution that uses Table storage. Toutefois, dans de nombreux scénarios, le stockage de données dénormalisées ou dupliquées afin d’améliorer les performances ou la scalabilité de votre solution est une approche appropriée.In many scenarios, however, storing denormalized or duplicate data in order to improve the performance or scalability of your solution is a valid approach to take. Pour plus d’informations sur la tarification, consultez la page Tarification Azure Storage.For more information about pricing, see Azure Storage pricing.

Conseils pour la conception de tableGuidelines for table design

Ces listes récapitulent certaines des principales recommandations à prendre en compte lors de la conception de vos tables.These lists summarize some of the key guidelines you should keep in mind when you're designing your tables. Elles sont toutes traitées en détail plus loin dans ce guide.This guide addresses them all in more detail later on. Ces recommandations sont différentes de celles généralement prodiguées pour la conception d’une base de données relationnelle.These guidelines are different from the guidelines you'd typically follow for relational database design.

Conception de votre stockage Table pour une lecture efficace :Designing your Table storage to be read efficient:

  • Pensez votre conception pour l’interrogation dans des applications à lecture intensive.Design for querying in read-heavy applications. Quand vous concevez vos tables, pensez aux requêtes que vous allez exécuter (en particulier celles sensibles à la latence) avant de réfléchir à la méthode de mise à jour de vos entités.When you're designing your tables, think about the queries (especially the latency-sensitive ones) you'll run before you think about how you'll update your entities. Cela permet généralement d’élaborer une solution efficace et performante.This typically results in an efficient and performant solution.
  • Spécifiez à la fois PartitionKey et RowKey dans vos requêtes.Specify both PartitionKey and RowKey in your queries. Les requêtes de pointage telles que celles-ci sont les requêtes de stockage Table les plus efficaces.Point queries such as these are the most efficient Table storage queries.
  • Envisagez de stocker des copies dupliquées des entités.Consider storing duplicate copies of entities. Le stockage Table est bon marché. Vous pourriez donc stocker la même entité plusieurs fois (avec différentes clés) pour rendre les requêtes plus efficaces.Table storage is cheap, so consider storing the same entity multiple times (with different keys), to enable more efficient queries.
  • Envisagez de dénormaliser vos données.Consider denormalizing your data. Le stockage Tables est bon marché. Nous vous recommandons donc d’envisager la dénormalisation de vos données.Table storage is cheap, so consider denormalizing your data. Par exemple, stockez des entités de résumé pour que les requêtes d’agrégation de données aient seulement besoin d’accéder à une entité unique.For example, store summary entities so that queries for aggregate data only need to access a single entity.
  • Utilisez des valeurs de clé composées.Use compound key values. Les seules clés que vous avez sont PartitionKey et RowKey.The only keys you have are PartitionKey and RowKey. Par exemple, utilisez des valeurs de clé composées pour activer les chemins d’accès de clé de substitution pour les entités.For example, use compound key values to enable alternate keyed access paths to entities.
  • Utilisez la projection de requête.Use query projection. Vous pouvez réduire la quantité de données que vous transférez sur le réseau en utilisant des requêtes qui sélectionnent uniquement les champs dont vous avez besoin.You can reduce the amount of data that you transfer over the network by using queries that select just the fields you need.

Conception de votre stockage Table pour une écriture efficace :Designing your Table storage to be write efficient:

  • Ne créez pas de partitions à chaud.Don't create hot partitions. Choisissez des clés qui vous permettent de répartir vos requêtes sur plusieurs partitions à tout moment.Choose keys that enable you to spread your requests across multiple partitions at any point of time.
  • Évitez les pics de trafic.Avoid spikes in traffic. Distribuez le trafic sur une période de temps raisonnable et évitez les pics de trafic.Distribute the traffic over a reasonable period of time, and avoid spikes in traffic.
  • Ne créez pas nécessairement une table distincte pour chaque type d’entité.Don't necessarily create a separate table for each type of entity. Lorsque vous avez besoin d’utiliser des transactions atomiques sur des types d’entité, vous pouvez stocker ces types d’entité multiples dans la même partition de la même table.When you require atomic transactions across entity types, you can store these multiple entity types in the same partition in the same table.
  • Prévoyez le débit maximal nécessaire.Consider the maximum throughput you must achieve. Vous devez connaître les objectifs de scalabilité du stockage Table, et vous assurer que votre conception n’entraînera pas de dépassement.You must be aware of the scalability targets for Table storage, and ensure that your design won't cause you to exceed them.

Plus loin dans ce guide, vous rencontrerez des exemples mettant tous ces principes en pratique.Later in this guide, you'll see examples that put all of these principles into practice.

Conception pour l'interrogationDesign for querying

Le stockage Table peut lire ou écrire de façon intensive, ou effectuer une combinaison des deux.Table storage can be read intensive, write intensive, or a mix of the two. Cette section traite de la conception pour prendre en charge efficacement les opérations de lecture.This section considers designing to support read operations efficiently. En règle générale, une conception qui prend en charge les opérations de lecture de manière efficace le sera également pour des opérations d'écriture.Typically, a design that supports read operations efficiently is also efficient for write operations. Toutefois, il existe d’autres éléments à prendre en compte lors de la conception pour prendre en charge les opérations d’écriture.However, there are additional considerations when designing to support write operations. Celles-ci sont présentées dans la section suivante, Conception pour la modification de données.These are discussed in the next section, Design for data modification.

Un bon point de départ afin de vous permettre de lire les données efficacement consiste à vous demander quelles requêtes votre application devra exécuter pour extraire les données dont elle aura besoin.A good starting point to enable you to read data efficiently is to ask "What queries will my application need to run to retrieve the data it needs?"

Nota

Avec le stockage Table, il est important de mettre en place une conception efficace dès le début, car il est difficile et coûteux de la modifier ultérieurement.With Table storage, it's important to get the design correct up front, because it's difficult and expensive to change it later. Par exemple, dans une base de données relationnelle, il est souvent possible de résoudre les problèmes de performances simplement en ajoutant des index à une base de données existante.For example, in a relational database, it's often possible to address performance issues simply by adding indexes to an existing database. Cela n’est pas possible avec le stockage Table.This isn't an option with Table storage.

Comment votre choix de PartitionKey et RowKey affecte les performances des requêtesHow your choice of PartitionKey and RowKey affects query performance

Les exemples suivants partent du principe que le stockage Table stocke les entités relatives aux employés (employee) en utilisant la structure suivante (la plupart des exemples omettent la propriété Timestamp par souci de clarté) :The following examples assume Table storage is storing employee entities with the following structure (most of the examples omit the Timestamp property for clarity):

Nom de la colonneColumn name Type de donnéesData type
PartitionKey (nom du service)PartitionKey (Department name) StringString
RowKey (ID d’employé)RowKey (Employee ID) StringString
FirstName StringString
LastName StringString
Age IntegerInteger
EmailAddress StringString

Voici quelques recommandations générales pour la conception de requêtes de stockage Table.Here are some general guidelines for designing Table storage queries. La syntaxe de filtre utilisée dans les exemples suivants provient de l’API REST de stockage Table.The filter syntax used in the following examples is from the Table storage REST API. Pour plus d’informations, consultez Entités de requêtes.For more information, see Query entities.

  • Une requête de pointage constitue la méthode de recherche la plus efficace. Elle est recommandée pour les recherches sur de gros volumes ou des recherches nécessitant la latence la plus faible.A point query is the most efficient lookup to use, and is recommended for high-volume lookups or lookups requiring the lowest latency. Une telle requête peut utiliser les index pour localiser une entité individuelle efficacement en spécifiant les valeurs de PartitionKey et RowKey.Such a query can use the indexes to locate an individual entity efficiently by specifying both the PartitionKey and RowKey values. Par exemple : $filter=(PartitionKey eq 'Sales') and (RowKey eq '2').For example: $filter=(PartitionKey eq 'Sales') and (RowKey eq '2').
  • La deuxième solution consiste à utiliser une requête de plage de données.Second best is a range query. Elle utilise la PartitionKey et filtre sur une plage de valeurs RowKey pour retourner plusieurs entités.It uses the PartitionKey, and filters on a range of RowKey values to return more than one entity. La valeur de PartitionKey identifie une partition spécifique, tandis que la valeur de RowKey identifie un sous-ensemble des entités de cette partition.The PartitionKey value identifies a specific partition, and the RowKey values identify a subset of the entities in that partition. Par exemple : $filter=PartitionKey eq 'Sales' and RowKey ge 'S' and RowKey lt 'T'.For example: $filter=PartitionKey eq 'Sales' and RowKey ge 'S' and RowKey lt 'T'.
  • La troisième solution consiste à effectuer une analyse de partition.Third best is a partition scan. Elle utilise la PartitionKey et filtre sur une autre propriété non-clé, et peut retourner plusieurs entités.It uses the PartitionKey, and filters on another non-key property and might return more than one entity. La valeur de PartitionKey identifie une partition spécifique, et les valeurs des propriétés sélectionnent un sous-ensemble d’entités dans cette partition.The PartitionKey value identifies a specific partition, and the property values select for a subset of the entities in that partition. Par exemple : $filter=PartitionKey eq 'Sales' and LastName eq 'Smith'.For example: $filter=PartitionKey eq 'Sales' and LastName eq 'Smith'.
  • Une analyse de table n’inclut pas la valeur de PartitionKey, et s’avère inefficace car elle lance une recherche sur toutes les partitions qui composent la table pour toutes les entités correspondantes.A table scan doesn't include the PartitionKey, and is inefficient because it searches all of the partitions that make up your table for any matching entities. Elle effectue une analyse de table, que votre filtre utilise la valeur de RowKey ou non.It performs a table scan regardless of whether or not your filter uses the RowKey. Par exemple : $filter=LastName eq 'Jones'.For example: $filter=LastName eq 'Jones'.
  • Les requêtes de stockage Table Azure qui retournent plusieurs entités les trient par ordre de PartitionKey et RowKey.Azure Table storage queries that return multiple entities sort them in PartitionKey and RowKey order. Pour éviter un nouveau tri des entités dans le client, sélectionnez une valeur de RowKey qui définit l’ordre de tri le plus répandu.To avoid resorting the entities in the client, choose a RowKey that defines the most common sort order. Les résultats de la requête renvoyés par l’API Table Azure dans Azure Cosmos DB ne sont pas triés par clé de partition ou clé de ligne.Query results returned by the Azure Table API in Azure Cosmos DB aren't sorted by partition key or row key. Pour obtenir la liste détaillée des différences de fonctionnalités, consultez Différences entre l'API Table dans Azure Cosmos DB et Stockage Table Azure.For a detailed list of feature differences, see differences between Table API in Azure Cosmos DB and Azure Table storage.

L’utilisation d’un connecteur «  or  » pour spécifier un filtre selon les valeurs de RowKey déclenche une analyse de partition, et n’est pas traitée en tant que requête de plage de données.Using an " or " to specify a filter based on RowKey values results in a partition scan, and isn't treated as a range query. Par conséquent, évitez les requêtes qui utilisent des filtres tels que : $filter=PartitionKey eq 'Sales' and (RowKey eq '121' or RowKey eq '322').Therefore, avoid queries that use filters such as: $filter=PartitionKey eq 'Sales' and (RowKey eq '121' or RowKey eq '322').

Pour obtenir des exemples de code côté client qui utilisent la bibliothèque de client de stockage pour exécuter des requêtes efficaces, consultez :For examples of client-side code that use the Storage Client Library to run efficient queries, see:

Pour obtenir des exemples de code côté client pouvant gérer plusieurs types d'entité stockés dans la même table, consultez la page :For examples of client-side code that can handle multiple entity types stored in the same table, see:

Choisir une PartitionKey appropriéeChoose an appropriate PartitionKey

Votre choix de PartitionKey peut équilibrer le besoin d’utiliser des transactions EGT (pour garantir la cohérence) avec l’exigence de distribution de vos entités sur plusieurs partitions (pour assurer une solution scalable).Your choice of PartitionKey should balance the need to enable the use of EGTs (to ensure consistency) against the requirement to distribute your entities across multiple partitions (to ensure a scalable solution).

À une extrémité, vous pouvez stocker toutes vos entités dans une partition unique.At one extreme, you can store all your entities in a single partition. Mais cela peut limiter la scalabilité de votre solution et empêcher le stockage Table de pouvoir équilibrer la charge des requêtes.But this might limit the scalability of your solution, and would prevent Table storage from being able to load-balance requests. À l’autre extrémité, vous pouvez stocker une entité par partition.At the other extreme, you can store one entity per partition. Cette solution est hautement scalable et permet au stockage Table d’équilibrer la charge des requêtes, mais vous empêche d’utiliser des transactions EGT.This is highly scalable and enables Table storage to load-balance requests, but prevents you from using entity group transactions.

Une PartitionKey idéale vous permet d’utiliser des requêtes efficaces, et a des partitions suffisantes pour garantir la scalabilité de votre solution.An ideal PartitionKey enables you to use efficient queries, and has sufficient partitions to ensure your solution is scalable. En règle générale, vous vous rendrez compte que vos entités ont une propriété appropriée qui les distribue sur des partitions suffisantes.Typically, you'll find that your entities will have a suitable property that distributes your entities across sufficient partitions.

Nota

Par exemple, dans un système qui stocke des informations sur des utilisateurs ou des employés, UserID peut être une bonne PartitionKey.For example, in a system that stores information about users or employees, UserID can be a good PartitionKey. Vous pouvez avoir plusieurs entités qui utilisent un UserID spécifique comme clé de partition.You might have several entities that use a particular UserID as the partition key. Chaque entité qui stocke des données relatives à un utilisateur est regroupée dans une partition unique.Each entity that stores data about a user is grouped into a single partition. Ces entités sont accessibles par le biais d’EGT, tout en restant hautement scalables.These entities are accessible via EGTs, while still being highly scalable.

Au moment de choisir la valeur de PartitionKey, vous devez vous demander comment vous allez insérer, mettre à jour et supprimer des entités.There are additional considerations in your choice of PartitionKey that relate to how you insert, update, and delete entities. Pour plus d’informations, consultez Conception pour la modification de données plus loin dans cet article.For more information, see Design for data modification later in this article.

Optimiser les requêtes pour le stockage TableOptimize queries for Table storage

Le stockage Table indexe automatiquement vos entités en utilisant les valeurs PartitionKey et RowKey dans un index cluster unique.Table storage automatically indexes your entities by using the PartitionKey and RowKey values in a single clustered index. C’est la raison pour laquelle les requêtes de pointage sont les plus efficaces.This is the reason that point queries are the most efficient to use. Toutefois, il n’existe aucun autre index que celui de l’index en cluster sur la PartitionKey et la RowKey.However, there are no indexes other than that on the clustered index on the PartitionKey and RowKey.

De nombreuses conceptions doivent répondre aux conditions requises pour permettre la recherche d'entités basée sur plusieurs critères.Many designs must meet requirements to enable lookup of entities based on multiple criteria. Par exemple, la localisation des entités relatives aux employés (employee) en fonction de leurs adresses e-mail, de leur ID employé ou de leur nom.For example, locating employee entities based on email, employee ID, or last name. Les modèles suivants de la section Modèles de conception de table permettent de gérer ces types d’exigences.The following patterns in the section Table design patterns address these types of requirements. Les modèles décrivent également comment contourner le fait que le stockage Table ne fournit pas d’index secondaires.The patterns also describe ways of working around the fact that Table storage doesn't provide secondary indexes.

  • Modèle d’index secondaire intra-partition : stocker plusieurs copies de chaque entité en utilisant différentes valeurs de RowKey (dans la même partition).Intra-partition secondary index pattern: Store multiple copies of each entity by using different RowKey values (in the same partition). Cela permet d’effectuer des recherches rapides et efficaces, ainsi que d’autres ordres de tri à l’aide de différentes valeurs de RowKey.This enables fast and efficient lookups, and alternate sort orders by using different RowKey values.
  • Modèle d’index secondaire entre les partitions : stocker plusieurs copies de chaque entité en utilisant différentes valeurs de RowKey dans des partitions ou des tables distinctes.Inter-partition secondary index pattern: Store multiple copies of each entity by using different RowKey values in separate partitions or in separate tables. Cela permet d’effectuer des recherches rapides et efficaces, ainsi que d’autres ordres de tri à l’aide de différentes valeurs de RowKey.This enables fast and efficient lookups, and alternate sort orders by using different RowKey values.
  • Modèle d’entités d’index : Permet de mettre à jour des entités d'index pour mener des recherches efficaces renvoyant des listes d'entités.Index entities pattern: Maintain index entities to enable efficient searches that return lists of entities.

Trier des données dans le stockage TableSort data in Table storage

Le stockage Table retourne les résultats de requête triés par ordre croissant, en fonction de PartitionKey puis de RowKey.Table storage returns query results sorted in ascending order, based on PartitionKey and then by RowKey.

Nota

Les résultats de la requête renvoyés par l’API Table Azure dans Azure Cosmos DB ne sont pas triés par clé de partition ou clé de ligne.Query results returned by the Azure Table API in Azure Cosmos DB aren't sorted by partition key or row key. Pour obtenir la liste détaillée des différences de fonctionnalités, consultez Différences entre l'API Table dans Azure Cosmos DB et Stockage Table Azure.For a detailed list of feature differences, see differences between Table API in Azure Cosmos DB and Azure Table storage.

Les clés dans le stockage Table sont des valeurs de chaîne.Keys in Table storage are string values. Pour être sûr que les valeurs numériques sont triées correctement, vous devez les convertir en une longueur fixe et les remplir avec des zéros.To ensure that numeric values sort correctly, you should convert them to a fixed length, and pad them with zeroes. Par exemple, si la valeur d’ID d’un employé que vous utilisez comme RowKey est une valeur de nombre entier, vous devez convertir l’ID de cet employé, 123 , en 00000123.For example, if the employee ID value you use as the RowKey is an integer value, you should convert employee ID 123 to 00000123.

De nombreuses applications ont des conditions d'utilisation pour l'utilisation des données triées dans différents ordres : par exemple, le tri des employés par nom ou par date d'arrivée.Many applications have requirements to use data sorted in different orders: for example, sorting employees by name, or by joining date. Les modèles suivants de la section Modèles de conception de table permettent de comprendre comment alterner les ordres de tri pour vos entités :The following patterns in the section Table design patterns address how to alternate sort orders for your entities:

  • Modèle d’index secondaire intra-partition : stocker plusieurs copies de chaque entité en utilisant différentes valeurs de RowKey (dans la même partition).Intra-partition secondary index pattern: Store multiple copies of each entity by using different RowKey values (in the same partition). Cela permet d’effectuer des recherches rapides et efficaces, ainsi que d’autres ordres de tri à l’aide de différentes valeurs de RowKey.This enables fast and efficient lookups, and alternate sort orders by using different RowKey values.
  • Modèle d’index secondaire entre les partitions : stocker plusieurs copies de chaque entité en utilisant différentes valeurs de RowKey dans des partitions ou des tables distinctes.Inter-partition secondary index pattern: Store multiple copies of each entity by using different RowKey values in separate partitions in separate tables. Cela permet d’effectuer des recherches rapides et efficaces, ainsi que d’autres ordres de tri à l’aide de différentes valeurs de RowKey.This enables fast and efficient lookups, and alternate sort orders by using different RowKey values.
  • Modèle de fin de journal : récupérer les n entités récemment ajoutées à une partition en utilisant une valeur de RowKey qui effectue un tri dans l’ordre inverse de la date et de l’heure.Log tail pattern: Retrieve the n entities most recently added to a partition, by using a RowKey value that sorts in reverse date and time order.

Conception pour la modification de donnéesDesign for data modification

Cette section se concentre sur les considérations de conception pour optimiser les insertions, les mises à jour et les suppressions.This section focuses on the design considerations for optimizing inserts, updates, and deletes. Dans certains cas, vous devrez évaluer le compromis entre les conceptions qui optimisent les requêtes et celles qui optimisent la modification des données.In some cases, you'll need to evaluate the trade-off between designs that optimize for querying against designs that optimize for data modification. Cette évaluation est similaire à ce que vous faites dans les conceptions des bases de données relationnelles (bien que les techniques de gestion des compromis de conception soient différentes dans une base de données relationnelle).This evaluation is similar to what you do in designs for relational databases (although the techniques for managing the design trade-offs are different in a relational database). La section Modèles de conception de table décrit plusieurs modèles de conception détaillés pour le stockage Table, et apporte des informations sur certains de ces compromis.The section Table design patterns describes some detailed design patterns for Table storage, and highlights some of these trade-offs. En pratique, vous constaterez que les nombreuses conceptions optimisées pour l’interrogation des entités fonctionnent aussi bien pour la modification des entités.In practice, you'll find that many designs optimized for querying entities also work well for modifying entities.

Optimiser les performances des opérations d'insertion, de mise à jour et de suppressionOptimize the performance of insert, update, and delete operations

Pour mettre à jour ou supprimer une entité, vous devez être en mesure de l’identifier à l’aide des valeurs de PartitionKey et RowKey.To update or delete an entity, you must be able to identify it by using the PartitionKey and RowKey values. À cet égard, votre choix de PartitionKey et RowKey pour la modification des entités doit suivre des critères similaires à ceux de votre choix concernant la prise en charge des requêtes de pointage.In this respect, your choice of PartitionKey and RowKey for modifying entities should follow similar criteria to your choice to support point queries. Il faut identifier les entités le plus efficacement possible.You want to identify entities as efficiently as possible. Il vaut mieux ne pas utiliser d’analyse de table ou de partition inefficace pour localiser une entité afin de découvrir les valeurs de PartitionKey et RowKey que vous devez mettre à jour ou supprimer.You don't want to use an inefficient partition or table scan to locate an entity in order to discover the PartitionKey and RowKey values you need to update or delete it.

Les modèles suivants de la section Modèles de conception de table permettent d’optimiser les performances de vos opérations d’insertion, de mise à jour et de suppression :The following patterns in the section Table design patterns address optimizing the performance of your insert, update, and delete operations:

  • Modèle de suppression de volume élevé : activer la suppression d’un volume élevé d’entités en stockant toutes les entités pour les supprimer simultanément dans leur propre table distincte.High volume delete pattern: Enable the deletion of a high volume of entities by storing all the entities for simultaneous deletion in their own separate table. Vous supprimez les entités en supprimant la table.You delete the entities by deleting the table.
  • Modèle de série de données : Stockez des séries de données complètes dans une entité unique pour réduire votre nombre de demandes.Data series pattern: Store complete data series in a single entity to minimize the number of requests you make.
  • Modèle d’entités larges : Utilisez plusieurs entités physiques pour stocker des entités logiques ayant plus de 252 propriétés.Wide entities pattern: Use multiple physical entities to store logical entities with more than 252 properties.
  • Modèle d’entités volumineuses : Utilisez le stockage d'objets blob pour stocker des valeurs de propriétés volumineuses.Large entities pattern: Use blob storage to store large property values.

Assurer la cohérence de vos entités stockéesEnsure consistency in your stored entities

L'autre facteur déterminant pour votre choix de clés en vue de l'optimisation des modifications de données consiste à assurer la cohérence à l'aide de transactions atomiques.The other key factor that influences your choice of keys for optimizing data modifications is how to ensure consistency by using atomic transactions. Vous pouvez uniquement utiliser une EGT pour mener des opérations sur des entités stockées dans la même partition.You can only use an EGT to operate on entities stored in the same partition.

Les modèles suivants de la section Modèles de conception de table permettent de gérer la cohérence :The following patterns in the section Table design patterns address managing consistency:

  • Modèle d’index secondaire intra-partition : stocker plusieurs copies de chaque entité en utilisant différentes valeurs de RowKey (dans la même partition).Intra-partition secondary index pattern: Store multiple copies of each entity by using different RowKey values (in the same partition). Cela permet d’effectuer des recherches rapides et efficaces, ainsi que d’autres ordres de tri à l’aide de différentes valeurs de RowKey.This enables fast and efficient lookups, and alternate sort orders by using different RowKey values.
  • Modèle d’index secondaire entre les partitions : stocker plusieurs copies de chaque entité en utilisant différentes valeurs de RowKey dans des partitions ou des tables distinctes.Inter-partition secondary index pattern: Store multiple copies of each entity by using different RowKey values in separate partitions or in separate tables. Cela permet d’effectuer des recherches rapides et efficaces, ainsi que d’autres ordres de tri à l’aide de différentes valeurs de RowKey.This enables fast and efficient lookups, and alternate sort orders by using different RowKey values.
  • Modèle de transactions cohérentes : Permet de conserver un comportement cohérent entre les limites de partition ou les limites du système de stockage à l'aide des files d'attente Azure.Eventually consistent transactions pattern: Enable eventually consistent behavior across partition boundaries or storage system boundaries by using Azure queues.
  • Modèle d’entités d’index : Permet de mettre à jour des entités d'index pour mener des recherches efficaces renvoyant des listes d'entités.Index entities pattern: Maintain index entities to enable efficient searches that return lists of entities.
  • Modèle de dénormalisation : combiner des données connexes dans une entité unique pour pouvoir récupérer toutes les données dont vous avez besoin avec une seule requête de pointage.Denormalization pattern: Combine related data together in a single entity, to enable you to retrieve all the data you need with a single point query.
  • Modèle de série de données : stocker des séries de données complètes dans une entité unique pour réduire le nombre de requêtes effectuées.Data series pattern: Store complete data series in a single entity, to minimize the number of requests you make.

Pour plus d’informations, consultez Transactions de groupe d’entités plus loin dans cet article.For more information, see Entity group transactions later in this article.

Faire en sorte que votre conception pour des modifications efficaces facilite les requêtes efficacesEnsure your design for efficient modifications facilitates efficient queries

Dans de nombreux cas, une conception visant à obtenir une interrogation efficace entraîne des modifications efficaces, mais vous devez toujours évaluer si cela est le cas pour votre scénario.In many cases, a design for efficient querying results in efficient modifications, but you should always evaluate whether this is the case for your specific scenario. Certains des modèles de la section Modèles de conception de table évaluent clairement les compromis entre l’interrogation et la modification des entités. Vous devez toujours prendre en compte le nombre de chaque type d’opération.Some of the patterns in the section Table design patterns explicitly evaluate trade-offs between querying and modifying entities, and you should always take into account the number of each type of operation.

Les modèles suivants de la section Modèles de conception de table répondent aux compromis entre la conception en vue d’une interrogation efficace et la conception en vue d’une modification de données efficace :The following patterns in the section Table design patterns address trade-offs between designing for efficient queries and designing for efficient data modification:

  • Modèle de clé composée : utiliser des valeurs de RowKey composées pour permettre à un client de rechercher des données connexes en utilisant une seule requête de pointage.Compound key pattern: Use compound RowKey values to enable a client to look up related data with a single point query.
  • Modèle de fin de journal : récupérer les n entités récemment ajoutées à une partition en utilisant une valeur de RowKey qui effectue un tri dans l’ordre inverse de la date et de l’heure.Log tail pattern: Retrieve the n entities most recently added to a partition, by using a RowKey value that sorts in reverse date and time order.

Chiffrer des données de tableEncrypt table data

La bibliothèque de client .NET Stockage Azure prend en charge le chiffrement des propriétés de l’entité de chaîne pour les opérations d’insertion et de remplacement.The .NET Azure Storage client library supports encryption of string entity properties for insert and replace operations. Les chaînes chiffrées sont stockées sur le service en tant que propriétés binaires, et elles sont converties en chaînes après le déchiffrement.The encrypted strings are stored on the service as binary properties, and they're converted back to strings after decryption.

Pour les tables, outre la stratégie de chiffrement, les utilisateurs doivent spécifier les propriétés à chiffrer.For tables, in addition to the encryption policy, users must specify the properties to be encrypted. Spécifiez un attribut EncryptProperty (pour les entités POCO qui dérivent de TableEntity) ou un programme de résolution de chiffrement dans les options de requête.Either specify an EncryptProperty attribute (for POCO entities that derive from TableEntity), or specify an encryption resolver in request options. Un programme de résolution de chiffrement est un délégué qui prend une clé de partition, une clé de ligne et un nom de propriété, puis retourne une valeur booléenne indiquant si cette propriété doit être chiffrée.An encryption resolver is a delegate that takes a partition key, row key, and property name, and returns a Boolean that indicates whether that property should be encrypted. Au cours du chiffrement, la bibliothèque de client utilise ces informations pour décider si une propriété doit être chiffrée lors de l’écriture en ligne.During encryption, the client library uses this information to decide whether a property should be encrypted while writing to the wire. Le délégué fournit également la possibilité de définir la manière dont les propriétés sont chiffrées l’aide d’un programme logique.The delegate also provides for the possibility of logic around how properties are encrypted. (Par exemple, si X, alors chiffrer la propriété A ; sinon chiffrer les propriétés A et B.) Il n’est pas nécessaire de fournir ces informations pendant la lecture ou l’interrogation des entités.(For example, if X, then encrypt property A; otherwise encrypt properties A and B.) It's not necessary to provide this information while reading or querying entities.

La fusion n’est pas prise en charge actuellement.Merge isn't currently supported. Un sous-ensemble de propriétés ayant pu être chiffré précédemment à l’aide d’une clé différente, la fusion des nouvelles propriétés et la mise à jour des métadonnées entraîneront une perte de données.Because a subset of properties might have been encrypted previously by using a different key, simply merging the new properties and updating the metadata will result in data loss. L’opération de fusion nécessite d’effectuer des appels de service supplémentaires pour lire l’entité pré-existante à partir du service, ou d’utiliser une nouvelle clé par propriété.Merging either requires making extra service calls to read the pre-existing entity from the service, or using a new key per property. Pour des raisons de performances, aucune de ces options n’est adaptée.Neither of these are suitable for performance reasons.

Pour plus d’informations sur le chiffrement des données de table, consultez Chiffrement côté client et coffre de clés Azure pour Microsoft Azure Storage.For information about encrypting table data, see Client-side encryption and Azure Key Vault for Microsoft Azure Storage.

Relations de modèlesModel relationships

La création de modèles de domaine est une étape importante pour concevoir des systèmes complexes.Building domain models is a key step in the design of complex systems. En règle générale, le processus de modélisation permet d’identifier les entités et les relations entre elles, pour mieux comprendre le domaine de l’entreprise et concevoir votre système.Typically, you use the modeling process to identify entities and the relationships between them, as a way to understand the business domain and inform the design of your system. Cette section est axée sur la manière dont vous pouvez traduire certains des types de relations courantes présents dans les modèles du domaine pour les conceptions du stockage Table.This section focuses on how you can translate some of the common relationship types found in domain models to designs for Table storage. Le processus de mappage d’un modèle de données logique vers un modèle de données NoSQL physique est différent de celui utilisé pour la conception d’une base de données relationnelle.The process of mapping from a logical data model to a physical NoSQL-based data model is different from that used when designing a relational database. La conception des bases de données relationnelles suppose généralement un processus de normalisation des données optimisé pour limiter la redondance.Relational databases design typically assumes a data normalization process optimized for minimizing redundancy. Une telle conception suppose également une fonctionnalité d’interrogation déclarative qui fait abstraction de l’implémentation du fonctionnement de la base de données.Such design also assumes a declarative querying capability that abstracts the implementation of how the database works.

Relations un-à-plusieursOne-to-many relationships

Les relations un-à-plusieurs entre des objets de domaine d’entreprise se produisent fréquemment : par exemple, un service a de nombreux employés.One-to-many relationships between business domain objects occur frequently: for example, one department has many employees. Il existe plusieurs méthodes pour implémenter des relations un-à-plusieurs dans le stockage Table. Chacune d’elles a des inconvénients et des avantages qui peuvent être pertinents pour un scénario particulier.There are several ways to implement one-to-many relationships in Table storage, each with pros and cons that might be relevant to the particular scenario.

Prenons l’exemple d’une grande entreprise multinationale avec des dizaines de milliers de services et d’entités d’employés.Consider the example of a large multinational corporation with tens of thousands of departments and employee entities. Chaque service a de nombreux employés, et chaque employé est associé à un service spécifique.Every department has many employees and each employee is associated with one specific department. Une approche consiste à stocker séparément les entités relatives aux services (department) et aux employés (employee), comme ceci :One approach is to store separate department and employee entities, such as the following:

Graphique présentant une entité Department et une entité Employee

Cet exemple montre une relation un-à-plusieurs implicite entre les types, basée sur la valeur de PartitionKey.This example shows an implicit one-to-many relationship between the types, based on the PartitionKey value. Chaque service peut avoir de nombreux employés.Each department can have many employees.

Cet exemple montre également une entité de service (department) et ses entités d'employés (employee) dans la même partition.This example also shows a department entity and its related employee entities in the same partition. Vous pouvez choisir d’utiliser des partitions, des tables ou même des comptes de stockage différents pour les différents types d’entité.You can choose to use different partitions, tables, or even storage accounts for the different entity types.

Une autre approche consiste à dénormaliser vos données et à stocker uniquement les entités d’employés avec les données de services dénormalisées, comme indiqué dans l’exemple suivant.An alternative approach is to denormalize your data, and store only employee entities with denormalized department data, as shown in the following example. Cette approche dénormalisée n’est peut-être pas la meilleure pour ce scénario si vous devez pouvoir modifier les détails d’un responsable de service.In this particular scenario, this denormalized approach might not be the best if you have a requirement to be able to change the details of a department manager. Pour ce faire, il vous faudrait mettre à jour chaque employé du service.To do this, you would need to update every employee in the department.

Graphique de l’entité Employé montrant comment dénormaliser vos données et stocker uniquement les entités d’employés avec les données de services dénormalisées.

Pour plus d’informations, consultez la section Modèle de dénormalisation plus loin dans ce guide.For more information, see the Denormalization pattern later in this guide.

Le tableau suivant récapitule les avantages et les inconvénients de chacune des approches pour le stockage des entités d’employés et de services qui ont une relation un-à-plusieurs.The following table summarizes the pros and cons of each of the approaches for storing employee and department entities that have a one-to-many relationship. Vous devez également prendre en compte la fréquence à laquelle vous prévoyez d’effectuer diverses opérations.You should also consider how often you expect to perform various operations. Il peut être acceptable d’avoir une conception qui comprend une opération coûteuse si cette opération ne se produit que rarement.It might be acceptable to have a design that includes an expensive operation if that operation only happens infrequently.

ApprocheApproach AvantagesPros InconvénientsCons
Séparation des types d'entités, même partition, même tableSeparate entity types, same partition, same table
  • Vous pouvez mettre à jour une entité de service en une seule opération.You can update a department entity with a single operation.
  • Vous pouvez utiliser une EGT pour maintenir la cohérence si vous avez besoin de modifier une entité de service à chaque mise à jour/insertion/suppression d'une entité d'employé.You can use an EGT to maintain consistency if you have a requirement to modify a department entity whenever you update/insert/delete an employee entity. Par exemple, si vous conservez un nombre d’employés de service pour chaque service.For example, if you maintain a departmental employee count for each department.
  • Vous devrez peut-être récupérer à la fois une entité d’employé et de service pour certaines activités du client.You might need to retrieve both an employee and a department entity for some client activities.
  • Les opérations de stockage se produisent dans la même partition.Storage operations happen in the same partition. Si les volumes de transactions sont élevés, cela peut générer une zone sensible.At high transaction volumes, this can result in a hotspot.
  • Vous ne pouvez pas déplacer un employé vers un nouveau service à l’aide d’une EGT.You can't move an employee to a new department by using an EGT.
Types d’entités distincts, différentes partitions ou différentes tables ou différents comptes de stockageSeparate entity types, different partitions, or tables or storage accounts
  • Vous pouvez mettre à jour une entité de service ou une entité d'employé avec une seule opération.You can update a department entity or employee entity with a single operation.
  • Si les volumes de transactions sont élevés, ceci peut permettre de répartir la charge sur plusieurs partitions.At high transaction volumes, this can help spread the load across more partitions.
  • Vous devrez peut-être récupérer à la fois une entité d’employé et de service pour certaines activités du client.You might need to retrieve both an employee and a department entity for some client activities.
  • Vous ne pouvez pas utiliser des EGT pour maintenir la cohérence lors d’une mise à jour/insertion/suppression d’employé et d’une mise à jour de service.You can't use EGTs to maintain consistency when you update/insert/delete an employee and update a department. Par exemple, la mise à jour d'un nombre d'employés dans une entité de service.For example, updating an employee count in a department entity.
  • Vous ne pouvez pas déplacer un employé vers un nouveau service à l’aide d’une EGT.You can't move an employee to a new department by using an EGT.
Dénormaliser en type d'entité uniqueDenormalize into single entity type
  • Vous pouvez récupérer toutes les informations dont vous avez besoin en utilisant une seule demande.You can retrieve all the information you need with a single request.
  • Il peut être coûteux de maintenir la cohérence si vous devez mettre à jour les informations d’un service (cela vous obligerait à mettre à jour tous les employés d’un service).It can be expensive to maintain consistency if you need to update department information (this would require you to update all the employees in a department).

Votre choix parmi ces options, ainsi que la détermination des avantages et des inconvénients les plus significatifs, dépendent de votre scénario d’application.How you choose among these options, and which of the pros and cons are most significant, depends on your specific application scenarios. Par exemple, à quelle fréquence modifiez-vous les entités de service ?For example, how often do you modify department entities? Toutes les requêtes de vos employés ont-elles besoin des informations supplémentaires sur les services ?Do all your employee queries need the additional departmental information? Êtes-vous proche de vos limites de scalabilité sur vos partitions ou votre compte de stockage ?How close are you to the scalability limits on your partitions or your storage account?

Relations un à unOne-to-one relationships

Les modèles de domaines peuvent inclure des relations un-à-un entre les entités.Domain models can include one-to-one relationships between entities. Si vous devez implémenter une relation un-à-un dans le stockage Table, vous devez également choisir comment lier les deux entités associées quand vous avez besoin de récupérer les deux.If you need to implement a one-to-one relationship in Table storage, you must also choose how to link the two related entities when you need to retrieve them both. Ce lien peut être implicite (basé sur une convention dans les valeurs de clé) ou explicite (si l’on stocke un lien sous forme de valeurs de PartitionKey et RowKey dans chaque entité et son entité associée).This link can be either implicit, based on a convention in the key values, or explicit, by storing a link in the form of PartitionKey and RowKey values in each entity to its related entity. Pour savoir quand stocker les entités associées dans la même partition, consultez la section Relations un à plusieurs.For a discussion of whether you should store the related entities in the same partition, see the section One-to-many relationships.

Certaines considérations sur l’implémentation peuvent vous conduire à implémenter des relations un-à-un dans le stockage Table :There are also implementation considerations that might lead you to implement one-to-one relationships in Table storage:

Joindre le clientJoin in the client

Bien qu’il existe des façons de modéliser des relations dans le stockage Table, n’oubliez pas que les deux principaux motifs pour utiliser le stockage Table sont la scalabilité et les performances.Although there are ways to model relationships in Table storage, don't forget that the two prime reasons for using Table storage are scalability and performance. Si vous devez modéliser plusieurs relations pouvant compromettre les performances et la scalabilité de votre solution, demandez-vous s’il est nécessaire de générer toutes les relations de données dans votre conception de table.If you find you are modeling many relationships that compromise the performance and scalability of your solution, you should ask yourself if it's necessary to build all the data relationships into your table design. Vous pouvez peut-être simplifier la conception, et améliorer la scalabilité et les performances de votre solution, si vous laissez votre application cliente effectuer les jointures nécessaires.You might be able to simplify the design, and improve the scalability and performance of your solution, if you let your client application perform any necessary joins.

Par exemple, si vous avez des petites tables qui contiennent des données qui ne changent pas souvent, vous pouvez récupérer ces données une fois et les mettre en cache sur le client.For example, if you have small tables that contain data that doesn't change often, you can retrieve this data once, and cache it on the client. Cela peut éviter des allers-retours répétés pour récupérer les mêmes données.This can avoid repeated roundtrips to retrieve the same data. Dans les exemples que nous avons étudiés dans ce guide, il est probable que l’ensemble des services d’une petite organisation soit peu volumineux et rarement modifié.In the examples we've looked at in this guide, the set of departments in a small organization is likely to be small and change infrequently. Cela en fait un bon candidat pour les données qu’une application cliente peut télécharger une seule fois et mettre en cache en tant que données de recherche.This makes it a good candidate for data that a client application can download once and cache as lookup data.

Relations d'héritageInheritance relationships

Si votre application cliente utilise un ensemble de classes qui font partie d’une relation d’héritage pour représenter des entités métier, vous pouvez facilement conserver ces entités dans le stockage Table.If your client application uses a set of classes that form part of an inheritance relationship to represent business entities, you can easily persist those entities in Table storage. Par exemple, l’ensemble de classes suivant peut être défini dans votre application cliente, Person étant une classe abstraite.For example, you might have the following set of classes defined in your client application, where Person is an abstract class.

Diagramme des relations d’héritage

Vous pouvez rendre persistantes les instances des deux classes concrètes dans le stockage Table en utilisant une seule table Person.You can persist instances of the two concrete classes in Table storage by using a single Person table. Utilisez des entités ressemblant à ce qui suit :Use entities that look like the following:

Graphique montrant l’entité Client et l’entité Employee

Pour plus d’informations sur l’utilisation de plusieurs types d’entité dans la même table dans le code client, consultez Utiliser des types d’entités hétérogènes plus loin dans ce guide.For more information about working with multiple entity types in the same table in client code, see Work with heterogeneous entity types later in this guide. Vous y trouverez des exemples montrant comment reconnaître le type d'entité dans le code client.This provides examples of how to recognize the entity type in client code.

Modèles de conception de tableTable design patterns

Dans les sections précédentes, vous avez découvert comment optimiser votre conception de table pour la récupération des données d’entité à l’aide de requêtes, et pour l’insertion, la mise à jour et la suppression des données d’entité.In previous sections, you learned about how to optimize your table design for both retrieving entity data by using queries, and for inserting, updating, and deleting entity data. Cette section décrit certains modèles appropriés pour une utilisation avec le stockage Table.This section describes some patterns appropriate for use with Table storage. En outre, vous verrez comment traiter certains problèmes et compromis abordés précédemment dans ce guide.In addition, you'll see how you can practically address some of the issues and trade-offs raised previously in this guide. Le diagramme suivant récapitule les relations entre les différents modèles :The following diagram summarizes the relationships among the different patterns:

Diagramme des modèles de conception de tables

Le plan des modèles met en évidence les relations entre les modèles (bleus) et les anti-modèles (orange) qui sont décrits dans ce guide.The pattern map highlights some relationships between patterns (blue) and anti-patterns (orange) that are documented in this guide. Il existe bien sûr bien d'autres modèles qui méritent votre attention.There are of course many other patterns that are worth considering. Par exemple, l’un des principaux scénarios pour un stockage Table consiste à utiliser des modèles d’affichages matérialisés à partir du modèle Répartition de la responsabilité de requête de commande.For example, one of the key scenarios for Table storage is to use the materialized view pattern from the command query responsibility segregation pattern.

Modèle d’index secondaire intra-partitionIntra-partition secondary index pattern

stocker plusieurs copies de chaque entité en utilisant différentes valeurs de RowKey (dans la même partition).Store multiple copies of each entity by using different RowKey values (in the same partition). Cela permet d’effectuer des recherches rapides et efficaces, ainsi que d’autres ordres de tri à l’aide de différentes valeurs de RowKey.This enables fast and efficient lookups, and alternate sort orders by using different RowKey values. La cohérence des mises à jour entre les copies peut être assurée à l’aide d’EGT.Updates between copies can be kept consistent by using EGTs.

Contexte et problèmeContext and problem

Le stockage Table indexe automatiquement les entités en utilisant les valeurs PartitionKey et RowKey.Table storage automatically indexes entities by using the PartitionKey and RowKey values. Ainsi, une application cliente peut récupérer une entité efficacement à l’aide de ces valeurs.This enables a client application to retrieve an entity efficiently by using these values. Par exemple, à l’aide de la structure de table suivante, une application cliente peut utiliser une requête de pointage pour récupérer une entité d’employé individuelle en utilisant le nom de service et l’ID d’employé (valeurs PartitionKey et RowKey).For example, using the following table structure, a client application can use a point query to retrieve an individual employee entity by using the department name and the employee ID (the PartitionKey and RowKey values). Un client peut aussi récupérer des entités triées par ID d’employé au sein de chaque service.A client can also retrieve entities sorted by employee ID within each department.

Graphique de l’entité Employé où une application cliente peut utiliser une requête de pointage pour récupérer une entité d’employé individuelle en utilisant le nom de service et l’ID d’employé (valeurs PartitionKey et RowKey).

Si vous voulez également trouver une entité d’employé en fonction de la valeur d’une autre propriété, comme l’adresse e-mail, vous devez utiliser une analyse de partition moins efficace pour rechercher une correspondance.If you also want to find an employee entity based on the value of another property, such as email address, you must use a less efficient partition scan to find a match. En effet, le stockage Table ne fournit pas d’index secondaires.This is because Table storage doesn't provide secondary indexes. De plus, vous ne pouvez pas demander une liste des employés triés dans un ordre différent de celui de RowKey.In addition, there's no option to request a list of employees sorted in a different order than RowKey order.

SolutionSolution

Pour contourner l’absence d’index secondaires, vous pouvez stocker plusieurs copies de chaque entité, chaque copie utilisant une valeur différente de RowKey.To work around the lack of secondary indexes, you can store multiple copies of each entity, with each copy using a different RowKey value. Si vous stockez une entité avec les structures suivantes, vous pouvez récupérer efficacement des entités d’employés d’après leur adresse e-mail ou leur ID d’employé.If you store an entity with the following structures, you can efficiently retrieve employee entities based on email address or employee ID. Les valeurs de préfixe pour RowKey, empid_ et email_ permettent d’interroger un seul employé, ou une plage d’employés, à l’aide d’une plage d’adresses e-mail ou d’ID d’employés.The prefix values for RowKey, empid_, and email_ enable you to query for a single employee, or a range of employees, by using a range of email addresses or employee IDs.

Graphique montrant une entité Employee avec différentes valeurs RowKey

Les deux critères de filtre suivants (l’un recherchant d’après l’ID d’employé et l’autre d’après l’adresse e-mail) spécifient des requêtes de pointage :The following two filter criteria (one looking up by employee ID, and one looking up by email address) both specify point queries:

  • $filter=(PartitionKey eq ’Sales’) and (RowKey eq ’empid_000223’)$filter=(PartitionKey eq 'Sales') and (RowKey eq 'empid_000223')
  • $filter=(PartitionKey eq 'Sales') and (RowKey eq email_jonesj@contoso.com$filter=(PartitionKey eq 'Sales') and (RowKey eq 'email_jonesj@contoso.com')

Si vous interrogez un ensemble d’entités d’employés, vous pouvez spécifier une plage triée par ID d’employé ou une plage triée par adresse e-mail.If you query for a range of employee entities, you can specify a range sorted in employee ID order, or a range sorted in email address order. Recherchez les entités avec le préfixe approprié dans la RowKey.Query for entities with the appropriate prefix in the RowKey.

  • Pour rechercher tous les employés du service des ventes avec un ID d’employé compris entre 000100 et 000199, utilisez : $filter=(PartitionKey eq 'Sales') and (RowKey ge 'empid_000100') and (RowKey le 'empid_000199')To find all the employees in the Sales department with an employee ID in the range 000100 to 000199, use: $filter=(PartitionKey eq 'Sales') and (RowKey ge 'empid_000100') and (RowKey le 'empid_000199')
  • Pour rechercher tous les employés du service des ventes dont l’adresse e-mail commence par la lettre « a », utilisez : $filter=(PartitionKey eq 'Sales') and (RowKey ge 'email_a') and (RowKey lt 'email_b')To find all the employees in the Sales department with an email address starting with the letter "a", use: $filter=(PartitionKey eq 'Sales') and (RowKey ge 'email_a') and (RowKey lt 'email_b')

La syntaxe de filtre utilisée dans les exemples précédents provient de l’API REST de stockage Table.The filter syntax used in the preceding examples is from the Table storage REST API. Pour plus d’informations, consultez Entités de requêtes.For more information, see Query entities.

Problèmes et considérationsIssues and considerations

Prenez en compte les points suivants lorsque vous choisissez comment implémenter ce modèle :Consider the following points when deciding how to implement this pattern:

  • L’utilisation du stockage Table est relativement bon marché. Le coût réel du stockage des données en double ne doit donc pas être une préoccupation majeure.Table storage is relatively cheap to use, so the cost overhead of storing duplicate data shouldn't be a major concern. Toutefois, vous devez toujours évaluer le coût de la conception en fonction de vos besoins en stockage anticipés, et ajouter uniquement des entités en double pour prendre en charge les requêtes que votre application cliente exécutera.However, you should always evaluate the cost of your design based on your anticipated storage requirements, and only add duplicate entities to support the queries your client application will run.

  • Les entités d’index secondaires étant stockées dans la même partition que les entités d’origine, vérifiez que vous ne dépassez pas les objectifs de scalabilité pour une partition spécifique.Because the secondary index entities are stored in the same partition as the original entities, ensure that you don't exceed the scalability targets for an individual partition.

  • Vous pouvez maintenir la cohérence de vos entités en double en utilisant des EGT pour mettre à jour de façon atomique les deux copies d'une même entité.You can keep your duplicate entities consistent with each other by using EGTs to update the two copies of the entity atomically. Cela implique un stockage de toutes les copies d'une entité dans la même partition.This implies that you should store all copies of an entity in the same partition. Pour plus d’informations, consultez Utiliser des transactions de groupe d’entités.For more information, see Use entity group transactions.

  • La valeur de la RowKey doit être unique pour chaque entité.The value used for the RowKey must be unique for each entity. Nous vous conseillons d'utiliser des valeurs de clé composée.Consider using compound key values.

  • Le remplissage des valeurs numériques dans RowKey (par exemple l’ID d’employé 000223) permet de corriger le tri et le filtrage en fonction des limites inférieure et supérieure.Padding numeric values in the RowKey (for example, the employee ID 000223) enables correct sorting and filtering based on upper and lower bounds.

  • Vous n’avez pas forcément besoin de dupliquer toutes les propriétés de votre entité.You don't necessarily need to duplicate all the properties of your entity. Par exemple, si les requêtes de recherche des entités à l’aide de l’adresse e-mail dans la RowKey n’ont jamais besoin de l’âge de l’employé, ces entités peuvent présenter la structure suivante :For example, if the queries that look up the entities by using the email address in the RowKey never need the employee's age, these entities can have the following structure:

    Graphique de l’entité Employee

  • En général, il est préférable de stocker les données en double et de vous assurer que vous pouvez récupérer toutes les données dont vous avez besoin avec une seule requête, plutôt que d’utiliser une requête pour rechercher une entité et une autre pour rechercher les données requises.Typically, it's better to store duplicate data and ensure that you can retrieve all the data you need with a single query, than to use one query to locate an entity and another to look up the required data.

Quand utiliser ce modèleWhen to use this pattern

Utilisez ce modèle dans les situations suivantes :Use this pattern when:

  • Votre application cliente doit récupérer des entités à l’aide de différentes clés.Your client application needs to retrieve entities by using a variety of different keys.
  • Votre client doit récupérer des entités dans différents ordres de tri.Your client needs to retrieve entities in different sort orders.
  • Vous pouvez identifier chaque entité à l’aide d’une variété de valeurs uniques.You can identify each entity by using a variety of unique values.

Toutefois, veillez à ne pas dépasser les limites de scalabilité de partition quand vous effectuez des recherches d’entité à l’aide des différentes valeurs de RowKey.However, be sure that you don't exceed the partition scalability limits when you're performing entity lookups by using the different RowKey values.

Les modèles et les conseils suivants peuvent aussi présenter un intérêt quand il s’agit d’implémenter ce modèle :The following patterns and guidance might also be relevant when implementing this pattern:

Modèle d’index secondaire entre les partitionsInter-partition secondary index pattern

Stockez plusieurs copies de chaque entité en utilisant différentes valeurs de RowKey dans des partitions ou des tables distinctes.Store multiple copies of each entity by using different RowKey values in separate partitions or in separate tables. Cela permet d’effectuer des recherches rapides et efficaces, ainsi que d’autres ordres de tri à l’aide de différentes valeurs de RowKey.This enables fast and efficient lookups, and alternate sort orders by using different RowKey values.

Contexte et problèmeContext and problem

Le stockage Table indexe automatiquement les entités en utilisant les valeurs PartitionKey et RowKey.Table storage automatically indexes entities by using the PartitionKey and RowKey values. Ainsi, une application cliente peut récupérer une entité efficacement à l’aide de ces valeurs.This enables a client application to retrieve an entity efficiently by using these values. Par exemple, à l’aide de la structure de table suivante, une application cliente peut utiliser une requête de pointage pour récupérer une entité d’employé individuelle en utilisant le nom de service et l’ID d’employé (valeurs PartitionKey et RowKey).For example, using the following table structure, a client application can use a point query to retrieve an individual employee entity by using the department name and the employee ID (the PartitionKey and RowKey values). Un client peut aussi récupérer des entités triées par ID d’employé au sein de chaque service.A client can also retrieve entities sorted by employee ID within each department.

Graphique de la structure de l’entité Employé, qui lorsqu’elle est employée, permet à une application cliente d’utiliser une requête de pointage pour récupérer une entité d’employé individuelle en utilisant le nom de service et l’ID d’employé (valeurs PartitionKey et RowKey). [9]

Si vous voulez également pouvoir trouver une entité d'employé en fonction de la valeur d'une autre propriété, comme l'adresse de messagerie, vous devez utiliser une analyse de partition moins efficace pour rechercher une correspondance.If you also want to be able to find an employee entity based on the value of another property, such as email address, you must use a less efficient partition scan to find a match. En effet, le stockage Table ne fournit pas d’index secondaires.This is because Table storage doesn't provide secondary indexes. De plus, vous ne pouvez pas demander une liste des employés triés dans un ordre différent de celui de RowKey.In addition, there's no option to request a list of employees sorted in a different order than RowKey order.

Vous prévoyez un volume élevé de transactions sur ces entités et vous souhaitez réduire le risque de limitation du débit de votre client par le stockage Table.You're anticipating a high volume of transactions against these entities, and want to minimize the risk of the Table storage rate limiting your client.

SolutionSolution

Pour contourner l’absence d’index secondaires, vous pouvez stocker plusieurs copies de chaque entité, chaque copie utilisant des valeurs différentes de PartitionKey et RowKey.To work around the lack of secondary indexes, you can store multiple copies of each entity, with each copy using different PartitionKey and RowKey values. Si vous stockez une entité avec les structures suivantes, vous pouvez récupérer efficacement des entités d’employés d’après leur adresse e-mail ou leur ID d’employé.If you store an entity with the following structures, you can efficiently retrieve employee entities based on email address or employee ID. Les valeurs de préfixe pour PartitionKey, empid_ et email_ permettent d’identifier l’index à utiliser pour une requête.The prefix values for PartitionKey, empid_, and email_ enable you to identify which index you want to use for a query.

Graphique montrant l’entité Employee avec index primaire et l’entité Employee avec index secondaire

Les deux critères de filtre suivants (l’un recherchant d’après l’ID d’employé et l’autre d’après l’adresse e-mail) spécifient des requêtes de pointage :The following two filter criteria (one looking up by employee ID, and one looking up by email address) both specify point queries:

  • $filter=(PartitionKey eq ’empid_Sales’) and (RowKey eq ’000223’)$filter=(PartitionKey eq 'empid_Sales') and (RowKey eq '000223')
  • $filter=(PartitionKey eq ’email_Sales’) and (RowKey eq jonesj@contoso.com$filter=(PartitionKey eq 'email_Sales') and (RowKey eq 'jonesj@contoso.com')

Si vous interrogez un ensemble d’entités d’employés, vous pouvez spécifier une plage triée par ID d’employé ou une plage triée par adresse e-mail.If you query for a range of employee entities, you can specify a range sorted in employee ID order, or a range sorted in email address order. Recherchez les entités avec le préfixe approprié dans la RowKey.Query for entities with the appropriate prefix in the RowKey.

  • Pour rechercher tous les employés du service des ventes avec un ID d’employé compris entre 000100 et 000199 , utilisez : $filter=(PartitionKey eq 'empid_Sales') and (RowKey ge '000100') and (RowKey le '000199')To find all the employees in the Sales department with an employee ID in the range 000100 to 000199 , sorted in employee ID order, use: $filter=(PartitionKey eq 'empid_Sales') and (RowKey ge '000100') and (RowKey le '000199')
  • Pour rechercher tous les employés du service des ventes ayant une adresse e-mail qui commence par « a », triés par ordre d’adresse e-mail, utilisez : $filter=(PartitionKey eq 'email_Sales') and (RowKey ge 'a') and (RowKey lt 'b')To find all the employees in the Sales department with an email address that starts with "a", sorted in email address order, use: $filter=(PartitionKey eq 'email_Sales') and (RowKey ge 'a') and (RowKey lt 'b')

Notez que la syntaxe de filtre utilisée dans les exemples précédents provient de l’API REST de stockage Table.Note that the filter syntax used in the preceding examples is from the Table storage REST API. Pour plus d’informations, consultez Entités de requêtes.For more information, see Query entities.

Problèmes et considérationsIssues and considerations

Prenez en compte les points suivants lorsque vous choisissez comment implémenter ce modèle :Consider the following points when deciding how to implement this pattern:

  • Vous pouvez conserver la cohérence de vos entités en double en utilisant le modèle de transactions cohérentes pour gérer les entités d’index primaire et secondaire.You can keep your duplicate entities eventually consistent with each other by using the Eventually consistent transactions pattern to maintain the primary and secondary index entities.

  • L’utilisation du stockage Table est relativement bon marché. Le coût réel du stockage des données en double ne doit donc pas être une préoccupation majeure.Table storage is relatively cheap to use, so the cost overhead of storing duplicate data should not be a major concern. Toutefois, évaluez toujours le coût de la conception en fonction de vos besoins en stockage anticipés, et ajoutez uniquement des entités en double pour prendre en charge les requêtes que votre application cliente exécutera.However, always evaluate the cost of your design based on your anticipated storage requirements, and only add duplicate entities to support the queries your client application will run.

  • La valeur de la RowKey doit être unique pour chaque entité.The value used for the RowKey must be unique for each entity. Nous vous conseillons d'utiliser des valeurs de clé composée.Consider using compound key values.

  • Le remplissage des valeurs numériques dans RowKey (par exemple l’ID d’employé 000223) permet de corriger le tri et le filtrage en fonction des limites inférieure et supérieure.Padding numeric values in the RowKey (for example, the employee ID 000223) enables correct sorting and filtering based on upper and lower bounds.

  • Vous n’avez pas forcément besoin de dupliquer toutes les propriétés de votre entité.You don't necessarily need to duplicate all the properties of your entity. Par exemple, si les requêtes de recherche des entités à l’aide de l’adresse e-mail dans la RowKey n’ont jamais besoin de l’âge de l’employé, ces entités peuvent présenter la structure suivante :For example, if the queries that look up the entities by using the email address in the RowKey never need the employee's age, these entities can have the following structure:

    Graphique montrant l’entité Employee avec index secondaire

  • En général, il est préférable de stocker les données en double et de vous assurer que vous pouvez récupérer toutes les données dont vous avez besoin en utilisant une seule requête, plutôt que d’utiliser une requête pour rechercher une entité à l’aide de l’index secondaire et une autre pour rechercher les données requises dans l’index primaire.Typically, it's better to store duplicate data and ensure that you can retrieve all the data you need with a single query, than to use one query to locate an entity by using the secondary index and another to look up the required data in the primary index.

Quand utiliser ce modèleWhen to use this pattern

Utilisez ce modèle dans les situations suivantes :Use this pattern when:

  • Votre application cliente doit récupérer des entités à l’aide de différentes clés.Your client application needs to retrieve entities by using a variety of different keys.
  • Votre client doit récupérer des entités dans différents ordres de tri.Your client needs to retrieve entities in different sort orders.
  • Vous pouvez identifier chaque entité à l’aide d’une variété de valeurs uniques.You can identify each entity by using a variety of unique values.

Utilisez ce modèle si vous voulez éviter le dépassement des limites de scalabilité de partition quand vous effectuez des recherches d’entité à l’aide des différentes valeurs de RowKey.Use this pattern when you want to avoid exceeding the partition scalability limits when you are performing entity lookups by using the different RowKey values.

Les modèles et les conseils suivants peuvent aussi présenter un intérêt quand il s’agit d’implémenter ce modèle :The following patterns and guidance might also be relevant when implementing this pattern:

Modèle de transactions cohérentesEventually consistent transactions pattern

Permet de conserver un comportement cohérent entre les limites de partition ou les limites du système de stockage à l'aide des files d'attente Azure.Enable eventually consistent behavior across partition boundaries or storage system boundaries by using Azure queues.

Contexte et problèmeContext and problem

Les EGT activent les transactions atomiques de plusieurs entités qui partagent la même clé de partition.EGTs enable atomic transactions across multiple entities that share the same partition key. Pour des raisons de scalabilité et de performances, vous pouvez décider de stocker des entités ayant des exigences de cohérence dans des partitions distinctes ou dans un système de stockage distinct.For performance and scalability reasons, you might decide to store entities that have consistency requirements in separate partitions or in a separate storage system. Dans ce scénario, vous ne pouvez pas utiliser les EGT pour maintenir la cohérence.In such a scenario, you can't use EGTs to maintain consistency. Par exemple, vous pouvez avoir besoin de maintenir la cohérence entre :For example, you might have a requirement to maintain eventual consistency between:

  • des entités stockées dans deux partitions différentes de la même table, dans des tables différentes ou dans différents comptes de stockage ;Entities stored in two different partitions in the same table, in different tables, or in different storage accounts.
  • Une entité stockée dans le stockage Table et un objet blob stocké dans le stockage d’objets blob.An entity stored in Table storage and a blob stored in Blob storage.
  • Une entité stockée dans le stockage Table et un fichier dans un système de fichiers.An entity stored in Table storage and a file in a file system.
  • Une entité stockée dans le stockage Table mais indexée à l’aide de Recherche cognitive Azure.An entity stored in Table storage, yet indexed by using Azure Cognitive Search.

SolutionSolution

À l'aide des files d'attente Azure, vous pouvez implémenter une solution cohérente entre plusieurs partitions ou systèmes de stockage.By using Azure queues, you can implement a solution that delivers eventual consistency across two or more partitions or storage systems.

Pour illustrer cette approche, supposez que vous avez besoin d’archiver des entités sur les anciens employés.To illustrate this approach, assume you have a requirement to be able to archive former employee entities. Ces entités sont rarement interrogées, et doivent être exclues de toutes les activités impliquant des employés actuels.Former employee entities are rarely queried, and should be excluded from any activities that deal with current employees. Pour implémenter cette exigence, vous stockez les employés actifs dans la table Current et les anciens employés dans la table Archive.To implement this requirement, you store active employees in the Current table and former employees in the Archive table. L’archivage d’un employé nécessite la suppression de son entité de la table Current et son ajout à la table Archive.Archiving an employee requires you to delete the entity from the Current table, and add the entity to the Archive table.

Toutefois, vous ne pouvez pas utiliser une EGT pour effectuer ces deux opérationsBut you can't use an EGT to perform these two operations. Pour éviter le risque qu'une défaillance provoque l'apparition d'une entité dans les deux tables ou dans aucune d'elles, l'opération d'archivage doit être cohérente.To avoid the risk that a failure causes an entity to appear in both or neither tables, the archive operation must be eventually consistent. Le diagramme de séquence suivant décrit les étapes de cette opération.The following sequence diagram outlines the steps in this operation.

Diagramme de solution pour la cohérence finale

Un client lance l’opération d’archivage en plaçant un message dans une file d’attente Azure (dans cet exemple, pour archiver l’employé n°456).A client initiates the archive operation by placing a message on an Azure queue (in this example, to archive employee #456). Un rôle de travail interroge la file d'attente à la recherche de nouveaux messages ; lorsqu'il en trouve un, il le lit et laisse une copie masquée dans la file d'attente.A worker role polls the queue for new messages; when it finds one, it reads the message and leaves a hidden copy on the queue. Le rôle de travail extrait ensuite une copie de l’entité à partir de la table Current , insère une copie dans la table Archive et supprime l’original de la table Current.The worker role next fetches a copy of the entity from the Current table, inserts a copy in the Archive table, and then deletes the original from the Current table. Enfin, si aucune erreur n'est survenue lors des étapes précédentes, le rôle de travail supprime le message masqué de la file d'attente.Finally, if there were no errors from the previous steps, the worker role deletes the hidden message from the queue.

Dans cet exemple, l’étape 4 du diagramme permet d’insérer l’employé dans la table Archive .In this example, step 4 in the diagram inserts the employee into the Archive table. L’employé peut être ajouté à un objet blob dans le stockage Blob ou à un fichier dans un système de fichiers.It can add the employee to a blob in Blob storage or a file in a file system.

Récupérer suite à des échecsRecover from failures

Il est important que les opérations des étapes 4-5 du diagramme soient idempotentes au cas où le rôle de travail nécessite un redémarrage de l’opération d’archivage.It's important that the operations in steps 4-5 in the diagram be idempotent in case the worker role needs to restart the archive operation. Si vous utilisez le stockage Table, à l’étape 4 vous devez utiliser une opération « insérer ou remplacer » ; à l’étape 5, vous devez faire appel à une opération « supprimer si existe » dans la bibliothèque de client que vous utilisez.If you're using Table storage, for step 4 you should use an "insert or replace" operation; for step 5, you should use a "delete if exists" operation in the client library you're using. Si vous utilisez un autre système de stockage, vous devez utiliser une opération idempotent appropriée.If you're using another storage system, you must use an appropriate idempotent operation.

Si le rôle de travail ne termine jamais l’étape 6, après un délai d’attente le message réapparaît dans la file d’attente, prêt pour le rôle de travail qui tentera de le retraiter.If the worker role never completes step 6 in the diagram, then, after a timeout, the message reappears on the queue ready for the worker role to try to reprocess it. Le rôle de travail peut vérifier le nombre de fois où un message de file d’attente a été lu et, si nécessaire, l’indiquer comme message « incohérent » en vue d’une investigation en l’envoyant vers une file d’attente distincte.The worker role can check how many times a message on the queue has been read and, if necessary, flag it as a "poison" message for investigation by sending it to a separate queue. Pour plus d’informations sur la lecture des messages de la file d’attente et la vérification du nombre de retraits, consultez Obtenir des messages.For more information about reading queue messages and checking the dequeue count, see Get messages.

Certaines erreurs provenant du stockage Table et du stockage File d’attente sont des erreurs temporaires, et votre application cliente doit inclure une logique de nouvelle tentative appropriée pour les gérer.Some errors from Table storage and Queue storage are transient errors, and your client application should include suitable retry logic to handle them.

Problèmes et considérationsIssues and considerations

Prenez en compte les points suivants lorsque vous choisissez comment implémenter ce modèle :Consider the following points when deciding how to implement this pattern:

  • Cette solution ne fournit pas d’isolation des transactions.This solution doesn't provide for transaction isolation. Par exemple, un client peut lire les tables Current et Archive quand le rôle de travail est entre les étapes 4-5 du diagramme, et obtenir une vue incohérente des données.For example, a client might read the Current and Archive tables when the worker role was between steps 4-5 in the diagram, and see an inconsistent view of the data. Les données seront cohérentes par la suite.The data will be consistent eventually.
  • Vous pouvez être amené à vérifier que les étapes 4-5 sont idempotent afin d’assurer la cohérence.You must be sure that steps 4-5 are idempotent in order to ensure eventual consistency.
  • Vous pouvez mettre à l'échelle la solution en utilisant plusieurs files d'attente et instances de rôle de travail.You can scale the solution by using multiple queues and worker role instances.

Quand utiliser ce modèleWhen to use this pattern

Utilisez ce modèle lorsque vous souhaitez maintenir une cohérence entre des entités qui existent dans différentes partitions ou tables.Use this pattern when you want to guarantee eventual consistency between entities that exist in different partitions or tables. Vous pouvez étendre ce modèle pour garantir la cohérence des opérations entre le stockage Table et le stockage Blob, et d’autres sources de données différentes de Stockage Azure, comme une base de données ou un système de fichiers.You can extend this pattern to ensure eventual consistency for operations across Table storage and Blob storage, and other non-Azure Storage data sources, such as a database or the file system.

Les modèles et les conseils suivants peuvent aussi présenter un intérêt quand il s’agit d’implémenter ce modèle :The following patterns and guidance might also be relevant when implementing this pattern:

Nota

Si l’isolation des transactions est importante pour votre solution, redéfinissez vos tables pour pouvoir utiliser des EGT.If transaction isolation is important to your solution, consider redesigning your tables to enable you to use EGTs.

Modèle d’entités d’indexIndex entities pattern

Permet de mettre à jour des entités d'index pour mener des recherches efficaces renvoyant des listes d'entités.Maintain index entities to enable efficient searches that return lists of entities.

Contexte et problèmeContext and problem

Le stockage Table indexe automatiquement les entités en utilisant les valeurs PartitionKey et RowKey.Table storage automatically indexes entities by using the PartitionKey and RowKey values. Ainsi, une application cliente peut récupérer une entité efficacement à l’aide d’une requête de pointage.This enables a client application to retrieve an entity efficiently by using a point query. Par exemple, à l’aide de la structure de table suivante, une application cliente peut récupérer efficacement une entité d’employé individuelle en utilisant le nom de service et l’ID d’employé (valeurs PartitionKey et RowKey).For example, using the following table structure, a client application can efficiently retrieve an individual employee entity by using the department name and the employee ID (the PartitionKey and RowKey).

Graphique de la structure de l’entité Employé où une application cliente peut récupérer efficacement une entité d’employé individuelle en utilisant le nom de service et l’ID d’employé (PartitionKey et RowKey).

Si vous voulez également récupérer la liste des entités d’employés en fonction de la valeur d’une autre propriété qui n’est pas unique (par exemple son nom), vous devez utiliser une analyse de partition moins efficace.If you also want to be able to retrieve a list of employee entities based on the value of another non-unique property, such as last name, you must use a less efficient partition scan. Cette analyse recherche des correspondances au lieu d’utiliser un index pour rechercher directement.This scan finds matches, rather than using an index to look them up directly. En effet, le stockage Table ne fournit pas d’index secondaires.This is because Table storage doesn't provide secondary indexes.

SolutionSolution

Pour permettre la recherche par nom de famille en utilisant la structure d’entité précédente, vous devez tenir à jour des listes d’ID d’employés.To enable lookup by last name with the preceding entity structure, you must maintain lists of employee IDs. Si vous voulez récupérer les entités d’employés ayant un nom donné (comme Jones), vous devez d’abord localiser la liste d’ID d’employés dont le nom est Jones, puis récupérer ces entités d’employés.If you want to retrieve the employee entities with a particular last name, such as Jones, you must first locate the list of employee IDs for employees with Jones as their last name, and then retrieve those employee entities. Il existe trois méthodes principales pour stocker les listes d’ID d’employés :There are three main options for storing the lists of employee IDs:

  • L’utilisation du stockage Blob.Use Blob storage.
  • La création d'entités d'index dans la même partition que les entités des employés.Create index entities in the same partition as the employee entities.
  • La création d'entités d'index dans une table ou une partition séparée.Create index entities in a separate partition or table.

Option 1 : Utiliser le stockage BlobOption 1: Use Blob storage

Créez un objet blob pour chaque nom unique et, dans chaque magasin d’objets blob, stockez une liste des valeurs de PartitionKey (service) et RowKey (ID d’employé) pour les employés ayant ce nom.Create a blob for every unique last name, and in each blob store a list of the PartitionKey (department) and RowKey (employee ID) values for employees who have that last name. Quand vous ajoutez ou supprimez un employé, vérifiez que le contenu de l’objet blob adéquat est cohérent avec les entités d’employés.When you add or delete an employee, ensure that the content of the relevant blob is eventually consistent with the employee entities.

Option n°2 : Créer des entités d’index dans la même partitionOption 2: Create index entities in the same partition

Utilisez des entités d’index qui stockent les données suivantes :Use index entities that store the following data:

Graphique montrant l’entité Employee, avec une chaîne contenant une liste des ID d’employés ayant le même nom de famille

La propriété EmployeeIDs contient une liste d’ID d’employés pour les employés portant le nom stocké dans la RowKey.The EmployeeIDs property contains a list of employee IDs for employees with the last name stored in the RowKey.

Les étapes suivantes décrivent le processus à suivre quand vous ajoutez un nouvel employé.The following steps outline the process you should follow when you're adding a new employee. Dans cet exemple, nous ajoutons au service des ventes un employé ayant l’ID 000152 et dont le nom de famille est Jones :In this example, we're adding an employee with ID 000152 and last name Jones in the Sales department:

  1. Récupérez l’entité de l’index ayant la valeur PartitionKey « Sales » et la valeur RowKey « Jones ».Retrieve the index entity with a PartitionKey value "Sales", and the RowKey value "Jones". Enregistrez l'ETag de cette entité pour l'utiliser lors de l'étape 2.Save the ETag of this entity to use in step 2.
  2. Créez une EGT (c’est-à-dire une opération de traitement par lot) qui insère la nouvelle entité d’employé (valeur PartitionKey « sales » et valeur RowKey « 000152 ») et met à jour l’entité d’index (valeur PartitionKey « sales » et valeur RowKey « Jones »).Create an entity group transaction (that is, a batch operation) that inserts the new employee entity (PartitionKey value "Sales" and RowKey value "000152"), and updates the index entity (PartitionKey value "Sales" and RowKey value "Jones"). Pour ce faire, l’EGT ajoute le nouvel ID d’employé à la liste dans le champ EmployeeIDs.The EGT does this by adding the new employee ID to the list in the EmployeeIDs field. Pour plus d’informations sur les EGT, consultez Transactions de groupe d’entités.For more information about EGTs, see Entity group transactions.
  3. Si l’EGT échoue en raison d’une erreur d’accès concurrentiel optimiste (autrement dit, quelqu’un d’autre a modifié l’entité d’index), vous devez recommencer à l’étape 1.If the EGT fails because of an optimistic concurrency error (that is, someone else has modified the index entity), then you need to start over at step 1.

Vous pouvez adopter une approche similaire pour supprimer un employé si vous utilisez la deuxième option.You can use a similar approach to deleting an employee if you're using the second option. La modification du nom d’un employé est légèrement plus complexe, car vous devrez exécuter une EGT qui met à jour trois entités : l’entité d’employé, l’entité d’index pour l’ancien nom et l’entité d’index pour le nouveau nom.Changing an employee's last name is slightly more complex, because you need to run an EGT that updates three entities: the employee entity, the index entity for the old last name, and the index entity for the new last name. Vous devez récupérer chaque entité avant d’apporter des modifications, afin de récupérer les valeurs ETag que vous pouvez ensuite utiliser pour effectuer les mises à jour à l’aide de l’accès concurrentiel optimiste.You must retrieve each entity before making any changes, in order to retrieve the ETag values that you can then use to perform the updates by using optimistic concurrency.

Les étapes suivantes décrivent le processus à suivre quand vous devez rechercher tous les employés ayant un nom spécifique dans un service.The following steps outline the process you should follow when you need to look up all the employees with a particular last name in a department. Dans cet exemple, nous recherchons tous les employés dont le nom est Jones et qui travaillent dans le service des ventes :In this example, we're looking up all the employees with last name Jones in the Sales department:

  1. Récupérez l’entité de l’index ayant la valeur PartitionKey « Sales » et la valeur RowKey « Jones ».Retrieve the index entity with a PartitionKey value "Sales", and the RowKey value "Jones".
  2. Analysez la liste des ID d’employés dans le champ EmployeeIDs.Parse the list of employee IDs in the EmployeeIDs field.
  3. Si vous avez besoin de plus d’informations sur chacun de ces employés (par exemple leurs adresses e-mail), récupérez chacune des entités d’employés à l’aide de la valeur PartitionKey « Sales » et des valeurs RowKey de la liste des employés obtenue à l’étape 2.If you need additional information about each of these employees (such as their email addresses), retrieve each of the employee entities by using PartitionKey value "Sales", and RowKey values from the list of employees you obtained in step 2.

Option 3 : Créer des entités d’index dans une table ou une partition séparéeOption 3: Create index entities in a separate partition or table

Pour cette méthode, utilisez les entités d’index qui stockent les données suivantes :For this option, use index entities that store the following data:

Capture d’écran qui montre l’entité d’index Employé qui contient une liste des ID d’employés pour les employés dont le nom de famille est stocké dans RowKey et PartitionKey.

La propriété EmployeeIDs contient une liste d’ID d’employés pour les employés portant le nom stocké dans la RowKey et PartitionKey.The EmployeeIDs property contains a list of employee IDs for employees with the last name stored in the RowKey and PartitionKey.

Vous ne pouvez pas utiliser des EGT pour maintenir la cohérence, car les entités d’index sont dans une partition distincte des entités d’employés.You can't use EGTs to maintain consistency, because the index entities are in a separate partition from the employee entities. Vérifiez que les entités d’index sont cohérentes avec les entités d’employé.Ensure that the index entities are eventually consistent with the employee entities.

Problèmes et considérationsIssues and considerations

Prenez en compte les points suivants lorsque vous choisissez comment implémenter ce modèle :Consider the following points when deciding how to implement this pattern:

  • Cette solution nécessite au moins deux requêtes pour récupérer des entités correspondantes : une pour interroger les entités d’index afin d’obtenir la liste des valeurs RowKey, puis des requêtes pour récupérer chaque entité dans la liste.This solution requires at least two queries to retrieve matching entities: one to query the index entities to obtain the list of RowKey values, and then queries to retrieve each entity in the list.
  • Étant donné qu’une entité a une taille maximale de 1 Mo, l’utilisation des méthodes n°2 et n°3 dans la solution partent du principe que la liste d’ID d’employés pour un nom donné n’est jamais supérieure à 1 Mo.Because an individual entity has a maximum size of 1 MB, option 2 and option 3 in the solution assume that the list of employee IDs for any particular last name is never more than 1 MB. Si la liste d’ID d’employés est susceptible d’être supérieure à 1 Mo, appliquez la méthode n°1 et stockez les données d’index dans le stockage Blob.If the list of employee IDs is likely to be more than 1 MB in size, use option 1 and store the index data in Blob storage.
  • Si vous appliquez la méthode n°2 (utilisation d’EGT pour gérer l’ajout et la suppression des employés et la modification du nom d’un employé), vous devez évaluer si le volume des transactions atteint les limites de scalabilité dans une partition donnée.If you use option 2 (using EGTs to handle adding and deleting employees, and changing an employee's last name), you must evaluate if the volume of transactions will approach the scalability limits in a particular partition. Si c’est le cas, vous devez envisager d’adopter une solution cohérente (option 1 ou option 3).If this is the case, you should consider an eventually consistent solution (option 1 or option 3). Celles-ci utilisent des files d’attente pour gérer les requêtes de mise à jour, et vous permettent de stocker vos entités d’index dans une partition distincte des entités d’employés.These use queues to handle the update requests, and enable you to store your index entities in a separate partition from the employee entities.
  • L’option 2 de cette solution part du principe que vous souhaitez effectuer une recherche par nom de famille dans un service.Option 2 in this solution assumes that you want to look up by last name within a department. Par exemple, vous souhaitez récupérer une liste d’employés dont le nom de famille est Jones dans le service des ventes.For example, you want to retrieve a list of employees with a last name Jones in the Sales department. Si vous souhaitez pouvoir rechercher dans toute l’organisation tous les employés portant le nom de famille Jones, appliquez la méthode n°1 ou n°3.If you want to be able to look up all the employees with a last name Jones across the whole organization, use either option 1 or option 3.
  • Vous pouvez implémenter une solution basée sur une file d’attente qui assure la cohérence finale.You can implement a queue-based solution that delivers eventual consistency. Pour plus d’informations, consultez Modèle de transactions cohérentes.For more details, see the Eventually consistent transactions pattern.

Quand utiliser ce modèleWhen to use this pattern

Utilisez ce modèle lorsque vous souhaitez rechercher un jeu d’entités qui partagent toutes une valeur de propriété courante, comme l’ensemble des employés dont le nom de famille est Jones.Use this pattern when you want to look up a set of entities that all share a common property value, such as all employees with the last name Jones.

Les modèles et les conseils suivants peuvent aussi présenter un intérêt quand il s’agit d’implémenter ce modèle :The following patterns and guidance might also be relevant when implementing this pattern:

Modèle de dénormalisationDenormalization pattern

Combinez des données connexes dans une entité unique pour pouvoir récupérer toutes les données dont vous avez besoin avec une seule requête de pointage.Combine related data together in a single entity to enable you to retrieve all the data you need with a single point query.

Contexte et problèmeContext and problem

Dans une base de données relationnelle, vous normalisez généralement des données pour supprimer les doublons générés quand des requêtes extraient des données provenant de plusieurs tables.In a relational database, you typically normalize data to remove duplication that occurs when queries retrieve data from multiple tables. Si vous normalisez des données dans les tables Azure, vous devez effectuer plusieurs allers-retours à partir du client vers le serveur pour récupérer des données associées.If you normalize your data in Azure tables, you must make multiple round trips from the client to the server to retrieve your related data. Par exemple, avec la structure de table suivante, vous avez besoin de deux allers-retours pour récupérer les détails d’un service.For example, with the following table structure, you need two round trips to retrieve the details for a department. Un aller-retour extrait l’entité Department qui comprend l’ID du responsable, et le deuxième aller-retour extrait les détails du responsable dans une entité Employee.One trip fetches the department entity that includes the manager's ID, and the second trip fetches the manager's details in an employee entity.

Graphique d’entité Department et d’entité Employee

SolutionSolution

Au lieu de stocker les données dans les deux entités distinctes, dénormalisez les données et conservez une copie des détails du responsable dans l’entité du service.Instead of storing the data in two separate entities, denormalize the data and keep a copy of the manager's details in the department entity. Par exemple :For example:

Graphique d’entité Department dénormalisée et combinée

Une fois les entités de service stockées avec ces propriétés, vous pouvez récupérer toutes les informations nécessaires sur un service à l’aide d’une requête de pointage.With department entities stored with these properties, you can now retrieve all the details you need about a department by using a point query.

Problèmes et considérationsIssues and considerations

Prenez en compte les points suivants lorsque vous choisissez comment implémenter ce modèle :Consider the following points when deciding how to implement this pattern:

  • Des coûts réels sont associés au stockage des données à deux reprises.There is some cost overhead associated with storing some data twice. L’avantage en matière de performances résultant d’un nombre réduit de requêtes au stockage Table compense généralement l’augmentation marginale des coûts de stockage.The performance benefit resulting from fewer requests to Table storage typically outweighs the marginal increase in storage costs. En outre, ce coût est partiellement compensé par une réduction du nombre de transactions dont vous avez besoin pour extraire les détails d’un service.Further, this cost is partially offset by a reduction in the number of transactions you require to fetch the details of a department.
  • Vous devez conserver la cohérence des deux entités qui stockent des informations sur les responsables.You must maintain the consistency of the two entities that store information about managers. Vous pouvez gérer le problème de cohérence en faisant appel à des EGT pour mettre à jour plusieurs entités en une seule transaction atomique.You can handle the consistency issue by using EGTs to update multiple entities in a single atomic transaction. Dans ce cas, l’entité Department et l’entité Employee pour le responsable du service sont stockées dans la même partition.In this case, the department entity and the employee entity for the department manager are stored in the same partition.

Quand utiliser ce modèleWhen to use this pattern

Utilisez ce modèle lorsque vous devez fréquemment rechercher des informations connexes.Use this pattern when you frequently need to look up related information. Ce modèle réduit le nombre de requêtes que votre client doit effectuer pour récupérer les données requises.This pattern reduces the number of queries your client must make to retrieve the data it requires.

Les modèles et les conseils suivants peuvent aussi présenter un intérêt quand il s’agit d’implémenter ce modèle :The following patterns and guidance might also be relevant when implementing this pattern:

Modèle de clé composéeCompound key pattern

utiliser des valeurs de RowKey composées pour permettre à un client de rechercher des données connexes en utilisant une seule requête de pointage.Use compound RowKey values to enable a client to look up related data with a single point query.

Contexte et problèmeContext and problem

Dans une base de données relationnelle, il est naturel d’utiliser des jointures dans les requêtes pour retourner des données connexes au client dans une seule requête.In a relational database, it's natural to use joins in queries to return related pieces of data to the client in a single query. Par exemple, vous pouvez utiliser l’ID d’employé pour rechercher une liste d’entités associées qui contiennent des données de performances et d’évaluation de cet employé.For example, you might use the employee ID to look up a list of related entities that contain performance and review data for that employee.

Supposez que vous stockez des entités relatives aux employés dans le stockage Table à l’aide de la structure suivante :Assume you are storing employee entities in Table storage by using the following structure:

Graphique de la structure d’entité Employé que vous devez utiliser pour stocker les entités d’employés dans le stockage Table.

Vous devez également stocker les données historiques relatives aux évaluations et aux performances de chaque année durant laquelle l’employé a travaillé pour votre organisation, et vous devez être en mesure d’accéder à ces informations par année.You also need to store historical data relating to reviews and performance for each year the employee has worked for your organization, and you need to be able to access this information by year. Une option consiste à créer une autre table qui stocke les entités avec la structure suivante :One option is to create another table that stores entities with the following structure:

Graphique d’entité d’évaluation d’employé

Avec cette approche, vous pouvez décider de dupliquer certaines informations (telles que le prénom et le nom) dans la nouvelle entité afin de pouvoir récupérer vos données avec une requête unique.With this approach, you might decide to duplicate some information (such as first name and last name) in the new entity, to enable you to retrieve your data with a single request. Cependant, vous ne pouvez pas conserver une cohérence forte, car vous ne pouvez pas utiliser une EGT pour mettre à jour les deux entités de manière atomique.However, you can't maintain strong consistency because you can't use an EGT to update the two entities atomically.

SolutionSolution

Stockez un nouveau type d’entité dans votre table d’origine à l’aide d’entités structurées comme suit :Store a new entity type in your original table by using entities with the following structure:

Graphique d’entité Employee avec clé composée

Notez que la RowKey est désormais une clé composée de l’ID d’employé et de l’année des données d’évaluation.Notice how the RowKey is now a compound key, made up of the employee ID and the year of the review data. Cela vous permet de récupérer les performances de l’employé et d’examiner les données avec une seule requête pour une seule entité.This enables you to retrieve the employee's performance and review data with a single request for a single entity.

L'exemple suivant indique comment vous pouvez récupérer toutes les données d'évaluation d'un employé donné (par exemple, l'employé 000123 du service des ventes) :The following example outlines how you can retrieve all the review data for a particular employee (such as employee 000123 in the Sales department):

$filter=(PartitionKey eq 'Sales') and (RowKey ge 'empid_000123') and (RowKey lt 'empid_000124')&$select=RowKey,Manager Rating,Peer Rating,Comments$filter=(PartitionKey eq 'Sales') and (RowKey ge 'empid_000123') and (RowKey lt 'empid_000124')&$select=RowKey,Manager Rating,Peer Rating,Comments

Problèmes et considérationsIssues and considerations

Prenez en compte les points suivants lorsque vous choisissez comment implémenter ce modèle :Consider the following points when deciding how to implement this pattern:

  • Vous devez utiliser un caractère de séparation approprié pour faciliter l’analyse des valeurs de RowKey : par exemple, 000123_2012.You should use a suitable separator character that makes it easy to parse the RowKey value: for example, 000123_2012.
  • Vous stockez également cette entité dans la même partition que les autres entités qui contiennent des données associées au même employé.You're also storing this entity in the same partition as other entities that contain related data for the same employee. Cela signifie que vous pouvez utiliser des EGT pour maintenir une forte cohérence.This means you can use EGTs to maintain strong consistency.
  • Vous devez prendre en compte la fréquence à laquelle vous interrogez les données afin de déterminer si ce modèle est approprié.You should consider how frequently you'll query the data to determine whether this pattern is appropriate. Par exemple, si vous accédez rarement aux données d’évaluation et souvent aux données principales de l’employé, vous devez les conserver en tant qu’entités distinctes.For example, if you access the review data infrequently, and the main employee data often, you should keep them as separate entities.

Quand utiliser ce modèleWhen to use this pattern

Utilisez ce modèle lorsque vous devez stocker une ou plusieurs entités connexes que vous interrogez fréquemment.Use this pattern when you need to store one or more related entities that you query frequently.

Les modèles et les conseils suivants peuvent aussi présenter un intérêt quand il s’agit d’implémenter ce modèle :The following patterns and guidance might also be relevant when implementing this pattern:

Modèle de fin de journalLog tail pattern

Récupérez les n dernières entités ajoutées à une partition en utilisant une valeur de RowKey qui effectue un tri dans l’ordre inverse de la date et de l’heure.Retrieve the n entities most recently added to a partition by using a RowKey value that sorts in reverse date and time order.

Nota

Les résultats de la requête renvoyés par l’API Table Azure dans Azure Cosmos DB ne sont pas triés par clé de partition ou clé de ligne.Query results returned by the Azure Table API in Azure Cosmos DB aren't sorted by partition key or row key. Ainsi, ce modèle convient au stockage Table, mais pas à Azure Cosmos DB.Thus, while this pattern is suitable for Table storage, it isn't suitable for Azure Cosmos DB. Pour obtenir la liste détaillée des différences de fonctionnalités, consultez Différences entre l'API Table dans Azure Cosmos DB et Stockage Table Azure.For a detailed list of feature differences, see differences between Table API in Azure Cosmos DB and Azure Table Storage.

Contexte et problèmeContext and problem

Une exigence courante est de pouvoir récupérer les toutes dernières entités créées, par exemple les dix dernières notes de frais soumises par un employé.A common requirement is to be able to retrieve the most recently created entities, for example the ten most recent expense claims submitted by an employee. Les requêtes de table prennent en charge une opération de requête $top pour retourner les n premières entités d’un ensemble.Table queries support a $top query operation to return the first n entities from a set. Il n’existe aucune opération de requête équivalente pour retourner les n dernières entités d’un ensemble.There's no equivalent query operation to return the last n entities in a set.

SolutionSolution

Stockez les entités en utilisant une RowKey qui trie naturellement par ordre inverse de date et d’heure, afin que l’entrée la plus récente soit toujours la première dans la table.Store the entities by using a RowKey that naturally sorts in reverse date/time order, so the most recent entry is always the first one in the table.

Par exemple, pour être en mesure de récupérer les dix notes de frais les plus récentes soumises par un employé, vous pouvez utiliser une valeur de graduation inverse dérivée de l'heure actuelle.For example, to be able to retrieve the ten most recent expense claims submitted by an employee, you can use a reverse tick value derived from the current date/time. L’exemple de code C# suivant montre une méthode de création d’une valeur de « graduation inverse » adéquate pour une RowKey qui procède à un tri du plus récent au plus ancien :The following C# code sample shows one way to create a suitable "inverted ticks" value for a RowKey that sorts from the most recent to the oldest:

string invertedTicks = string.Format("{0:D19}", DateTime.MaxValue.Ticks - DateTime.UtcNow.Ticks);

Vous pouvez récupérer la valeur de date-heure à l’aide du code suivant :You can get back to the date/time value by using the following code:

DateTime dt = new DateTime(DateTime.MaxValue.Ticks - Int64.Parse(invertedTicks));

La requête de table ressemble à ceci :The table query looks like this:

https://myaccount.table.core.windows.net/EmployeeExpense(PartitionKey='empid')?$top=10

Problèmes et considérationsIssues and considerations

Prenez en compte les points suivants lorsque vous choisissez comment implémenter ce modèle :Consider the following points when deciding how to implement this pattern:

  • Vous devez faire précéder la valeur de graduation inverse par des zéros non significatifs pour garantir que la valeur de chaîne trie comme prévu.You must pad the reverse tick value with leading zeroes, to ensure the string value sorts as expected.
  • Vous devez être conscient des objectifs d'évolutivité au niveau d'une partition.You must be aware of the scalability targets at the level of a partition. Veillez à ne pas créer des partitions de zone sensible.Be careful to not create hot spot partitions.

Quand utiliser ce modèleWhen to use this pattern

Utilisez ce modèle quand vous avez besoin d’accéder aux entités dans l’ordre inverse de date-heure, ou quand vous devez accéder aux entités ajoutées récemment.Use this pattern when you need to access entities in reverse date/time order, or when you need to access the most recently added entities.

Les modèles et les conseils suivants peuvent aussi présenter un intérêt quand il s’agit d’implémenter ce modèle :The following patterns and guidance might also be relevant when implementing this pattern:

Modèle de suppression de volume élevéHigh volume delete pattern

activer la suppression d’un volume élevé d’entités en stockant toutes les entités pour les supprimer simultanément dans leur propre table distincte.Enable the deletion of a high volume of entities by storing all the entities for simultaneous deletion in their own separate table. Vous supprimez les entités en supprimant la table.You delete the entities by deleting the table.

Contexte et problèmeContext and problem

De nombreuses applications suppriment les anciennes données qui n’ont plus besoin d’être disponibles pour une application cliente ou archivées par l’application sur un autre support de stockage.Many applications delete old data that no longer needs to be available to a client application, or that the application has archived to another storage medium. En général, vous identifiez ces données par date.You typically identify such data by a date. Par exemple, vous devez supprimer les enregistrements de toutes les requêtes de connexion datant de plus de 60 jours.For example, you have a requirement to delete records of all sign-in requests that are more than 60 days old.

Une conception possible consiste à utiliser la date et l’heure de la requête de connexion dans la RowKey :One possible design is to use the date and time of the sign-in request in the RowKey:

Graphique d’entité de tentative de connexion

Cette approche évite les zones sensibles de partition, car l’application peut insérer et supprimer des entités de connexion pour chaque utilisateur dans une partition distincte.This approach avoids partition hotspots, because the application can insert and delete sign-in entities for each user in a separate partition. Toutefois, cette approche peut s’avérer coûteuse et fastidieuse si vous avez un grand nombre d’entités.However, this approach can be costly and time consuming if you have a large number of entities. Tout d’abord, vous devez effectuer une analyse de table afin d’identifier toutes les entités à supprimer, puis vous devez supprimer chaque entité ancienne.First, you need to perform a table scan in order to identify all the entities to delete, and then you must delete each old entity. Vous pouvez réduire le nombre d’allers-retours vers le serveur requis pour supprimer les anciennes entités en traitant par lots plusieurs demandes de suppression dans les TGE.You can reduce the number of round trips to the server required to delete the old entities by batching multiple delete requests into EGTs.

SolutionSolution

Utilisez une table distincte pour chaque jour de tentative de connexion.Use a separate table for each day of sign-in attempts. Vous pouvez utiliser la conception d’entité précédente pour éviter les zones sensibles quand vous insérez des entités.You can use the preceding entity design to avoid hotspots when you are inserting entities. La suppression des anciennes entités consiste désormais à simplement supprimer une table tous les jours (une seule opération de stockage) au lieu de rechercher et de supprimer des centaines de milliers d’entités de connexion individuelle chaque jour.Deleting old entities is now simply a question of deleting one table every day (a single storage operation), instead of finding and deleting hundreds and thousands of individual sign-in entities every day.

Problèmes et considérationsIssues and considerations

Prenez en compte les points suivants lorsque vous choisissez comment implémenter ce modèle :Consider the following points when deciding how to implement this pattern:

  • Votre conception prend-elle en charge les autres méthodes de traitement des données que votre application va utiliser, telles que la recherche d’entités spécifiques, les liaisons avec d’autres données ou la génération d’informations d’agrégation ?Does your design support other ways your application will use the data, such as looking up specific entities, linking with other data, or generating aggregate information?
  • Votre conception évite-t-elle les zones sensibles lorsque vous insérez de nouvelles entités ?Does your design avoid hot spots when you are inserting new entities?
  • Vous devez attendre un délai si vous voulez réutiliser le même nom de table après l'avoir supprimée.Expect a delay if you want to reuse the same table name after deleting it. Il est préférable de toujours utiliser des noms de table uniques.It's better to always use unique table names.
  • Attendez-vous à une limitation du débit lors de l’utilisation initiale d’une nouvelle table, pendant que le stockage Table assimile les modèles d’accès et distribue les partitions parmi les nœuds.Expect some rate limiting when you first use a new table, while Table storage learns the access patterns and distributes the partitions across nodes. Vous devez réfléchir à la fréquence à laquelle vous devez créer des tables.You should consider how frequently you need to create new tables.

Quand utiliser ce modèleWhen to use this pattern

Utilisez ce modèle lorsque vous avez un volume élevé d'entités, que vous devez supprimer en même temps.Use this pattern when you have a high volume of entities that you must delete at the same time.

Les modèles et les conseils suivants peuvent aussi présenter un intérêt quand il s’agit d’implémenter ce modèle :The following patterns and guidance might also be relevant when implementing this pattern:

Modèle de série de donnéesData series pattern

Stockez des séries de données complètes dans une entité unique pour réduire votre nombre de demandes.Store complete data series in a single entity to minimize the number of requests you make.

Contexte et problèmeContext and problem

Il arrive qu'une application stocke une série de données qu'elle doit fréquemment récupérer en une seule fois :A common scenario is for an application to store a series of data that it typically needs to retrieve all at once. Par exemple, votre application peut enregistrer combien de messages de messagerie instantanée chaque employé envoie toutes les heures, puis utiliser ces informations pour tracer le nombre de messages envoyés par chaque utilisateur dans les 24 heures précédentes.For example, your application might record how many IM messages each employee sends every hour, and then use this information to plot how many messages each user sent over the preceding 24 hours. Une conception peut consister à stocker 24 entités pour chaque employé :One design might be to store 24 entities for each employee:

Graphique d’entité de statistiques de message

Grâce à cette conception, vous pouvez facilement rechercher et mettre à jour l'entité mise à jour pour chaque employé chaque fois que l'application doit mettre à jour la valeur de nombre de messages.With this design, you can easily locate and update the entity to update for each employee whenever the application needs to update the message count value. Cependant, pour récupérer les informations pour tracer un graphique de l'activité des 24 heures précédentes, vous devez récupérer les 24 entités.However, to retrieve the information to plot a chart of the activity for the preceding 24 hours, you must retrieve 24 entities.

SolutionSolution

Utilisez la conception suivante, avec une propriété distincte pour stocker le nombre de messages pour chaque heure :Use the following design, with a separate property to store the message count for each hour:

Graphique montrant l’entité de statistiques de message avec des propriétés distinctes

Grâce à cette conception, vous pouvez utiliser une opération de fusion pour mettre à jour le nombre de messages pour un employé pour une heure spécifique.With this design, you can use a merge operation to update the message count for an employee for a specific hour. À présent, vous pouvez récupérer toutes les informations dont vous avez besoin pour tracer le graphique à l’aide d’une requête pour une seule entité.Now, you can retrieve all the information you need to plot the chart by using a request for a single entity.

Problèmes et considérationsIssues and considerations

Prenez en compte les points suivants lorsque vous choisissez comment implémenter ce modèle :Consider the following points when deciding how to implement this pattern:

  • Si votre série de données complète ne tient pas dans une seule entité (une entité peut avoir jusqu’à 252 propriétés), utilisez un autre magasin de données, comme un objet blob.If your complete data series doesn't fit into a single entity (an entity can have up to 252 properties), use an alternative data store such as a blob.
  • Si vous avez plusieurs clients qui mettent à jour une entité simultanément, utilisez le ETag pour implémenter l’accès concurrentiel optimiste.If you have multiple clients updating an entity simultaneously, use the ETag to implement optimistic concurrency. Si vous avez de nombreux clients, vous pouvez observer une contention élevée.If you have many clients, you might experience high contention.

Quand utiliser ce modèleWhen to use this pattern

Utilisez ce modèle lorsque vous devez mettre à jour et récupérer une série de données associée à une entité individuelle.Use this pattern when you need to update and retrieve a data series associated with an individual entity.

Les modèles et les conseils suivants peuvent aussi présenter un intérêt quand il s’agit d’implémenter ce modèle :The following patterns and guidance might also be relevant when implementing this pattern:

Modèle d’entités largesWide entities pattern

Utilisez plusieurs entités physiques pour stocker des entités logiques ayant plus de 252 propriétés.Use multiple physical entities to store logical entities with more than 252 properties.

Contexte et problèmeContext and problem

Une entité individuelle ne peut pas avoir plus de 252 propriétés (à l’exception des propriétés système obligatoires) et ne peut pas stocker plus de 1 Mo de données au total.An individual entity can have no more than 252 properties (excluding the mandatory system properties), and can't store more than 1 MB of data in total. Dans une base de données relationnelle, vous contourneriez généralement les limites de taille d’une ligne en ajoutant une nouvelle table et en appliquant une relation un-à-un entre elles.In a relational database, you would typically work around any limits on the size of a row by adding a new table, and enforcing a 1-to-1 relationship between them.

SolutionSolution

À l’aide du stockage Table, vous pouvez stocker plusieurs entités pour représenter un objet métier volumineux unique ayant plus de 252 propriétés.By using Table storage, you can store multiple entities to represent a single large business object with more than 252 properties. Par exemple, si vous souhaitez stocker le nombre de messages instantanés envoyés par chaque employé durant les 365 derniers jours, vous pouvez utiliser la conception suivante qui utilise deux entités avec des schémas différents :For example, if you want to store a count of the number of IM messages sent by each employee for the last 365 days, you can use the following design that uses two entities with different schemas:

Graphique montrant l’entité de statistiques de message avec RowKey 01 et l’entité de statistiques de message avec RowKey 02

Si vous souhaitez apporter une modification qui nécessite la mise à jour des deux entités pour les garder mutuellement synchronisées, vous pouvez utiliser une EGT.If you need to make a change that requires updating both entities to keep them synchronized with each other, you can use an EGT. Sinon, vous pouvez utiliser une opération de fusion pour mettre à jour le nombre de messages pour un jour spécifique.Otherwise, you can use a single merge operation to update the message count for a specific day. Pour récupérer toutes les données d’un employé, vous devez récupérer les deux entités.To retrieve all the data for an individual employee, you must retrieve both entities. Vous pouvez effectuer cette opération avec deux requêtes efficaces qui utilisent à la fois une PartitionKey et une valeur RowKey.You can do this with two efficient requests that use both a PartitionKey and a RowKey value.

Problèmes et considérationsIssues and considerations

Prenez en compte les points suivants quand vous choisissez comment implémenter ce modèle :Consider the following point when deciding how to implement this pattern:

  • La récupération d'une entité logique complète implique au moins deux transactions de stockage : une pour récupérer chaque entité physique.Retrieving a complete logical entity involves at least two storage transactions: one to retrieve each physical entity.

Quand utiliser ce modèleWhen to use this pattern

Utilisez ce modèle quand vous avez besoin de stocker des entités dont la taille ou le nombre de propriétés dépassent les limites d’une entité individuelle dans le stockage Table.Use this pattern when you need to store entities whose size or number of properties exceeds the limits for an individual entity in Table storage.

Les modèles et les conseils suivants peuvent aussi présenter un intérêt quand il s’agit d’implémenter ce modèle :The following patterns and guidance might also be relevant when implementing this pattern:

Modèle d’entités volumineusesLarge entities pattern

Utilisez le stockage Blob pour stocker des valeurs de propriétés volumineuses.Use Blob storage to store large property values.

Contexte et problèmeContext and problem

Une entité individuelle ne peut pas stocker plus de 1 Mo de données au total.An individual entity can't store more than 1 MB of data in total. Si une ou plusieurs des propriétés stockent des valeurs qui provoquent un dépassement de la taille totale de votre entité, vous ne pouvez pas stocker l’intégralité de l’entité dans le stockage Table.If one or several of your properties store values that cause the total size of your entity to exceed this value, you can't store the entire entity in Table storage.

SolutionSolution

Si votre entité dépasse 1 Mo car une ou plusieurs propriétés contiennent une grande quantité de données, vous pouvez stocker des données dans le stockage Blob et stocker ensuite l’adresse de l’objet blob dans une propriété de l’entité.If your entity exceeds 1 MB in size because one or more properties contain a large amount of data, you can store data in Blob storage, and then store the address of the blob in a property in the entity. Par exemple, vous pouvez stocker la photo d’un employé dans le stockage Blob, et stocker un lien vers la photo dans la propriété Photo de votre entité d’employé :For example, you can store the photo of an employee in Blob storage, and store a link to the photo in the Photo property of your employee entity:

Graphique montrant l’entité Employee avec chaîne Photo qui pointe vers le stockage Blob

Problèmes et considérationsIssues and considerations

Prenez en compte les points suivants lorsque vous choisissez comment implémenter ce modèle :Consider the following points when deciding how to implement this pattern:

  • Pour maintenir la cohérence entre l’entité du stockage Table et les données du stockage Blob, utilisez le modèle de transactions cohérentes pour tenir à jour vos entités.To maintain eventual consistency between the entity in Table storage and the data in Blob storage, use the Eventually consistent transactions pattern to maintain your entities.
  • La récupération d'une entité complète implique au moins deux transactions de stockage : une pour récupérer l'entité et l'autre pour récupérer les données blob.Retrieving a complete entity involves at least two storage transactions: one to retrieve the entity and one to retrieve the blob data.

Quand utiliser ce modèleWhen to use this pattern

Utilisez ce modèle quand vous avez besoin de stocker des entités dont la taille dépasse les limites d’une entité individuelle dans le stockage Table.Use this pattern when you need to store entities whose size exceeds the limits for an individual entity in Table storage.

Les modèles et les conseils suivants peuvent aussi présenter un intérêt quand il s’agit d’implémenter ce modèle :The following patterns and guidance might also be relevant when implementing this pattern:

Ajouter un anti-modèle ou un préfixe d'anti-modèlePrepend/append anti-pattern

Quand vous avez un volume élevé d’insertions, augmentez la scalabilité en répartissant les insertions parmi plusieurs partitions.When you have a high volume of inserts, increase scalability by spreading the inserts across multiple partitions.

Contexte et problèmeContext and problem

L'ajout d'entité ou de suffixe d'entité à vos entités stockées pousse généralement l'application à ajouter de nouvelles entités à la première ou à la dernière partition d'une séquence.Prepending or appending entities to your stored entities typically results in the application adding new entities to the first or last partition of a sequence of partitions. Dans ce cas, toutes les insertions à un moment donné se produisent dans la même partition, ce qui crée une zone sensible.In this case, all of the inserts at any particular time are taking place in the same partition, creating a hotspot. Cela empêche le stockage Table d’effectuer des insertions d’équilibrage de charge sur plusieurs nœuds, et peut éventuellement obliger votre application à atteindre les objectifs de scalabilité pour la partition.This prevents Table storage from load-balancing inserts across multiple nodes, and possibly causes your application to hit the scalability targets for partition. Par exemple, considérez le cas d’une application qui journalise l’accès au réseau et aux ressources par les employés.For example, consider the case of an application that logs network and resource access by employees. Une structure d’entité telle que la suivante peut entraîner la saturation de la partition de l’heure actuelle, si le volume des transactions atteint l’objectif de scalabilité pour une partition individuelle :An entity structure such as the following can result in the current hour's partition becoming a hotspot, if the volume of transactions reaches the scalability target for an individual partition:

Graphique d’une structure d’entité qui peut entraîner la saturation de la partition de l’heure actuelle, si le volume des transactions atteint l’objectif de scalabilité pour une partition individuelle.

SolutionSolution

La structure d’entité alternative suivante permet d’éviter une zone sensible dans n’importe quelle partition particulière tandis que l’application journalise les événements :The following alternative entity structure avoids a hotspot on any particular partition, as the application logs events:

Graphique montrant l’entité Employee avec RowKey combinant l’année, le mois, le jour, l’heure et l’ID d’événement

Dans cet exemple, notez que PartitionKey et RowKey sont toutes deux des clés composées.Notice with this example how both the PartitionKey and RowKey are compound keys. PartitionKey utilise les ID de service et d’employé pour distribuer la journalisation sur plusieurs partitions.The PartitionKey uses both the department and employee ID to distribute the logging across multiple partitions.

Problèmes et considérationsIssues and considerations

Prenez en compte les points suivants lorsque vous choisissez comment implémenter ce modèle :Consider the following points when deciding how to implement this pattern:

  • La structure clé alternative qui évite de créer efficacement des partitions sensibles sur des insertions prend-elle en charge efficacement les requêtes effectuées par votre application cliente ?Does the alternative key structure that avoids creating hot partitions on inserts efficiently support the queries your client application makes?
  • Le volume prévu de transactions signifie-t-il que vous êtes susceptible d’atteindre les objectifs de scalabilité pour une partition individuelle et d’être limité par le stockage Table ?Does your anticipated volume of transactions mean that you're likely to reach the scalability targets for an individual partition, and be throttled by Table storage?

Quand utiliser ce modèleWhen to use this pattern

Évitez l’ajout d’anti-modèle ou de suffixe d’anti-modèle quand votre volume de transactions est susceptible d’entraîner la limitation du débit par le stockage Table quand vous accédez à une partition sensible.Avoid the prepend/append anti-pattern when your volume of transactions is likely to result in rate limiting by Table storage when you access a hot partition.

Les modèles et les conseils suivants peuvent aussi présenter un intérêt quand il s’agit d’implémenter ce modèle :The following patterns and guidance might also be relevant when implementing this pattern:

Journalisation de l'anti-modèle de donnéesLog data anti-pattern

En règle générale, vous devez utiliser le stockage Blob plutôt que le stockage Table pour stocker les données du journal.Typically, you should use Blob storage instead of Table storage to store log data.

Contexte et problèmeContext and problem

Un cas d’usage courant pour les données de journal consiste à récupérer une sélection d’entrées de journal pour une plage de dates/heures spécifique.A common use case for log data is to retrieve a selection of log entries for a specific date/time range. Par exemple, vous souhaitez rechercher tous les messages d’erreur et messages critiques enregistrés par votre application entre 15:04 et 15:06 à une date spécifique.For example, you want to find all the error and critical messages that your application logged between 15:04 and 15:06 on a specific date. Vous ne souhaitez pas utiliser la date et l’heure du message de journal pour déterminer la partition sur laquelle vous enregistrez les entités de journal.You don't want to use the date and time of the log message to determine the partition you save log entities to. Cela aboutit à une partition sensible, car à tout moment donné, toutes les entités du journal partagent la même valeur de PartitionKey (voir Ajouter un anti-modèle ou un préfixe d’anti-modèle).That results in a hot partition because at any particular time, all the log entities will share the same PartitionKey value (see the Prepend/append anti-pattern). Par exemple, le schéma d’entité suivant d’un message de journal génère une partition sensible, car l’application écrit tous les messages de journal sur la partition pour la date et l’heure actuelles :For example, the following entity schema for a log message results in a hot partition, because the application writes all log messages to the partition for the current date and hour:

Graphique montrant un schéma d’entité pour un message de journalisation qui aboutit à une partition sensible.

Dans cet exemple, la RowKey contient la date et l’heure du message de journal pour s’assurer que les messages du journal sont triés par ordre de date/heure.In this example, the RowKey includes the date and time of the log message to ensure that log messages are sorted in date/time order. La RowKey comprend également un ID de message, pour le cas où plusieurs messages de journal partageraient les mêmes date et heure.The RowKey also includes a message ID, in case multiple log messages share the same date and time.

Une autre approche consiste à utiliser une valeur de PartitionKey qui garantit que l’application écrit des messages dans une plage de partitions.Another approach is to use a PartitionKey that ensures that the application writes messages across a range of partitions. Par exemple, si la source du message de journal offre un moyen de distribuer les messages sur plusieurs partitions, vous pouvez utiliser le schéma d’entité suivant :For example, if the source of the log message provides a way to distribute messages across many partitions, you can use the following entity schema:

Graphique d’entité de message de journal

Toutefois, le problème avec ce schéma est que, pour récupérer tous les messages de journal pour un intervalle de temps spécifique, vous devez rechercher sur chaque partition dans la table.However, the problem with this schema is that to retrieve all the log messages for a specific time span, you must search every partition in the table.

SolutionSolution

La section précédente a présenté le problème posé par la tentative d’utilisation du stockage Table pour stocker des entrées de journal et a suggéré deux conceptions, peu satisfaisantes.The previous section highlighted the problem of trying to use Table storage to store log entries, and suggested two unsatisfactory designs. Une solution a conduit à une partition sensible, avec le risque de faibles performances d’écriture de messages de journal.One solution led to a hot partition with the risk of poor performance writing log messages. L’autre solution a entraîné des performances médiocres, en raison de la nécessité d’analyser chaque partition dans la table pour récupérer les messages du journal pour une période spécifique.The other solution resulted in poor query performance, because of the requirement to scan every partition in the table to retrieve log messages for a specific time span. Le stockage Blob offre une meilleure solution pour ce type de scénario. Voici comment Azure Storage Analytics stocke les données de journal collectées.Blob storage offers a better solution for this type of scenario, and this is how Azure Storage analytics stores the log data it collects.

Cette section décrit comment Storage Analytics stocke les données de journal dans le stockage Blob, en guise d’illustration de cette approche pour le stockage des données que vous interrogez généralement par plage.This section outlines how Storage analytics stores log data in Blob storage, as an illustration of this approach to storing data that you typically query by range.

Storage Analytics stocke les messages de journal dans un format délimité dans plusieurs objets blob.Storage analytics stores log messages in a delimited format in multiple blobs. Ce format facilite l'analyse des données du message de journalisation pour une application cliente.The delimited format makes it easy for a client application to parse the data in the log message.

Storage Analytics utilise une convention de nommage pour les objets blob qui vous permet de localiser le ou les objets blob contenant les messages de journal que vous recherchez.Storage analytics uses a naming convention for blobs that enables you to locate the blob (or blobs) that contain the log messages for which you are searching. Par exemple, un objet blob nommé « queue/2014/07/31/1800/000001.log » contient des messages de journal liés au service de File d’attente dont l’heure de début est à 18h00 le 31 juillet 2014.For example, a blob named "queue/2014/07/31/1800/000001.log" contains log messages that relate to the queue service for the hour starting at 18:00 on July 31, 2014. Le « 000001 » indique qu'il s'agit du premier fichier journal pour cette période.The "000001" indicates that this is the first log file for this period. Storage Analytics enregistre également les horodatages du premier et du dernier messages stockés dans le fichier dans le cadre des métadonnées de l’objet blob.Storage analytics also records the timestamps of the first and last log messages stored in the file, as part of the blob's metadata. L’API pour le stockage Blob vous permet de localiser des objets blob dans un conteneur en fonction d’un préfixe de nom.The API for Blob storage enables you locate blobs in a container based on a name prefix. Pour localiser tous les objets blob qui contiennent des données de journal de file d’attente pour l’heure commençant à 18:00, vous pouvez utiliser le préfixe « queue/2014/07/31/1800 ».To locate all the blobs that contain queue log data for the hour starting at 18:00, you can use the prefix "queue/2014/07/31/1800".

Storage Analytics met en mémoire tampon les messages de journal en interne, puis met à jour de façon périodique l’objet blob adéquat ou en crée un autre avec le dernier lot d’entrées de journal.Storage analytics buffers log messages internally, and then periodically updates the appropriate blob or creates a new one with the latest batch of log entries. Cela réduit le nombre d’écritures qu’il doit exécuter vers le stockage Blob.This reduces the number of writes it must perform to Blob storage.

Si vous implémentez une solution similaire dans votre propre application, réfléchissez à la manière de gérer le compromis entre la fiabilité, le coût et la scalabilité.If you're implementing a similar solution in your own application, consider how to manage the trade-off between reliability and cost and scalability. En d’autres termes, évaluez l’effet de l’écriture de chaque entrée de journal dans le stockage Blob, par rapport à la mise en mémoire tampon des mises à jour dans votre application et leur écriture dans le stockage Blob par lots.In other words, evaluate the effect of writing every log entry to Blob storage as it happens, compared to buffering updates in your application and writing them to Blob storage in batches.

Problèmes et considérationsIssues and considerations

Prenez en compte les points suivants lorsque vous décidez de la manière de stocker des données de journalisation :Consider the following points when deciding how to store log data:

  • Si vous créez une conception de table qui évite les risques de partitions sensibles, il est possible que l’accès aux données de journal ne soit pas très efficace.If you create a table design that avoids potential hot partitions, you might find that you can't access your log data efficiently.
  • Pour traiter les données de journalisation, un client doit souvent charger de nombreux enregistrements.To process log data, a client often needs to load many records.
  • Bien que les données de journal soient souvent structurées, le stockage Blob peut être une meilleure solution.Although log data is often structured, Blob storage might be a better solution.

Considérations relatives à l’implémentationImplementation considerations

Cette section décrit certaines des considérations à prendre en compte lorsque vous implémentez les modèles décrits dans les sections précédentes.This section discusses some of the considerations to bear in mind when you implement the patterns described in the previous sections. La plupart de cette section utilise des exemples rédigés en C#, ainsi que la bibliothèque cliente de stockage (version 4.3.0 au moment de la rédaction).Most of this section uses examples written in C# that use the Storage Client Library (version 4.3.0 at the time of writing).

Récupérer des entitésRetrieve entities

Comme indiqué dans la section Conception pour l’interrogation, la requête la plus efficace est une requête de pointage.As discussed in the section Design for querying, the most efficient query is a point query. Toutefois, dans certains scénarios vous devrez peut-être récupérer plusieurs entités.However, in some scenarios you might need to retrieve multiple entities. Cette section décrit certaines des approches courantes pour récupérer des entités à l’aide de la bibliothèque de client de stockage.This section describes some common approaches to retrieving entities by using the Storage Client Library.

Exécuter une requête de pointage à l’aide de la bibliothèque de client de stockageRun a point query by using the Storage Client Library

Le moyen le plus simple d’exécuter une requête de pointage est d’utiliser l’opération de table Retrieve.The easiest way to run a point query is to use the Retrieve table operation. Comme indiqué dans l’extrait de code C# suivant, cette opération récupère une entité avec une PartitionKey ayant la valeur « sales » et une RowKey ayant la valeur « 212 » :As shown in the following C# code snippet, this operation retrieves an entity with a PartitionKey of value "Sales", and a RowKey of value "212":

TableOperation retrieveOperation = TableOperation.Retrieve<EmployeeEntity>("Sales", "212");
var retrieveResult = employeeTable.Execute(retrieveOperation);
if (retrieveResult.Result != null)
{
    EmployeeEntity employee = (EmployeeEntity)retrieveResult.Result;
    ...
}  

Notez que cet exemple part du principe que l’entité récupérée doit être de type EmployeeEntity.Notice how this example expects the entity it retrieves to be of type EmployeeEntity.

Récupérer plusieurs entités à l’aide de LINQRetrieve multiple entities by using LINQ

Vous pouvez récupérer plusieurs entités à l’aide de LINQ avec la bibliothèque de client de stockage, en spécifiant une requête avec une clause where.You can retrieve multiple entities by using LINQ with Storage Client Library, and specifying a query with a where clause. Pour éviter une analyse de table, vous devez toujours inclure la valeur de PartitionKey dans la clause where, et si possible la valeur de RowKey afin d’éviter les analyses de table et de partition.To avoid a table scan, you should always include the PartitionKey value in the where clause, and if possible the RowKey value to avoid table and partition scans. Le stockage Table prend en charge un ensemble limité d’opérateurs de comparaison (supérieur à, supérieure ou égal à, inférieur ou égal à, égal, et différent de).Table storage supports a limited set of comparison operators (greater than, greater than or equal, less than, less than or equal, equal, and not equal) to use in the where clause. L’extrait de code C# suivant recherche tous les employés dont le nom commence par « B » (en supposant que la RowKey stocke le nom de famille) dans le service Sales (en supposant que la PartitionKey stocke le nom du service) :The following C# code snippet finds all the employees whose last name starts with "B" (assuming that the RowKey stores the last name) in the Sales department (assuming the PartitionKey stores the department name):

TableQuery<EmployeeEntity> employeeQuery = employeeTable.CreateQuery<EmployeeEntity>();
var query = (from employee in employeeQuery
            where employee.PartitionKey == "Sales" &&
            employee.RowKey.CompareTo("B") >= 0 &&
            employee.RowKey.CompareTo("C") < 0
            select employee).AsTableQuery();
var employees = query.Execute();  

Notez que la requête spécifie à la fois une RowKey et une PartitionKey pour garantir des performances optimales.Notice how the query specifies both a RowKey and a PartitionKey to ensure better performance.

L’exemple de code suivant montre une fonctionnalité équivalente faisant appel à l’API Fluent (pour plus d’informations sur cette API, consultez Bonnes pratiques pour la conception d’une API Fluent) :The following code sample shows equivalent functionality by using the fluent API (for more information about fluent APIs in general, see Best practices for designing a fluent API):

TableQuery<EmployeeEntity> employeeQuery = new TableQuery<EmployeeEntity>().Where(
    TableQuery.CombineFilters(
    TableQuery.CombineFilters(
        TableQuery.GenerateFilterCondition(
    "PartitionKey", QueryComparisons.Equal, "Sales"),
    TableOperators.And,
    TableQuery.GenerateFilterCondition(
    "RowKey", QueryComparisons.GreaterThanOrEqual, "B")
),
TableOperators.And,
TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.LessThan, "C")
    )
);
var employees = employeeTable.ExecuteQuery(employeeQuery);  

Nota

L’exemple imbrique plusieurs méthodes CombineFilters pour inclure les trois conditions de filtre.The sample nests multiple CombineFilters methods to include the three filter conditions.

Récupérer un grand nombre d’entités à partir d’une requêteRetrieve large numbers of entities from a query

Une requête optimale retourne une entité individuelle basée sur une valeur de PartitionKey et une valeur de RowKey.An optimal query returns an individual entity based on a PartitionKey value and a RowKey value. Toutefois, dans certains scénarios, vous pouvez être obligé de retourner de nombreuses entités à partir de la même partition ou même de plusieurs partitions.However, in some scenarios you might have a requirement to return many entities from the same partition, or even from many partitions. Vous devez toujours tester entièrement les performances de votre application dans de tels scénarios.You should always fully test the performance of your application in such scenarios.

Une requête sur le stockage Table peut retourner un maximum de 1000 entités à la fois, et s’exécuter pendant un maximum de cinq secondes.A query against Table storage can return a maximum of 1,000 entities at one time, and run for a maximum of five seconds. Le stockage Table retourne un jeton de continuation pour permettre à l’application cliente de demander le jeu d’entités suivant, si l’une des conditions suivantes est vraie :Table storage returns a continuation token to enable the client application to request the next set of entities, if any of the following are true:

  • Le jeu de résultats contient plus de 1000 entités.The result set contains more than 1,000 entities.
  • La requête ne s’est pas terminée dans les cinq secondes.The query didn't complete within five seconds.
  • La requête franchit les limites de la partition.The query crosses the partition boundary.

Pour plus d’informations sur le fonctionnement des jetons de continuation, consultez Délai de requête et pagination.For more information about how continuation tokens work, see Query timeout and pagination.

Si vous utilisez la bibliothèque de client de stockage, celle-ci peut gérer automatiquement les jetons de continuation pour vous lors du retour des entités à partir du stockage Table.If you're using the Storage Client Library, it can automatically handle continuation tokens for you as it returns entities from Table storage. Par exemple, le code C# suivant gère automatiquement les jetons de continuation si le stockage Table les retourne dans une réponse :For example, the following C# code sample automatically handles continuation tokens if Table storage returns them in a response:

string filter = TableQuery.GenerateFilterCondition(
        "PartitionKey", QueryComparisons.Equal, "Sales");
TableQuery<EmployeeEntity> employeeQuery =
        new TableQuery<EmployeeEntity>().Where(filter);

var employees = employeeTable.ExecuteQuery(employeeQuery);
foreach (var emp in employees)
{
        ...
}  

Le code C# suivant gère les jetons de continuation de manière explicite :The following C# code handles continuation tokens explicitly:

string filter = TableQuery.GenerateFilterCondition(
        "PartitionKey", QueryComparisons.Equal, "Sales");
TableQuery<EmployeeEntity> employeeQuery =
        new TableQuery<EmployeeEntity>().Where(filter);

TableContinuationToken continuationToken = null;

do
{
        var employees = employeeTable.ExecuteQuerySegmented(
        employeeQuery, continuationToken);
    foreach (var emp in employees)
    {
    ...
    }
    continuationToken = employees.ContinuationToken;
} while (continuationToken != null);  

En utilisant des jetons de continuation de manière explicite, vous pouvez contrôler le moment où votre application extrait le segment suivant des données.By using continuation tokens explicitly, you can control when your application retrieves the next segment of data. Par exemple, si votre application cliente permet aux utilisateurs de parcourir les entités stockées dans une table, un utilisateur peut décider de ne pas parcourir toutes les entités récupérées par la requête.For example, if your client application enables users to page through the entities stored in a table, a user might decide not to page through all the entities retrieved by the query. Votre application utiliserait uniquement un jeton de continuation pour récupérer le segment suivant quand l’utilisateur aurait terminé de parcourir toutes les entités du segment actuel.Your application would only use a continuation token to retrieve the next segment when the user had finished paging through all the entities in the current segment. Cette approche présente plusieurs avantages :This approach has several benefits:

  • Vous pouvez limiter la quantité de données à récupérer à partir du stockage Table et que vous placez sur le réseau.You can limit the amount of data to retrieve from Table storage and that you move over the network.
  • Vous pouvez effectuer des E/S asynchrones dans .NET.You can perform asynchronous I/O in .NET.
  • Vous pouvez sérialiser le jeton de continuation dans un stockage permanent, afin de pouvoir continuer même si l’application se plante.You can serialize the continuation token to persistent storage, so you can continue in the event of an application crash.

Nota

En général, un jeton de continuation retourne un segment contenant 1000 entités, bien qu’il puisse y en avoir moins.A continuation token typically returns a segment containing 1,000 entities, although it can contain fewer. C’est également le cas si vous limitez le nombre d’entrées retournées par une requête à l’aide de Take pour retourner les n premières entités qui correspondent à vos critères de recherche.This is also the case if you limit the number of entries a query returns by using Take to return the first n entities that match your lookup criteria. Le stockage Table peut retourner un segment contenant moins de n entités, ainsi qu’un jeton de continuation pour vous permettre de récupérer les entités restantes.Table storage might return a segment containing fewer than n entities, along with a continuation token to enable you to retrieve the remaining entities.

Le code C# suivant montre comment modifier le nombre d'entités renvoyées à l'intérieur d'un segment :The following C# code shows how to modify the number of entities returned inside a segment:

employeeQuery.TakeCount = 50;  

Projection côté serveurServer-side projection

Une seule entité peut avoir jusqu'à 255 propriétés et une taille allant jusqu'à 1 Mo.A single entity can have up to 255 properties and be up to 1 MB in size. Quand vous interrogez la table et récupérez des entités, il est possible que vous n’ayez pas besoin de toutes les propriétés et que vous puissiez éviter de transférer des données quand ça n’est pas nécessaire (ce qui permet de réduire la latence et les coûts).When you query the table and retrieve entities, you might not need all the properties, and can avoid transferring data unnecessarily (to help reduce latency and cost). Vous pouvez utiliser la projection côté serveur pour transférer uniquement les propriétés que vous avez besoin.You can use server-side projection to transfer just the properties you need. L’exemple suivant récupère uniquement la propriété Email (avec les valeurs de PartitionKey, RowKey, Timestamp et ETag) à partir des entités sélectionnées par la requête.The following example retrieves just the Email property (along with PartitionKey, RowKey, Timestamp, and ETag) from the entities selected by the query.

string filter = TableQuery.GenerateFilterCondition(
        "PartitionKey", QueryComparisons.Equal, "Sales");
List<string> columns = new List<string>() { "Email" };
TableQuery<EmployeeEntity> employeeQuery =
        new TableQuery<EmployeeEntity>().Where(filter).Select(columns);

var entities = employeeTable.ExecuteQuery(employeeQuery);
foreach (var e in entities)
{
        Console.WriteLine("RowKey: {0}, EmployeeEmail: {1}", e.RowKey, e.Email);
}  

Notez que la valeur de RowKey est disponible même si elle ne figure pas dans la liste de propriétés à récupérer.Notice how the RowKey value is available even though it isn't included in the list of properties to retrieve.

Modifier des entitésModify entities

La bibliothèque de client de stockage vous permet de modifier les entités stockées dans le stockage Table pour les insérer, les supprimer et les mettre à jour.The Storage Client Library enables you to modify your entities stored in Table storage by inserting, deleting, and updating entities. Vous pouvez utiliser des EGT pour traiter par lots plusieurs opérations d’insertion, mise à jour et suppression, afin de réduire le nombre d’allers-retours requis et d’améliorer les performances de votre solution.You can use EGTs to batch multiple inserts, update, and delete operations together, to reduce the number of round trips required and improve the performance of your solution.

Les exceptions levées quand la bibliothèque de client de stockage exécute une EGT incluent généralement l’index de l’entité qui a provoqué l’échec du lot.Exceptions thrown when the Storage Client Library runs an EGT typically include the index of the entity that caused the batch to fail. Cela est utile lorsque vous déboguez du code qui utilise des EGT.This is helpful when you are debugging code that uses EGTs.

Nous vous conseillons de réfléchir également à la façon dont votre conception affecte la méthode de votre application cliente pour gérer les opérations d'accès concurrentiel et de mises à jour.You should also consider how your design affects how your client application handles concurrency and update operations.

Gérer l'accès concurrentielManaging concurrency

Par défaut, le stockage Table implémente des contrôles d’accès concurrentiel optimiste au niveau des entités individuelles pour les opérations d’insertion, de fusion et de suppression, bien qu’il soit possible pour un client de forcer le stockage Table à ignorer ces contrôles.By default, Table storage implements optimistic concurrency checks at the level of individual entities for insert, merge, and delete operations, although it's possible for a client to force Table storage to bypass these checks. Pour plus d’informations, consultez Gestion de l’accès concurrentiel dans Microsoft Azure Storage.For more information, see Managing concurrency in Microsoft Azure Storage.

Fusion ou remplacementMerge or replace

La méthode Replace de la classe TableOperation remplace toujours l’entité complète dans le stockage Table.The Replace method of the TableOperation class always replaces the complete entity in Table storage. Si vous n’incluez pas une propriété dans la requête quand cette propriété existe dans l’entité stockée, la requête supprime cette propriété de l’entité stockée.If you don't include a property in the request when that property exists in the stored entity, the request removes that property from the stored entity. Si vous ne souhaitez pas supprimer une propriété explicitement à partir d'une entité stockée, vous devez inclure chaque propriété dans la demande.Unless you want to remove a property explicitly from a stored entity, you must include every property in the request.

Vous pouvez utiliser la méthode Merge de la classe TableOperation pour réduire la quantité de données que vous envoyez au stockage Table quand vous souhaitez mettre à jour une entité.You can use the Merge method of the TableOperation class to reduce the amount of data that you send to Table storage when you want to update an entity. La méthode Merge remplace toutes les propriétés de l’entité stockée par des valeurs de propriété de l’entité incluse dans la requête.The Merge method replaces any properties in the stored entity with property values from the entity included in the request. Cette méthode laisse intactes toutes les propriétés de l’entité stockée qui ne sont pas incluses dans la requête.This method leaves intact any properties in the stored entity that aren't included in the request. Cela est utile si vous avez des entités volumineuses et que vous avez seulement besoin de mettre à jour un petit nombre de propriétés dans une requête.This is useful if you have large entities, and only need to update a small number of properties in a request.

Nota

Les méthodes *Replace et Merge échouent si l’entité n’existe pas.The *Replace and Merge methods fail if the entity doesn't exist. En guise d’alternative, vous pouvez utiliser les méthodes InsertOrReplaceet InsertOrMerge, qui créent une entité si elle n’existe pas.As an alternative, you can use the InsertOrReplace and InsertOrMerge methods that create a new entity if it doesn't exist.

Utiliser des types d’entités hétérogènesWork with heterogeneous entity types

Le stockage Table est un magasin de tables sans schéma.Table storage is a schema-less table store. Cela signifie qu’une table peut stocker des entités de plusieurs types afin d’améliorer la flexibilité de votre conception.That means that a single table can store entities of multiple types, providing great flexibility in your design. L'exemple suivant présente une table qui stocke les entités de service et d'employé :The following example illustrates a table storing both employee and department entities:

PartitionKeyPartitionKey RowKeyRowKey TimestampTimestamp
FirstNameFirstName LastNameLastName AgeAge E-mailEmail
FirstNameFirstName LastNameLastName AgeAge E-mailEmail
DepartmentNameDepartmentName EmployeeCountEmployeeCount
FirstNameFirstName LastNameLastName AgeAge E-mailEmail

Chaque entité doit toujours avoir des valeurs PartitionKey, RowKey et Timestamp, mais elle peut avoir n’importe quel ensemble de propriétés.Each entity must still have PartitionKey, RowKey, and Timestamp values, but can have any set of properties. De plus, il n’y a rien pour indiquer le type d’une entité, sauf si vous choisissez de stocker cette information quelque part.Furthermore, there's nothing to indicate the type of an entity unless you choose to store that information somewhere. Il existe deux options pour identifier le type d'une entité :There are two options for identifying the entity type:

  • Ajout d’un préfixe de type d’entité à la RowKey (ou éventuellement à la PartitionKey).Prepend the entity type to the RowKey (or possibly the PartitionKey). Par exemple, EMPLOYEE_000123 ou DEPARTMENT_SALES comme valeurs de RowKey.For example, EMPLOYEE_000123 or DEPARTMENT_SALES as RowKey values.
  • Utilisation d’une propriété distincte pour enregistrer le type d’entité, comme indiqué dans le tableau ci-dessous.Use a separate property to record the entity type, as shown in the following table.
PartitionKeyPartitionKey RowKeyRowKey TimestampTimestamp
EntityTypeEntityType FirstNameFirstName LastNameLastName AgeAge E-mailEmail
EmployeeEmployee
EntityTypeEntityType FirstNameFirstName LastNameLastName AgeAge E-mailEmail
EmployeeEmployee
EntityTypeEntityType DepartmentNameDepartmentName EmployeeCountEmployeeCount
departmentDepartment
EntityTypeEntityType FirstNameFirstName LastNameLastName AgeAge E-mailEmail
EmployeeEmployee

La première option, qui consiste à ajouter un préfixe de type d’entité à la RowKey, est utile au cas où deux entités de types différents se retrouvent avec la même valeur de clé.The first option, prepending the entity type to the RowKey, is useful if there is a possibility that two entities of different types might have the same key value. Il regroupe également les entités du même type dans la partition.It also groups entities of the same type together in the partition.

Les techniques abordées dans cette section s’appliquent particulièrement à la discussion sur les relations d’héritage.The techniques discussed in this section are especially relevant to the discussion aboutInheritance relationships.

Nota

Pensez à inclure un numéro de version dans la valeur de type d’entité, pour permettre aux applications clientes de faire évoluer des objets POCO et de fonctionner avec différentes versions.Consider including a version number in the entity type value, to enable client applications to evolve POCO objects and work with different versions.

Le reste de cette section décrit certaines des fonctionnalités de la bibliothèque cliente de stockage qui facilitent l'utilisation de plusieurs types d'entités dans la même table.The remainder of this section describes some of the features in the Storage Client Library that facilitate working with multiple entity types in the same table.

Récupérer des types d’entités hétérogènesRetrieve heterogeneous entity types

Si vous utilisez la bibliothèque de client de stockage, vous avez trois options pour travailler avec plusieurs types d’entité.If you're using the Storage Client Library, you have three options for working with multiple entity types.

Si vous connaissez le type de l’entité stockée avec des valeurs RowKey et PartitionKey spécifiques, vous pouvez spécifier le type d’entité quand vous récupérez l’entité.If you know the type of the entity stored with specific RowKey and PartitionKey values, then you can specify the entity type when you retrieve the entity. Vous avez vu cela dans les deux exemples précédents qui récupèrent les entités de type EmployeeEntity : Exécuter une requête de pointage à l’aide de la bibliothèque de client de stockage et Récupérer plusieurs entités à l’aide de LINQ.You saw this in the previous two examples that retrieve entities of type EmployeeEntity: Run a point query by using the Storage Client Library and Retrieve multiple entities by using LINQ.

La deuxième option consiste à utiliser le type DynamicTableEntity (un conteneur de propriétés) au lieu d’un type d’entité POCO concret.The second option is to use the DynamicTableEntity type (a property bag), instead of a concrete POCO entity type. Cette option peut également améliorer les performances, car il n’est pas nécessaire de sérialiser et de désérialiser l’entité en types .NET.This option might also improve performance, because there's no need to serialize and deserialize the entity to .NET types. Le code C# suivant récupère plusieurs entités de types différents à partir de la table, mais retourne toutes les entités en tant qu’instances de DynamicTableEntity.The following C# code potentially retrieves multiple entities of different types from the table, but returns all entities as DynamicTableEntity instances. Il utilise ensuite la propriété EntityType pour déterminer le type de chaque entité :It then uses the EntityType property to determine the type of each entity:

string filter = TableQuery.CombineFilters(
    TableQuery.GenerateFilterCondition("PartitionKey",
    QueryComparisons.Equal, "Sales"),
    TableOperators.And,
    TableQuery.CombineFilters(
    TableQuery.GenerateFilterCondition("RowKey",
                    QueryComparisons.GreaterThanOrEqual, "B"),
        TableOperators.And,
        TableQuery.GenerateFilterCondition("RowKey",
        QueryComparisons.LessThan, "F")
    )
);
TableQuery<DynamicTableEntity> entityQuery =
    new TableQuery<DynamicTableEntity>().Where(filter);
var employees = employeeTable.ExecuteQuery(entityQuery);

IEnumerable<DynamicTableEntity> entities = employeeTable.ExecuteQuery(entityQuery);
foreach (var e in entities)
{
EntityProperty entityTypeProperty;
if (e.Properties.TryGetValue("EntityType", out entityTypeProperty))
{
    if (entityTypeProperty.StringValue == "Employee")
    {
        // Use entityTypeProperty, RowKey, PartitionKey, Etag, and Timestamp
        }
    }
}  

Pour récupérer d’autres propriétés, vous devez utiliser la méthode TryGetValue sur la propriété Properties de la classe DynamicTableEntity.To retrieve other properties, you must use the TryGetValue method on the Properties property of the DynamicTableEntity class.

Une troisième option consiste à combiner l’utilisation du type DynamicTableEntity et d’une instance EntityResolver.A third option is to combine using the DynamicTableEntity type and an EntityResolver instance. Cela vous permet de résoudre plusieurs types POCO dans la même requête.This enables you to resolve to multiple POCO types in the same query. Dans cet exemple, le délégué EntityResolver utilise la propriété EntityType pour faire la distinction entre les deux types d’entité retournés par la requête.In this example, the EntityResolver delegate is using the EntityType property to distinguish between the two types of entity that the query returns. La méthode Resolve utilise le délégué resolver pour résoudre les instances DynamicTableEntity en instances TableEntity.The Resolve method uses the resolver delegate to resolve DynamicTableEntity instances to TableEntity instances.

EntityResolver<TableEntity> resolver = (pk, rk, ts, props, etag) =>
{

        TableEntity resolvedEntity = null;
        if (props["EntityType"].StringValue == "Department")
        {
        resolvedEntity = new DepartmentEntity();
        }
        else if (props["EntityType"].StringValue == "Employee")
        {
        resolvedEntity = new EmployeeEntity();
        }
        else throw new ArgumentException("Unrecognized entity", "props");

        resolvedEntity.PartitionKey = pk;
        resolvedEntity.RowKey = rk;
        resolvedEntity.Timestamp = ts;
        resolvedEntity.ETag = etag;
        resolvedEntity.ReadEntity(props, null);
        return resolvedEntity;
};

string filter = TableQuery.GenerateFilterCondition(
        "PartitionKey", QueryComparisons.Equal, "Sales");
TableQuery<DynamicTableEntity> entityQuery =
        new TableQuery<DynamicTableEntity>().Where(filter);

var entities = employeeTable.ExecuteQuery(entityQuery, resolver);
foreach (var e in entities)
{
        if (e is DepartmentEntity)
        {
    ...
        }
        if (e is EmployeeEntity)
        {
    ...
        }
}  

Modifier des types d’entités hétérogènesModify heterogeneous entity types

Vous n’avez pas besoin de connaître le type d’une entité pour la supprimer, et vous connaissez toujours le type d’une entité quand vous l’insérez.You don't need to know the type of an entity to delete it, and you always know the type of an entity when you insert it. Toutefois, vous pouvez utiliser le type DynamicTableEntity pour mettre à jour une entité sans connaître son type et sans utiliser de classe d’entité POCO.However, you can use the DynamicTableEntity type to update an entity without knowing its type, and without using a POCO entity class. L’exemple de code suivant récupère une entité unique et vérifie que la propriété EmployeeCount existe avant de la mettre à jour.The following code sample retrieves a single entity, and checks that the EmployeeCount property exists before updating it.

TableResult result =
        employeeTable.Execute(TableOperation.Retrieve(partitionKey, rowKey));
DynamicTableEntity department = (DynamicTableEntity)result.Result;

EntityProperty countProperty;

if (!department.Properties.TryGetValue("EmployeeCount", out countProperty))
{
        throw new
        InvalidOperationException("Invalid entity, EmployeeCount property not found.");
}
countProperty.Int32Value += 1;
employeeTable.Execute(TableOperation.Merge(department));  

Contrôler l’accès avec des signatures d’accès partagéControl access with shared access signatures

Vous pouvez utiliser des signature d’accès partagé (SAS) pour permettre aux applications clientes de modifier (et d’interroger) des entités de table directement, sans avoir besoin de s’authentifier directement auprès du stockage Table.You can use shared access signature (SAS) tokens to enable client applications to modify (and query) table entities directly, without the need to authenticate directly with Table storage. En règle générale, il existe trois principaux avantages à l'utilisation de SAP dans votre application :Typically, there are three main benefits to using SAS in your application:

  • Vous n’avez pas besoin de distribuer votre clé de compte de stockage sur une plateforme non sécurisée (par exemple un appareil mobile) pour permettre à cet appareil d’accéder à des entités dans le stockage Table et de les modifier.You don't need to distribute your storage account key to an insecure platform (such as a mobile device) in order to allow that device to access and modify entities in Table storage.
  • Vous pouvez décharger une partie du travail effectué par les rôles web et de travail dans la gestion de vos entités.You can offload some of the work that web and worker roles perform in managing your entities. Vous pouvez décharger ce travail à des appareils clients tels que les appareils mobiles et les ordinateurs des utilisateurs finaux.You can offload to client devices such as end-user computers and mobile devices.
  • Vous pouvez affecter un ensemble d’autorisations contraintes et limitées dans le temps à un client (par exemple pour autoriser l’accès en lecture seule à des ressources spécifiques).You can assign a constrained and time-limited set of permissions to a client (such as allowing read-only access to specific resources).

Pour plus d’informations sur l’utilisation de jetons SAS avec le stockage Table, consultez Utilisation des signatures d’accès partagé (SAS).For more information about using SAS tokens with Table storage, see Using shared access signatures (SAS).

Toutefois, vous devez toujours générer les jetons SAS qui accordent à une application cliente l’accès aux entités dans le stockage Table.However, you must still generate the SAS tokens that grant a client application to the entities in Table storage. Vous devez le faire dans un environnement qui dispose d’un accès sécurisé à vos clés de compte de stockage.Do this in an environment that has secure access to your storage account keys. En règle générale, vous utilisez un rôle web ou de travail pour générer les jetons SAP et les transmettre vers les applications clientes qui ont besoin d'accéder à vos entités.Typically, you use a web or worker role to generate the SAS tokens and deliver them to the client applications that need access to your entities. Comme il existe toujours une surcharge impliquée dans la génération et l'envoi de jetons SAP aux clients, vous devez envisager la meilleure méthode pour réduire cette surcharge, en particulier dans les scénarios à volumes élevés.Because there is still an overhead involved in generating and delivering SAS tokens to clients, you should consider how best to reduce this overhead, especially in high-volume scenarios.

Il est possible de générer un jeton SAS qui accorde l’accès à un sous-ensemble d’entités dans une table.It's possible to generate a SAS token that grants access to a subset of the entities in a table. Par défaut, vous créez un jeton SAS pour une table entière.By default, you create a SAS token for an entire table. Toutefois, il est également possible de spécifier que le jeton SAS accorde l’accès à une plage de valeurs PartitionKey, ou à une plage de valeurs PartitionKey et RowKey.But it's also possible to specify that the SAS token grant access to either a range of PartitionKey values, or a range of PartitionKey and RowKey values. Vous pouvez choisir de générer des jetons SAS pour des utilisateurs spécifiques de votre système, de sorte que chaque jeton SAS d’un utilisateur lui permette uniquement d’accéder à ses propres entités dans le stockage Table.You might choose to generate SAS tokens for individual users of your system, such that each user's SAS token only allows them access to their own entities in Table storage.

Opérations asynchrones et parallèlesAsynchronous and parallel operations

Si vous effectuez la diffusion de vos demandes sur plusieurs partitions, vous pouvez améliorer le débit et la réactivité du client en utilisant des requêtes asynchrones ou parallèles.Provided you are spreading your requests across multiple partitions, you can improve throughput and client responsiveness by using asynchronous or parallel queries. Par exemple, vous pouvez avoir plusieurs instances de rôle de travail accédant à vos tables en parallèle.For example, you might have two or more worker role instances accessing your tables in parallel. Vous pouvez avoir des rôles de travail responsables d’ensembles particuliers de partitions, ou simplement plusieurs instances de rôle de travail, chacune étant en mesure d’accéder à toutes les partitions d’une table.You can have individual worker roles responsible for particular sets of partitions, or simply have multiple worker role instances, each able to access all the partitions in a table.

Dans une instance cliente, vous pouvez améliorer le débit en exécutant des opérations de stockage en mode asynchrone.Within a client instance, you can improve throughput by running storage operations asynchronously. La bibliothèque cliente de stockage facilite l'écriture des modifications et des requêtes asynchrones.The Storage Client Library makes it easy to write asynchronous queries and modifications. Par exemple, vous pouvez commencer avec la méthode synchrone qui récupère toutes les entités d’une partition, comme illustré dans le code C# suivant :For example, you might start with the synchronous method that retrieves all the entities in a partition, as shown in the following C# code:

private static void ManyEntitiesQuery(CloudTable employeeTable, string department)
{
        string filter = TableQuery.GenerateFilterCondition(
        "PartitionKey", QueryComparisons.Equal, department);
        TableQuery<EmployeeEntity> employeeQuery =
        new TableQuery<EmployeeEntity>().Where(filter);

        TableContinuationToken continuationToken = null;

        do
        {
        var employees = employeeTable.ExecuteQuerySegmented(
                employeeQuery, continuationToken);
        foreach (var emp in employees)
    {
        ...
    }
        continuationToken = employees.ContinuationToken;
        } while (continuationToken != null);
}  

Vous pouvez facilement modifier ce code afin que la requête s’exécute de façon asynchrone, comme suit :You can easily modify this code so that the query runs asynchronously, as follows:

private static async Task ManyEntitiesQueryAsync(CloudTable employeeTable, string department)
{
        string filter = TableQuery.GenerateFilterCondition(
        "PartitionKey", QueryComparisons.Equal, department);
        TableQuery<EmployeeEntity> employeeQuery =
        new TableQuery<EmployeeEntity>().Where(filter);
        TableContinuationToken continuationToken = null;

        do
        {
        var employees = await employeeTable.ExecuteQuerySegmentedAsync(
                employeeQuery, continuationToken);
        foreach (var emp in employees)
        {
            ...
        }
        continuationToken = employees.ContinuationToken;
            } while (continuationToken != null);
}  

Dans cet exemple asynchrone, vous pouvez voir les modifications suivantes par rapport à la version synchrone :In this asynchronous example, you can see the following changes from the synchronous version:

  • La signature de méthode inclut désormais le modificateur async et retourne une instance Task.The method signature now includes the async modifier, and returns a Task instance.
  • Au lieu d’appeler la méthode ExecuteSegmented pour récupérer les résultats, la méthode appelle maintenant la méthode ExecuteSegmentedAsync.Instead of calling the ExecuteSegmented method to retrieve results, the method now calls the ExecuteSegmentedAsync method. La méthode utilise le modificateur await pour récupérer les résultats de façon asynchrone.The method uses the await modifier to retrieve results asynchronously.

L’application cliente peut appeler cette méthode plusieurs fois, avec des valeurs différentes pour le paramètre department.The client application can call this method multiple times, with different values for the department parameter. Chaque requête s’exécute sur un thread distinct.Each query runs on a separate thread.

Il n’existe aucune version asynchrone de la méthode Execute dans la classe TableQuery, car l’interface IEnumerable ne prend pas en charge l’énumération asynchrone.There is no asynchronous version of the Execute method in the TableQuery class, because the IEnumerable interface doesn't support asynchronous enumeration.

Vous pouvez également insérer, mettre à jour et supprimer des entités de façon asynchrone.You can also insert, update, and delete entities asynchronously. L'exemple C# suivant indique une méthode simple et synchrone pour insérer ou remplacer une entité d'employé :The following C# example shows a simple, synchronous method to insert or replace an employee entity:

private static void SimpleEmployeeUpsert(CloudTable employeeTable,
        EmployeeEntity employee)
{
        TableResult result = employeeTable
        .Execute(TableOperation.InsertOrReplace(employee));
        Console.WriteLine("HTTP Status: {0}", result.HttpStatusCode);
}  

Vous pouvez facilement modifier ce code pour que la mise à jour s’exécute de façon asynchrone, comme suit :You can easily modify this code so that the update runs asynchronously, as follows:

private static async Task SimpleEmployeeUpsertAsync(CloudTable employeeTable,
        EmployeeEntity employee)
{
        TableResult result = await employeeTable
        .ExecuteAsync(TableOperation.InsertOrReplace(employee));
        Console.WriteLine("HTTP Status: {0}", result.HttpStatusCode);
}  

Dans cet exemple asynchrone, vous pouvez voir les modifications suivantes par rapport à la version synchrone :In this asynchronous example, you can see the following changes from the synchronous version:

  • La signature de méthode inclut désormais le modificateur async et retourne une instance Task.The method signature now includes the async modifier, and returns a Task instance.
  • Au lieu d’appeler la méthode Execute pour mettre à jour l’entité, la méthode appelle maintenant la méthode ExecuteAsync.Instead of calling the Execute method to update the entity, the method now calls the ExecuteAsync method. La méthode utilise le modificateur await pour récupérer les résultats de façon asynchrone.The method uses the await modifier to retrieve results asynchronously.

L’application cliente peut appeler plusieurs méthodes asynchrones comme celle-ci, et chaque appel de méthode s’exécute sur un thread distinct.The client application can call multiple asynchronous methods like this one, and each method invocation runs on a separate thread.