Guida alla progettazione della tabella di archiviazione di Azure: Progettazione scalabile e Tabelle ad alte prestazioni Azure Storage Table Design Guide: Designing Scalable and Performant Tables

Suggerimento

Il contenuto in questo articolo si applica all'archivio tabelle originale di Azure.The content in this article applies to the original Azure Table storage. Tuttavia, è ora disponibile un'offerta Premium per l'archivio tabelle, l'API Tabelle di Azure Cosmos DB che include tabelle con ottimizzazione per la velocità effettiva, distribuzione globale e indici secondari automatici.However, there is now a premium offering for table storage, the Azure Cosmos DB Table API that offers throughput-optimized tables, global distribution, and automatic secondary indexes. Per altre informazioni e per provare l'esperienza Premium, vedere l'articolo relativo all'API Tabelle di Azure Cosmos DB.To learn more and try out the premium experience, please check out Azure Cosmos DB Table API.

Per progettare tabelle scalabili ed efficienti, è necessario tenere in considerazione diversi fattori, come le prestazioni, la scalabilità e il costo.To design scalable and performant tables you must consider a number of factors such as performance, scalability, and cost. Se in precedenza si sono progettati schemi per i database relazionali, queste considerazioni saranno già state fatte, ma, pur essendoci alcune somiglianze tra il modello di archiviazione del servizio tabelle di Azure e i modelli relazionali, esistono anche molte importanti differenze.If you have previously designed schemas for relational databases, these considerations will be familiar to you, but while there are some similarities between the Azure Table service storage model and relational models, there are also many important differences. Queste differenze in genere danno origine a progettazioni molto diverse che potrebbero sembrare poco plausibili o sbagliate a chi ha familiarità con i database relazionali, ma che invece hanno perfettamente senso se la progettazione è finalizzata a un archivio di chiavi/valori NoSQL, come il servizio tabelle di Azure.These differences typically lead to very different designs that may look counter-intuitive or wrong to someone familiar with relational databases, but which do make good sense if you are designing for a NoSQL key/value store such as the Azure Table service. Molte differenze di progettazione rispecchieranno il fatto che il servizio tabelle è progettato per supportare applicazioni con scalabilità cloud che possono contenere miliardi di entità (dette righe nella terminologia dei database relazionali) di dati o per set di dati che devono supportare volumi di transazioni molto elevati: quindi è necessario pensare in modo diverso all'archiviazione dei dati e conoscere il funzionamento del servizio tabelle.Many of your design differences will reflect the fact that the Table service 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 very high transaction volumes: therefore, you need to think differently about how you store your data and understand how the Table service works. Un archivio dati NoSQL ben progettato offre alla soluzione una scalabilità decisamente più elevata (e a un costo inferiore) rispetto a una soluzione che usa un database relazionale.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. Questa guida illustra proprio questi argomenti.This guide helps you with these topics.

Informazioni sul servizio tabelle di AzureAbout the Azure Table service

Questa sezione evidenzia alcune funzionalità chiave del servizio tabelle, di particolare importanza per la progettazione a livello di prestazioni e scalabilità.This section highlights some of the key features of the Table service that are especially relevant to designing for performance and scalability. Se non si ha familiarità con Archiviazione di Azure e con il servizio tabelle, prima di proseguire con la lettura di questo articolo, vedere Introduzione ad Archiviazione di Microsoft Azure e Introduzione all'archivio tabelle di Azure con .NET.If you are new to Azure Storage and the Table service, first read Introduction to Microsoft Azure Storage and Get started with Azure Table Storage using .NET before reading the remainder of this article. Anche se l'argomento principale di questa guida è il servizio tabelle, sono incluse alcune informazioni sui servizi di accodamento e BLOB di Azure e su come sia possibile usarli con il servizio tabelle in una soluzione.Although the focus of this guide is on the Table service, it will include some discussion of the Azure Queue and Blob services, and how you might use them along with the Table service in a solution.

Cos'è il servizio tabelle?What is the Table service? Come indica il nome stesso, il servizio tabelle usa un formato tabulare per archiviare i dati.As you might expect from the name, the Table service uses a tabular format to store data. In base alla terminologia standard, ogni riga della tabella rappresenta un'entità le cui diverse proprietà sono archiviate nelle colonne.In the standard terminology, each row of the table represents an entity, and the columns store the various properties of that entity. Ogni entità ha una coppia di chiavi che la identificano in modo univoco e una colonna di tipo timestamp usata dal servizio tabelle per tenere traccia dell'ultimo aggiornamento dell'entità. Questa operazione è automatica e non è possibile sovrascrivere manualmente il timestamp con un valore arbitrario.Every entity has a pair of keys to uniquely identify it, and a timestamp column that the Table service uses to track when the entity was last updated (this happens automatically and you cannot manually overwrite the timestamp with an arbitrary value). Il servizio tabelle usa il timestamp dell’ultima modifica (LMT, Last Modified Timestamp) per gestire la concorrenza ottimistica.The Table service uses this last-modified timestamp (LMT) to manage optimistic concurrency.

Nota

Le operazioni API REST del servizio tabelle restituiscono anche un valore ETag derivato dal timestamp LMT.The Table service REST API operations also return an ETag value that it derives from the last-modified timestamp (LMT). In questo documento i termini ETag ed LMT verranno usati in modo intercambiabile perché si riferiscono agli stessi dati sottostanti.In this document we will use the terms ETag and LMT interchangeably because they refer to the same underlying data.

L'esempio seguente mostra la progettazione di una semplice tabella in cui archiviare le entità dei dipendenti e dei reparti.The following example shows a simple table design to store employee and department entities. Molti degli esempi illustrati più avanti in questa guida si basano su questo tipo di progettazione semplice.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 EmailEmail
DonDon HallHall 3434 donh@contoso.com
MarketingMarketing 0000200002 2014-08-22T00:50:34Z2014-08-22T00:50:34Z
FirstNameFirstName LastNameLastName AgeAge EmailEmail
JunJun CaoCao 4747 junc@contoso.com
MarketingMarketing departmentDepartment 2014-08-22T00:50:30Z2014-08-22T00:50:30Z
DepartmentNameDepartmentName EmployeeCountEmployeeCount
MarketingMarketing 153153
SalesSales 0001000010 2014-08-22T00:50:44Z2014-08-22T00:50:44Z
FirstNameFirstName LastNameLastName AgeAge EmailEmail
KenKen KwokKwok 2323 kenk@contoso.com

Per il momento, sembra molto simile a una tabella di un database relazionale. Le principali differenze sono le colonne obbligatorie e la possibilità di archiviare più tipi di entità nella stessa tabella.So far, this looks very similar to a table in a relational database with the key differences being the mandatory columns, and the ability to store multiple entity types in the same table. Inoltre ogni proprietà definita dall'utente, come FirstNameo Age ha un tipo di dati, ad esempio numero intero o stringa, proprio come una colonna in un database relazionale.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. Anche se diversamente da un database relazionale, essendo il servizio tabelle privo di schema, una proprietà non deve avere lo stesso tipo di dati in ogni entità.Although unlike in a relational database, the schema-less nature of the Table service means that a property need not have the same data type on each entity. Per archiviare tipi di dati complessi in una sola proprietà, è necessario usare un formato serializzato come JSON o XML.To store complex data types in a single property, you must use a serialized format such as JSON or XML. Per altre informazioni sul servizio tabelle, ad esempio sui tipi di dati supportati, sugli intervalli di date supportate, sulle regole di denominazione e sui limiti di dimensioni, vedere Understanding the Table Service Data Model (Informazioni sul modello di dati del servizio tabelle).For more information about the table service such as supported data types, supported date ranges, naming rules, and size constraints, see Understanding the Table Service Data Model.

Come si vedrà, la scelta di PartitionKey e RowKey è fondamentale per la progettazione ottimale di una tabella.As you will see, your choice of PartitionKey and RowKey is fundamental to good table design. Ogni entità archiviata in una tabella deve avere una combinazione univoca di PartitionKey e RowKey.Every entity stored in a table must have a unique combination of PartitionKey and RowKey. Come le chiavi in una tabella di database relazionale, i valori diPartitionKey e RowKey vengono indicizzati per creare un indice cluster che consenta di eseguire ricerche rapide. Il servizio tabelle non crea però indici secondari e dunque queste sono le due sole proprietà indicizzate. Alcuni dei modelli descritti più avanti mostrano come poter ovviare a questa apparente limitazione.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; however, the Table service does not 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).

Una tabella è costituita da una o più partizioni e, come si vedrà, molte delle decisioni relative alla progettazione riguarderanno la scelta di un valore appropriato per PartitionKey e RowKey per poter ottimizzare la soluzione.A table is made up of one or more partitions, and as you will see, many of the design decisions you make will be around choosing a suitable PartitionKey and RowKey to optimize your solution. Una soluzione può essere costituita da una sola tabella contenente tutte le entità organizzate in partizioni, ma normalmente una soluzione comprende più tabelle.A solution could consist of just a single table that contains all your entities organized into partitions, but typically a solution will have multiple tables. Le tabelle permettono di organizzare in modo logico le entità e di gestire l'accesso ai dati con gli elenchi di controllo di accesso. Inoltre è possibile eliminare un'intera tabella con una sola operazione di archiviazione.Tables help you to logically organize your entities, help you manage access to the data using access control lists, and you can drop an entire table using a single storage operation.

Partizioni della tabellaTable partitions

Il nome account, il nome tabella e PartitionKey insieme identificano la partizione nel servizio di archiviazione in cui il servizio tabelle archivia l'entità.The account name, table name and PartitionKey together identify the partition within the storage service where the table service stores the entity. Oltre a far parte dello schema di indirizzamento per le entità, le partizioni definiscono un ambito per le transazioni (vedere più avanti Transazioni di gruppi di entità) e formano le basi del ridimensionamento del servizio tabelle.As well as being part of the addressing scheme for entities, partitions define a scope for transactions (see Entity Group Transactions below), and form the basis of how the table service scales. Per altre informazioni sulle partizioni, vedere Obiettivi di scalabilità e prestazioni per Archiviazione di Azure.For more information on partitions see Azure Storage Scalability and Performance Targets.

Nel servizio tabelle, un solo nodo gestisce una o più partizioni complete e il servizio scala bilanciando dinamicamente il carico delle partizioni tra i nodi.In the Table service, an individual node services one or more complete partitions and the service scales by dynamically load-balancing partitions across nodes. Se un nodo è in condizioni di carico, il servizio tabelle può dividere in più nodi l'intervallo di partizioni gestite da quel nodo. Quando il traffico diminuisce, il servizio può unire nuovamente in un solo nodo gli intervalli di partizioni dai nodi inattivi.If a node is under load, the table service can split the range of partitions serviced by that node onto different nodes; when traffic subsides, the service can merge the partition ranges from quiet nodes back onto a single node.

Per altre informazioni sui dettagli interni del servizio tabelle, in particolare sulla gestione delle partizioni con il servizio tabelle, vedere il documento relativo all’ Archiviazione di Microsoft Azure: un servizio di archiviazione cloud a elevata disponibilità con coerenza assolutaFor more information about the internal details of the Table service, and in particular how the service manages partitions, see the paper Microsoft Azure Storage: A Highly Available Cloud Storage Service with Strong Consistency.

Transazioni dei gruppi di entitàEntity Group Transactions

Nel servizio tabelle, le transazioni di gruppi di entità (EGT, Entity Group Transaction) sono il solo meccanismo predefinito per eseguire aggiornamenti atomici tra più entità.In the Table service, Entity Group Transactions (EGTs) are the only built-in mechanism for performing atomic updates across multiple entities. In alcuni documenti, le transazioni EGT sono chiamate anche transazioni batch.EGTs are also referred to as batch transactions in some documentation. Le transazioni EGT possono agire solo su entità archiviate nella stessa partizione (ovvero che condividono la stessa chiave di partizione in una determinata tabella), quindi, ogni volta che è necessario un comportamento transazionale atomico tra più entità, bisogna assicurarsi che tali entità siano nella stessa partizione.EGTs can only operate on entities stored in the same partition (share the same partition key in a given table), so anytime you need atomic transactional behavior across multiple entities you need to ensure that those entities are in the same partition. Per questo motivo spesso si tengono tipi diversi di entità nella stessa tabella (e partizione) e non si usa una tabella per ogni tipo di 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. Una sola EGT può agire al massimo su 100 entità.A single EGT can operate on at most 100 entities. Se si inviano più EGT simultanee per l'elaborazione è importante garantire che tali EGT non vengano applicate a entità che sono comuni tra EGT, altrimenti l'elaborazione potrebbe subire dei ritardi.If you submit multiple concurrent EGTs for processing it is important to ensure those EGTs do not operate on entities that are common across EGTs as otherwise processing can be delayed.

Le transazioni EGT introducono anche un potenziale compromesso da tenere in considerazione durante la progettazione: se si usano più partizioni, la scalabilità dell'applicazione aumenta perché Azure ha più opportunità di bilanciare il carico delle richieste tra i nodi, ma questo potrebbe limitare la possibilità dell'applicazione di eseguire transazioni atomiche e di mantenere la coerenza assoluta per i dati.EGTs also introduce a potential trade-off for you to evaluate in your design: using more partitions will increase the scalability of your application because Azure has more opportunities for load balancing requests across nodes, but this might limit the ability of your application to perform atomic transactions and maintain strong consistency for your data. Esistono poi specifici obiettivi di scalabilità a livello di partizione, che potrebbero limitare la velocità effettiva delle transazioni prevista per un singolo nodo: per altre informazioni sugli obiettivi di scalabilità per gli account di archiviazione di Azure e il servizio tabelle, vedere Obiettivi di scalabilità e prestazioni per Archiviazione di Azure.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: for more information about the scalability targets for Azure storage accounts and the table service, see Azure Storage Scalability and Performance Targets. Le sezioni successive di questa guida illustrano diverse strategie di progettazione che aiutano a gestire compromessi come questo e illustrano il modo migliore per scegliere la chiave di partizione in base ai requisiti specifici dell'applicazione client.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.

Considerazioni sulla capacitàCapacity considerations

La tabella seguente include alcuni valori chiave da tenere presenti quando si progetta una soluzione di servizio tabelle:The following table includes some of the key values to be aware of when you are designing a Table service solution:

Capacità totale di un account di archiviazione di AzureTotal capacity of an Azure storage account 500 TB500 TB
Numero di tabelle in un account di archiviazione di AzureNumber of tables in an Azure storage account Limitato solo dalla capacità dell'account di archiviazioneLimited only by the capacity of the storage account
Numero di partizioni in una tabellaNumber of partitions in a table Limitato solo dalla capacità dell'account di archiviazioneLimited only by the capacity of the storage account
Numero di entità in una partizioneNumber of entities in a partition Limitato solo dalla capacità dell'account di archiviazioneLimited only by the capacity of the storage account
Dimensioni di una singola entitàSize of an individual entity Fino a 1 MB con un massimo di 255 proprietà (incluse PartitionKey, RowKey e Timestamp)Up to 1 MB with a maximum of 255 properties (including the PartitionKey, RowKey, and Timestamp)
Dimensioni di PartitionKeySize of the PartitionKey Stringa con dimensioni fino a 1 KB.A string up to 1 KB in size
Dimensioni di RowKeySize of the RowKey Stringa con dimensioni fino a 1 KB.A string up to 1 KB in size
Dimensioni di una transazione di gruppi di entitàSize of an Entity Group Transaction Una transazione può includere al massimo 100 entità e le dimensioni del payload devono essere inferiori a 4 MB.A transaction can include at most 100 entities and the payload must be less than 4 MB in size. Una transazione EGT può aggiornare una sola entità per volta.An EGT can only update an entity once.

Per altre informazioni, vedere Informazioni sul modello di dati del servizio tabelle.For more information, see Understanding the Table Service Data Model.

Considerazioni sul costoCost considerations

Anche se l'archiviazione tabelle è relativamente poco costosa, è consigliabile includere le stime dei costi, sia per l'utilizzo della capacità che per la quantità di transazioni, nella valutazione delle soluzioni che usano il servizio tabelle.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 the Table service. Tuttavia in molti scenari, l'archiviazione dei dati denormalizzati o duplicati per migliorare le prestazioni o la scalabilità della soluzione costituisce un valido approccio.However, in many scenarios storing denormalized or duplicate data in order to improve the performance or scalability of your solution is a valid approach to take. Per altre informazioni sui prezzi, vedere Prezzi di Archiviazione di Azure.For more information about pricing, see Azure Storage Pricing.

Linee guida per la progettazione di tabelleGuidelines for table design

Questi elenchi riepilogano alcune linee guida chiave che è necessario tenere presenti durante la progettazione delle, la guida li descriverà più nel dettaglio in seguito.These lists summarize some of the key guidelines you should keep in mind when you are designing your tables, and this guide will address them all in more detail later in. Queste linee guida sono molto diverse dalle linee guida a cui in genere ci si attiene per la progettazione di database relazionali.These guidelines are very different from the guidelines you would typically follow for relational database design.

Progettazione di una soluzione di servizio tabelle efficiente nelle operazioni di lettura :Designing your Table service solution to be read efficient:

  • Progettazione per le query nelle applicazioni con intensa attività di lettura.Design for querying in read-heavy applications. Quando si progettano le tabelle, considerare le query (soprattutto quelle sensibili alla latenza) che si eseguiranno prima di pensare a come si aggiorneranno le entità.When you are designing your tables, think about the queries (especially the latency sensitive ones) that you will execute before you think about how you will update your entities. Ciò comporta in genere una soluzione efficiente e ad alte prestazioni.This typically results in an efficient and performant solution.
  • Specificare PartitionKey e RowKey nelle query.Specify both PartitionKey and RowKey in your queries. Scegliere query come queste sono le query più efficienti del servizio tabella.Point queries such as these are the most efficient table service queries.
  • Prendere in considerazione l'archiviazione di copie duplicate delle entità.Consider storing duplicate copies of entities. Poiché l'archiviazione tabelle è economica, considerare la possibilità di archiviare la stessa entità più volte (con chiavi diverse) per consentire query più efficienti.Table storage is cheap so consider storing the same entity multiple times (with different keys) to enable more efficient queries.
  • Considerare la denormalizzazione dei dati.Consider denormalizing your data. L’archiviazione delle tabelle è economica, dunque è opportuno considerare la denormalizzazione dei dati.Table storage is cheap so consider denormalizing your data. Ad esempio, archiviare le entità di riepilogo in modo che le query per aggregare i dati debbano accedere a una singola entità.For example, store summary entities so that queries for aggregate data only need to access a single entity.
  • Usare valori chiave composti.Use compound key values. Le sole chiavi a disposizione sono PartitionKey e RowKey.The only keys you have are PartitionKey and RowKey. Ad esempio, per abilitare percorsi alternativi per l'accesso con chiave alle entità, ad esempio, utilizzare valori chiave composti.For example, use compound key values to enable alternate keyed access paths to entities.
  • Usare la proiezione di query.Use query projection. È possibile ridurre la quantità di dati trasferiti tramite la rete usando query che selezionano solo i campi necessari.You can reduce the amount of data that you transfer over the network by using queries that select just the fields you need.

Progettazione di una soluzione di servizio tabelle efficiente nelle operazioni di scrittura :Designing your Table service solution to be write efficient:

  • Non creare partizioni critiche.Do not create hot partitions. Scegliere chiavi che consentono di distribuire le richieste tra più partizioni in qualsiasi momento.Choose keys that enable you to spread your requests across multiple partitions at any point of time.
  • Evitare picchi di traffico.Avoid spikes in traffic. Contenere il traffico in un intervallo di tempo ragionevole ed evitare i picchi di traffico.Smooth the traffic over a reasonable period of time and avoid spikes in traffic.
  • Non creare necessariamente una tabella separata per ogni tipo di entità.Don't necessarily create a separate table for each type of entity. Quando è necessario eseguire transazioni atomiche tra diversi tipi di entità, è possibile archiviare questi tipi di entità nella stessa partizione della stessa tabella.When you require atomic transactions across entity types, you can store these multiple entity types in the same partition in the same table.
  • Considerare la velocità effettiva massima che è necessario raggiungere.Consider the maximum throughput you must achieve. È necessario tenere presenti gli obiettivi di scalabilità per il servizio tabelle e assicurarsi di non superarli con la progettazione.You must be aware of the scalability targets for the Table service and ensure that your design will not cause you to exceed them.

Questa guida contiene esempi in cui vengono messi in pratica tutti questi principi.As you read this guide, you will see examples that put all of these principles into practice.

Progettazione per le queryDesign for querying

Le soluzioni di servizio tabelle possono eseguire un'intensa attività di lettura, di scrittura o una combinazione di entrambe.Table service solutions may be read intensive, write intensive, or a mix of the two. Questa sezione è incentrata sugli aspetti da prendere in considerazione quando si progetta un servizio tabelle in grado di supportare in modo efficiente le operazioni di lettura.This section focuses on the things to bear in mind when you are designing your Table service to support read operations efficiently. Una progettazione che supporta in modo efficiente le operazioni di lettura è in genere efficiente anche nelle operazioni di scrittura.Typically, a design that supports read operations efficiently is also efficient for write operations. Esistono però altri aspetti da considerare per una progettazione che supporti le operazioni di scrittura, come illustrato nella prossima sezione, Progettazione per la modifica dei dati,However, there are additional considerations to bear in mind when designing to support write operations, discussed in the next section, Design for data modification.

Quando si inizia a progettare una soluzione di servizio tabelle che consenta di leggere i dati in modo efficiente, è importante chiedersi quali query dovrà eseguire l'applicazione per recuperare i dati necessari dal servizio tabelle.A good starting point for designing your Table service solution to enable you to read data efficiently is to ask "What queries will my application need to execute to retrieve the data it needs from the Table service?"

Nota

Con il servizio tabelle, è fondamentale realizzare una progettazione corretta fin dall'inizio perché cambiarla in seguito è complesso e costoso.With the Table service, it's important to get the design correct up front because it's difficult and expensive to change it later. In un database relazionale, ad esempio, spesso è possibile risolvere i problemi di prestazioni semplicemente aggiungendo degli indici a un database esistente, ma questa opzione non è applicabile al servizio tabelle.For example, in a relational database it's often possible to address performance issues simply by adding indexes to an existing database: this is not an option with the Table service.

Questa sezione è incentrata sui problemi chiave che è necessario affrontare quando si progettano le tabelle per le query.This section focuses on the key issues you must address when you design your tables for querying. Gli argomenti trattati in questa sezione includono:The topics covered in this section include:

Come la scelta di PartitionKey e RowKey compromette le prestazioni delle queryHow your choice of PartitionKey and RowKey impacts query performance

I seguenti esempi presuppongono che nel servizio tabelle vengano archiviate entità dipendente con la struttura seguente (per maggiore chiarezza, nella maggior parte degli esempi viene omessa la proprietà Timestamp ):The following examples assume the table service is storing employee entities with the following structure (most of the examples omit the Timestamp property for clarity):

Nome colonnaColumn name Tipo di datiData type
PartitionKey (nome del reparto)PartitionKey (Department Name) stringString
RowKey (ID dipendente)RowKey (Employee Id) stringString
FirstNameFirstName stringString
LastNameLastName stringString
AgeAge IntegerInteger
EmailAddressEmailAddress stringString

La sezione precedente Azure Table service overview (Panoramica del servizio tabelle di Azure) descrive alcune funzionalità chiave del servizio tabelle di Azure che influiscono direttamente sulla progettazione della query.The earlier section Azure Table service overview describes some of the key features of the Azure Table service that have a direct influence on designing for query. Se ne possono ricavare le seguenti linee guida generali per la progettazione di query del servizio tabelle.These result in the following general guidelines for designing Table service queries. Si noti che la sintassi del filtro usata negli esempi seguenti proviene dall'API REST del servizio tabelle. Per altre informazioni, vedere Query Entities (Entità query).Note that the filter syntax used in the examples below is from the Table service REST API, for more information see Query Entities.

  • Una query di tipo punto è il tipo di ricerca più efficiente da usare ed è consigliata per le ricerche con volumi elevati o per le ricerche che richiedono una latenza molto bassa.A Point Query is the most efficient lookup to use and is recommended to be used for high-volume lookups or lookups requiring lowest latency. Una query di questo tipo può usare gli indici per trovare in modo molto efficiente una singola entità specificando entrambi i valori PartitionKey e RowKey.Such a query can use the indexes to locate an individual entity very efficiently by specifying both the PartitionKey and RowKey values. Ad esempio, $filter=(PartitionKey eq 'Sales') e (RowKey eq '2')For example: $filter=(PartitionKey eq 'Sales') and (RowKey eq '2')
  • La seconda miglior ricerca è la query di intervallo, che usa PartitionKey e applica il filtro a un intervallo di valori RowKey per restituire più di un'entità.Second best is a Range Query that uses the PartitionKey and filters on a range of RowKey values to return more than one entity. Il valore PartitionKey identifica una partizione specifica e i valori RowKey identificano un subset delle entità in quella partizione.The PartitionKey value identifies a specific partition, and the RowKey values identify a subset of the entities in that partition. Ad esempio, $filter=PartitionKey eq 'Sales' e RowKey ge 'S' e RowKey lt 'T'For example: $filter=PartitionKey eq 'Sales' and RowKey ge 'S' and RowKey lt 'T'
  • La terza miglior ricerca è l'analisi della partizione, che usa PartitionKey e applica un filtro in base a un'altra proprietà non chiave e che potrebbe restituire più di un'entità.Third best is a Partition Scan that uses the PartitionKey and filters on another non-key property and that may return more than one entity. Il valore PartitionKey identifica una partizione specifica e i valori della proprietà selezionano un subset delle entità in quella partizione.The PartitionKey value identifies a specific partition, and the property values select for a subset of the entities in that partition. Ad esempio: $filter=PartitionKey eq 'Sales' e LastName eq 'Smith'For example: $filter=PartitionKey eq 'Sales' and LastName eq 'Smith'
  • Una scansione di tabella non include PartitionKey ed è molto inefficiente perché cerca le entità corrispondenti in tutte le partizioni della tabella, una alla volta.A Table Scan does not include the PartitionKey and is very inefficient because it searches all of the partitions that make up your table in turn for any matching entities. Una scansione di tabella viene eseguita indipendentemente dal fatto che il filtro usi RowKeyo meno.It will perform a table scan regardless of whether or not your filter uses the RowKey. Ad esempio: $filter = LastName eq 'Jones'For example: $filter=LastName eq 'Jones'
  • Le query che restituiscono più entità le ordinano in base a PartitionKey e RowKey.Queries that return multiple entities return them sorted in PartitionKey and RowKey order. Per non dover riordinare le entità nel client, scegliere un valore RowKey che definisca l'ordinamento più comune.To avoid resorting the entities in the client, choose a RowKey that defines the most common sort order.

Si noti che, se si usa "or" per specificare un filtro basato su valori RowKey, si ottiene un'analisi della partizione che non viene considerata come query di intervallo.Note that using an "or" to specify a filter based on RowKey values results in a partition scan and is not treated as a range query. Pertanto, è consigliabile evitare query che utilizzano filtri ad esempio: $filter = PartitionKey eq "Sales" e (RowKey '121' o RowKey eq '322')Therefore, you should avoid queries that use filters such as: $filter=PartitionKey eq 'Sales' and (RowKey eq '121' or RowKey eq '322')

Per esempi di codice lato client che usano la libreria client di archiviazione per eseguire query efficienti, vedere:For examples of client-side code that use the Storage Client Library to execute efficient queries, see:

Per esempi di codice lato client che possono gestire più tipi di entità archiviati nella stessa tabella, vedere:For examples of client-side code that can handle multiple entity types stored in the same table, see:

Scelta di un valore PartitionKey appropriatoChoosing an appropriate PartitionKey

La scelta di PartitionKey deve soddisfare sia la necessità di abilitare l'uso di transazioni EGT (per assicurare la coerenza) sia il requisito di distribuzione delle entità tra più partizioni (per assicurare una soluzione scalabile).Your choice of PartitionKey should balance the need to enables the use of EGTs (to ensure consistency) against the requirement to distribute your entities across multiple partitions (to ensure a scalable solution).

Da una parte, pur essendo possibile archiviare tutte le entità in una singola partizione, questo potrebbe limitare la scalabilità della soluzione e impedirebbe al servizio tabelle di bilanciare il carico delle richieste.At one extreme, you could store all your entities in a single partition, but this may limit the scalability of your solution and would prevent the table service from being able to load-balance requests. D'altra parte, pur essendo possibile archiviare un'entità per partizione, ottenendo così la scalabilità elevata e consentendo al servizio tabelle di bilanciare il carico delle richieste, questo impedirebbe di usare le transazioni del gruppo di entità.At the other extreme, you could store one entity per partition, which would be highly scalable and which enables the table service to load-balance requests, but which would prevent you from using entity group transactions.

Il valore PartitionKey ideale consente di usare query efficienti e ha un numero sufficiente di partizioni per garantire la scalabilità della soluzione.An ideal PartitionKey is one that enables you to use efficient queries and that has sufficient partitions to ensure your solution is scalable. Di solito le entità dispongono una proprietà apposita che le distribuisce in un numero sufficiente di partizioni.Typically, you will find that your entities will have a suitable property that distributes your entities across sufficient partitions.

Nota

Ad esempio, in un sistema che archivia le informazioni sugli utenti o i dipendenti, l'ID utente può essere un valore PartitionKey valido.For example, in a system that stores information about users or employees, UserID may be a good PartitionKey. È possibile avere più entità che utilizzano un ID utente specificato come chiave di partizione.You may have several entities that use a given UserID as the partition key. Ogni entità che archivia i dati su un utente è raggruppata in una singola partizione e quindi queste entità sono accessibili tramite gruppi di entità, mantenendo la scalabilità elevata.Each entity that stores data about a user is grouped into a single partition, and so these entities are accessible via entity group transactions, while still being highly scalable.

Gli altri aspetti da considerare per la scelta di PartitionKey riguardano l'inserimento, l'aggiornamento e l'eliminazione delle entità: vedere la sezione Progettazione per la modifica dei dati qui di seguito.There are additional considerations in your choice of PartitionKey that relate to how you will insert, update, and delete entities: see the section Design for data modification below.

Ottimizzazione delle query per il servizio tabelleOptimizing queries for the Table service

Il servizio tabelle indicizza automaticamente le entità usando i valori PartitionKey e RowKey in un singolo indice cluster. È per questo che le query di tipo punto sono le più efficienti da usare.The Table service automatically indexes your entities using the PartitionKey and RowKey values in a single clustered index, hence the reason that point queries are the most efficient to use. Tuttavia, non esistono altri indici oltre a quello nell'indice cluster in PartitionKey e RowKey.However, there are no indexes other than that on the clustered index on the PartitionKey and RowKey.

Molte progettazioni devono soddisfare alcuni requisiti per abilitare la ricerca di entità in base a più criteri,Many designs must meet requirements to enable lookup of entities based on multiple criteria. ad esempio trovare le entità dipendente in base a indirizzo di posta elettronica, ID dipendente o cognome.For example, locating employee entities based on email, employee id, or last name. I modelli seguenti nella sezione Modelli di progettazione tabelle soddisfano questi tipi di requisito e descrivono come ovviare al fatto che il servizio tabelle non fornisca indici secondari:The following patterns in the section Table Design Patterns address these types of requirement and describe ways of working around the fact that the Table service does not provide secondary indexes:

  • Modello per indice secondario intrapartizione - Archivia più copie di ogni entità usando valori RowKey diversi (nella stessa partizione) per consentire ricerche rapide ed efficienti e ordinamenti alternativi usando valori RowKey diversi.Intra-partition secondary index pattern - Store multiple copies of each entity using different RowKey values (in the same partition) to enable fast and efficient lookups and alternate sort orders by using different RowKey values.
  • Modello tra partizionare l'indice secondario -archiviazione di più copie di ogni entità mediante diverse RowKey valori partizioni in separate o in diverse tabelle per abilitare le ricerche veloci ed efficienti e ordinamento alternativo gli ordini con diversi RowKey valori.Inter-partition secondary index pattern - Store multiple copies of each entity using different RowKey values in separate partitions or in separate tables to enable fast and efficient lookups and alternate sort orders by using different RowKey values.
  • Modello per entità di indice - Mantiene le entità di indice per consentire ricerche efficienti che restituiscano elenchi di entità.Index Entities Pattern - Maintain index entities to enable efficient searches that return lists of entities.

Ordinamento dei dati nel servizio tabelleSorting data in the Table service

Il servizio tabelle restituisce le entità in ordine crescente in base a PartitionKey e quindi a RowKey.The Table service returns entities sorted in ascending order based on PartitionKey and then by RowKey. Queste chiavi sono valori stringa e, per essere certi che i valori numerici siano ordinati correttamente, è consigliabile convertirli in una lunghezza fissa aggiungendo degli zeri se necessario.These keys are string values and to ensure that numeric values sort correctly, you should convert them to a fixed length and pad them with zeroes. Se, ad esempio, il valore dell'ID dipendente usato come RowKey è un valore intero, è consigliabile convertire l'ID dipendente 123 in 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.

In molte applicazioni è necessario usare i dati ordinandoli in modo diverso, ad esempio ordinando i dipendenti per nome o per data di assunzione.Many applications have requirements to use data sorted in different orders: for example, sorting employees by name, or by joining date. I modelli seguenti nella sezione Modelli di progettazione tabella descrivono come alternare l'ordinamento per le entità:The following patterns in the section Table Design Patterns address how to alternate sort orders for your entities:

  • Modello per indice secondario intrapartizione - Archivia più copie di ogni entità usando valori RowKey diversi (nella stessa partizione) per consentire ricerche rapide ed efficienti e ordinamenti alternativi usando valori.Intra-partition secondary index pattern - Store multiple copies of each entity using different RowKey values (in the same partition) to enable fast and efficient lookups and alternate sort orders by using different RowKey values.
  • Modello per indice secondario intrapartizione - Archivia più copie di ogni entità usando valori RowKey diversi in partizioni separate o in tabelle separate per consentire ricerche rapide ed efficienti e ordinamenti alternativi usando valori RowKey.Inter-partition secondary index pattern - Store multiple copies of each entity using different RowKey values in separate partitions in separate tables to enable fast and efficient lookups and alternate sort orders by using different RowKey values.
  • Modello della parte finale del log - Recupera le n entità aggiunte più di recente a una partizione in base a un valore RowKey che usa un ordinamento inverso di data e ora.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.

Progettazione per la modifica dei datiDesign for data modification

Questa sezione esamina le considerazioni relative alla progettazione per ottimizzare inserimenti, aggiornamenti ed eliminazioni.This section focuses on the design considerations for optimizing inserts, updates, and deletes. In alcuni casi, sarà necessario valutare il compromesso tra progettazioni che ottimizzano le query e progettazioni che ottimizzano la modifica dei dati, come avviene per le progettazioni per i database relazionali (anche se le tecniche per gestire i compromessi tra progettazioni sono diverse in un database relazionale).In some cases, you will need to evaluate the trade-off between designs that optimize for querying against designs that optimize for data modification just as you do in designs for relational databases (although the techniques for managing the design trade-offs are different in a relational database). La sezione Modelli di progettazione tabelle descrive in dettaglio alcuni modelli di progettazione per il servizio tabelle ed evidenzia alcuni di questi compromessi.The section Table Design Patterns describes some detailed design patterns for the Table service and highlights some these trade-offs. In pratica si vedrà che molte progettazioni ottimizzate per le query delle entità vanno bene anche per la modifica delle entità.In practice, you will find that many designs optimized for querying entities also work well for modifying entities.

Ottimizzazione delle prestazioni delle operazioni di inserimento, aggiornamento ed eliminazioneOptimizing the performance of insert, update, and delete operations

Per aggiornare o eliminare un'entità, è necessario poterla identificare usando i valori PartitionKey e RowKey.To update or delete an entity, you must be able to identify it by using the PartitionKey and RowKey values. In questo senso la scelta di PartitionKey e RowKey per modificare le entità deve seguire criteri simili a quelli usati per la scelta di supportare le query di tipo punto, perché l'obiettivo è identificare le entità nel modo più efficiente possibile.In this respect, your choice of PartitionKey and RowKey for modifying entities should follow similar criteria to your choice to support point queries because you want to identify entities as efficiently as possible. Si vuole evitare di usare una scansione di tabella o di partizione inefficiente per trovare un'entità e poter individuare i valori PartitionKey e RowKey necessari per aggiornarla o eliminarla.You do not 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.

I modelli seguenti nella sezione Modelli di progettazione tabelle consentono di ottimizzare le prestazioni delle operazioni di inserimento, aggiornamento ed eliminazione:The following patterns in the section Table Design Patterns address optimizing the performance or your insert, update, and delete operations:

  • Modello di eliminazione volume elevato - Abilita l'eliminazione di un volume elevato di entità mediante l'archiviazione di tutte le entità per l'eliminazione simultanea nella relativa tabella separata. Per eliminare le entità, eliminare la tabella.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; you delete the entities by deleting the table.
  • Modello di serie di dati - Archivia serie di dati complete in un'unica entità per ridurre al minimo il numero di richieste effettuate.Data series pattern - Store complete data series in a single entity to minimize the number of requests you make.
  • Modello di entità di grandi dimensioni - Usa più entità fisiche per archiviare entità logiche con più di 252 proprietà.Wide entities pattern - Use multiple physical entities to store logical entities with more than 252 properties.
  • Modello di entità di grandi dimensioni - Usa l'archiviazione BLOB per archiviare i valori di proprietà di grandi dimensioni.Large entities pattern - Use blob storage to store large property values.

Verifica della coerenza nelle entità archiviateEnsuring consistency in your stored entities

L'altro aspetto importante che influisce sulla scelta delle chiavi per ottimizzare la modifica dei dati è come assicurare la coerenza usando le transazioni atomiche.The other key factor that influences your choice of keys for optimizing data modifications is how to ensure consistency by using atomic transactions. È possibile usare una transazione EGT solo per agire sulle entità archiviate nella stessa partizione.You can only use an EGT to operate on entities stored in the same partition.

I modelli seguenti nella sezione Modelli di progettazione tabella descrive la gestione della coerenza:The following patterns in the section Table Design Patterns address managing consistency:

  • Modello per indice secondario intrapartizione - Archivia più copie di ogni entità usando valori RowKey diversi (nella stessa partizione) per consentire ricerche rapide ed efficienti e ordinamenti alternativi usando valori RowKey diversi.Intra-partition secondary index pattern - Store multiple copies of each entity using different RowKey values (in the same partition) to enable fast and efficient lookups and alternate sort orders by using different RowKey values.
  • Modello per indice secondario intrapartizione - Archivia più copie di ogni entità usando valori RowKey diversi in partizioni separate o in tabelle separate per consentire ricerche rapide ed efficienti e ordinamenti alternativi usando valori RowKey diversi.Inter-partition secondary index pattern - Store multiple copies of each entity using different RowKey values in separate partitions or in separate tables to enable fast and efficient lookups and alternate sort orders by using different RowKey values.
  • Modello per transazioni con coerenza finale - Abilita un comportamento di coerenza finale tra i limiti della partizione o i limiti del sistema di archiviazione usando le code di Azure.Eventually consistent transactions pattern - Enable eventually consistent behavior across partition boundaries or storage system boundaries by using Azure queues.
  • Modello per entità di indice - Mantiene le entità di indice per consentire ricerche efficienti che restituiscano elenchi di entità.Index Entities Pattern - Maintain index entities to enable efficient searches that return lists of entities.
  • Modello di denormalizzazione - Combina i dati correlati in una singola entità per consentire di recuperare tutti i dati necessari con un sola query di tipo punto.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.
  • Modello di serie di dati - Archivia serie di dati complete in un'unica entità per ridurre al minimo il numero di richieste effettuate.Data series pattern - Store complete data series in a single entity to minimize the number of requests you make.

Per informazioni sulle transazioni di gruppi di entità, vedere la sezione Transazioni di gruppi di entità.For information about entity group transactions, see the section Entity Group Transactions.

Verifica della capacità della progettazione per modifiche efficienti di facilitare query efficientiEnsuring your design for efficient modifications facilitates efficient queries

In molti casi, una progettazione per query efficienti consente modifiche efficienti, ma è consigliabile valutare sempre se questa condizione si applica a uno specifico scenario.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. Alcuni dei modelli nella sezione Modelli di progettazione tabelle valutano in modo esplicito i compromessi tra la query e la modifica delle entità. Inoltre è sempre consigliabile tenere in considerazione il numero di ogni tipo di operazione.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.

I seguenti modelli nella sezione Modelli di progettazione tabelle considerano i compromessi tra la progettazione per query efficienti e la progettazione per una modifica efficiente dei dati:The following patterns in the section Table Design Patterns address trade-offs between designing for efficient queries and designing for efficient data modification:

  • Modello per chiave composta - Usa valori RowKey composti per consentire a un client di cercare dati correlati con una sola query di tipo punto.Compound key pattern - Use compound RowKey values to enable a client to lookup related data with a single point query.
  • Modello della parte finale del log - Recupera le n entità aggiunte più di recente a una partizione in base a un valore RowKey che usa un ordinamento inverso di data e ora.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.

Crittografia dei dati di tabellaEncrypting Table Data

La libreria client di Archiviazione di Azure per .NET supporta la crittografia di proprietà di entità stringa per le operazioni di inserimento e sostituzione.The .NET Azure Storage Client Library supports encryption of string entity properties for insert and replace operations. Le stringhe crittografate vengono archiviate nel servizio come proprietà binarie e vengono convertite nuovamente in stringhe dopo la decrittografia.The encrypted strings are stored on the service as binary properties, and they are converted back to strings after decryption.

Per le tabelle, oltre al criterio di crittografia, gli utenti devono specificare le proprietà da crittografare.For tables, in addition to the encryption policy, users must specify the properties to be encrypted. Questa operazione può essere eseguita specificando un attributo [EncryptProperty] (per le entità POCO che derivano da TableEntity) o un resolver di crittografia nelle opzioni di richiesta.This can be done by either specifying an [EncryptProperty] attribute (for POCO entities that derive from TableEntity) or an encryption resolver in request options. Un resolver di crittografia è un delegato che accetta una chiave di partizione, una chiave di riga e un nome di proprietà e restituisce un valore booleano che indica se tale proprietà deve essere crittografata.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. Durante la crittografia, la libreria client utilizzerà queste informazioni per decidere se una proprietà deve essere crittografata durante la scrittura in rete.During encryption, the client library will use this information to decide whether a property should be encrypted while writing to the wire. Il delegato fornisce inoltre la possibilità di logica per la modalità di crittografia delle proprietà.The delegate also provides for the possibility of logic around how properties are encrypted. (Ad esempio, se X, quindi crittografa la proprietà A; in caso contrario crittografa le proprietà A e B). Si noti che non è necessario fornire queste informazioni durante la lettura o la query su entità.(For example, if X, then encrypt property A; otherwise encrypt properties A and B.) Note that it is not necessary to provide this information while reading or querying entities.

Si noti che l'unione non è attualmente supportata.Note that merge is not currently supported. Poiché un subset di proprietà potrebbe essere stato crittografato in precedenza utilizzando una chiave diversa, la semplice unione delle nuove proprietà e l’aggiornamento dei metadati comportano la perdita di dati.Since a subset of properties may have been encrypted previously using a different key, simply merging the new properties and updating the metadata will result in data loss. L'unione richiede chiamate a servizi aggiuntivi per la lettura dell’entità preesistente dal servizio o l’utilizzo di una nuova chiave per ogni proprietà, entrambe operazioni non idonee per motivi di prestazioni.Merging either requires making extra service calls to read the pre-existing entity from the service, or using a new key per property, both of which are not suitable for performance reasons.

Per informazioni sulla crittografia dei dati di tabella, vedere Crittografia lato client e insieme di credenziali delle chiavi di Azure per Archiviazione di Microsoft Azure.For information about encrypting table data, see Client-Side Encryption and Azure Key Vault for Microsoft Azure Storage.

Modellazione di relazioniModelling relationships

La compilazione di modelli di dominio è un passaggio chiave della progettazione di sistemi complessi.Building domain models is a key step in the design of complex systems. Il processo di modellazione in genere viene usato per identificare le entità e le relazioni tra di esse, per poter comprendere il dominio aziendale e informare la progettazione del sistema.Typically, you use the modelling process to identify entities and the relationships between them as a way to understand the business domain and inform the design of your system. Questa sezione illustra come sia possibile convertire alcuni tipi comuni di relazione presenti nei modelli di dominio in progettazioni per il servizio tabelle.This section focuses on how you can translate some of the common relationship types found in domain models to designs for the Table service. Il processo di mapping da un modello di dati logico a un modello di dati fisico basato su NoSQL è molto diverso da quello usato quando si progetta un database relazionale.The process of mapping from a logical data-model to a physical NoSQL based data-model is very different from that used when designing a relational database. La progettazione di database relazionali presuppone in genere un processo di normalizzazione dei dati ottimizzato per ridurre al minimo la ridondanza, oltre a una funzionalità di query dichiarativa che astrae l'implementazione per il funzionamento del database.Relational databases design typically assumes a data normalization process optimized for minimizing redundancy – and a declarative querying capability that abstracts how the implementation of how the database works.

Relazioni uno a moltiOne-to-many relationships

Le relazioni uno a molti tra gli oggetti del dominio aziendale sono molto frequenti: ad esempio, un reparto ha più dipendenti.One-to-many relationships between business domain objects occur very frequently: for example, one department has many employees. Esistono modi diversi per implementare le relazioni uno a molti nel servizio tabelle, ciascuno dei quali presenta pro e contro che potrebbero essere pertinenti a un particolare scenario.There are several ways to implement one-to-many relationships in the Table service each with pros and cons that may be relevant to the particular scenario.

Considerare l'esempio di una grande multinazionale con decine di migliaia di reparti ed entità dipendente, dove ogni reparto ha più dipendenti e ogni dipendente è associato a uno specifico reparto.Consider the example of a large multi-national corporation with tens of thousands of departments and employee entities where every department has many employees and each employee as associated with one specific department. Un approccio prevede l'archiviazione di entità reparto e dipendente separate, come queste:One approach is to store separate department and employee entities such as these:

Questo esempio illustra una relazione uno a molti implicita tra i tipi basata sui valori PartitionKey .This example shows an implicit one-to-many relationship between the types based on the PartitionKey value. Ogni reparto può avere più dipendenti.Each department can have many employees.

Questo esempio mostra anche un'entità reparto e le relative entità dipendente nella stessa partizione.This example also shows a department entity and its related employee entities in the same partition. È possibile scegliere di usare partizioni, tabelle o anche account di archiviazione diversi per ogni tipo di entità.You could choose to use different partitions, tables, or even storage accounts for the different entity types.

Un approccio alternativo prevede la denormalizzazione dei dati e l'archiviazione delle sole entità dipendente con i dati reparto denormalizzati, come illustrato nell'esempio seguente.An alternative approach is to denormalize your data and store only employee entities with denormalized department data as shown in the following example. In questo particolare scenario, l'approccio denormalizzato non sarà quello migliore se si deve essere in grado di cambiare i dettagli di un responsabile di reparto perché, per questa operazione, sarà necessario aggiornare ogni dipendente del reparto.In this particular scenario, this denormalized approach may not be the best if you have a requirement to be able to change the details of a department manager because to do this you need to update every employee in the department.

Per ulteriori informazioni, vedere il Modello di denormalizzazione più avanti in questa guida.For more information, see the Denormalization pattern later in this guide.

La tabella seguente riepiloga i vantaggi e gli svantaggi di ogni approccio descritto sopra per l'archiviazione delle entità dipendente e reparto con una relazione uno a molti.The following table summarizes the pros and cons of each of the approaches outlined above for storing employee and department entities that have a one-to-many relationship. Si consiglia inoltre di considerare la frequenza con cui si prevede di eseguire le diverse operazioni: una progettazione che include un'operazione dal costo elevato può essere accettabile se l'operazione non viene eseguita spesso.You should also consider how often you expect to perform various operations: it may be acceptable to have a design that includes an expensive operation if that operation only happens infrequently.

ApproccioApproach VantaggiPros SvantaggiCons
Tipi di entità distinti, stessa partizione, stessa tabellaSeparate entity types, same partition, same table
  • È possibile aggiornare un'entità reparto con un'unica operazione.You can update a department entity with a single operation.
  • È possibile usare una transazione EGT per mantenere la coerenza, se esiste un requisito che impone di modificare un'entità reparto quando si aggiorna/inserisce/elimina un'entità dipendente,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. ad esempio se si mantiene un conteggio dei dipendenti per ogni reparto.For example if you maintain a departmental employee count for each department.
  • Per alcune attività client, potrebbe essere necessario recuperare sia un'entità dipendente che un'entità reparto.You may need to retrieve both an employee and a department entity for some client activities.
  • Le operazioni di archiviazione vengono eseguite nella stessa partizione.Storage operations happen in the same partition. Con volumi di transazioni elevati, potrebbe risultarne un hotspot.At high transaction volumes, this may result in a hotspot.
  • Non è possibile spostare un dipendente in un nuovo reparto con una transazione EGT.You cannot move an employee to a new department using an EGT.
Tipi di entità distinti, partizioni o tabelle o account di archiviazione diversiSeparate entity types, different partitions or tables or storage accounts
  • È possibile aggiornare un'entità reparto o un'entità dipendente con un'unica operazione.You can update a department entity or employee entity with a single operation.
  • Con volumi di transazioni elevati, può essere più facile distribuire il carico tra più partizioni.At high transaction volumes, this may help spread the load across more partitions.
  • Per alcune attività client, potrebbe essere necessario recuperare sia un'entità dipendente che un'entità reparto.You may need to retrieve both an employee and a department entity for some client activities.
  • Non è possibile usare le transazioni EGT per mantenere la coerenza quando si aggiorna/inserisce/elimina un dipendente e si aggiorna un reparto,You cannot use EGTs to maintain consistency when you update/insert/delete an employee and update a department. ad esempio quando si aggiorna un conteggio dipendenti in un'entità reparto.For example, updating an employee count in a department entity.
  • Non è possibile spostare un dipendente in un nuovo reparto con una transazione EGT.You cannot move an employee to a new department using an EGT.
Denormalizzazione in un solo tipo di entitàDenormalize into single entity type
  • È possibile recuperare tutte le informazioni necessarie con una sola richiesta.You can retrieve all the information you need with a single request.
  • Mantenere la coerenza potrebbe risultare costoso, se è necessario aggiornare le informazioni sui reparti, perché si dovrebbero aggiornare tutti i dipendenti di un reparto.It may be expensive to maintain consistency if you need to update department information (this would require you to update all the employees in a department).

Per scegliere tra queste opzioni e stabilire quali siano i vantaggi e gli svantaggi più importanti, è necessario considerare gli scenari specifici dell'applicazione.How you choose between these options, and which of the pros and cons are most significant, depends on your specific application scenarios. Ad esempio, ogni quanto si modificano le entità reparto, se tutte le query dei dipendenti richiedono informazioni aggiuntive sul reparto, quanto si è vicini ai limiti di scalabilità nelle partizioni o nell'account di archiviazione.For example, how often do you modify department entities; do all your employee queries need the additional departmental information; how close are you to the scalability limits on your partitions or your storage account?

Relazioni uno a unoOne-to-one relationships

I modelli di dominio possono includere relazioni uno a uno tra le entità.Domain models may include one-to-one relationships between entities. Se è necessario implementare una relazione uno a uno nel servizio tabelle, è necessario scegliere anche come collegare le due entità correlate quando è necessario recuperarle entrambe.If you need to implement a one-to-one relationship in the Table service, you must also choose how to link the two related entities when you need to retrieve them both. Questo collegamento può essere implicito, ovvero basato su una convenzione nei valori chiave, o esplicito, ovvero basato sull'archiviazione di un collegamento all'entità correlata, sotto forma di valori PartitionKey e RowKey in ogni entità.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. Per informazioni utili a stabilire se archiviare le entità correlate nella stessa partizione, vedere la sezione Relazioni uno a molti.For a discussion of whether you should store the related entities in the same partition, see the section One-to-many relationships.

Esistono anche alcune considerazioni sull'implementazione che potrebbero far decidere di implementare le relazioni uno a uno nel servizio tabelle:Note that there are also implementation considerations that might lead you to implement one-to-one relationships in the Table service:

Join nel clientJoin in the client

Anche se esistono alcuni modi per modellare le relazioni nel servizio tabelle, è bene non dimenticare che i due principali motivi per usare il servizio tabelle sono la scalabilità e le prestazioni.Although there are ways to model relationships in the Table service, you should not forget that the two prime reasons for using the Table service are scalability and performance. Se ci si accorge che si stanno modellando troppe relazioni che compromettono le prestazioni e la scalabilità della soluzione, è consigliabile chiedersi se sia necessario compilare tutte le relazioni tra i dati nella progettazione tabelle.If you find you are modelling many relationships that compromise the performance and scalability of your solution, you should ask yourself if it is necessary to build all the data relationships into your table design. È possibile semplificare la progettazione e migliorare la scalabilità e le prestazioni della soluzione permettendo all'applicazione client di eseguire i join necessari.You may 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.

Ad esempio, se si dispone di tabelle di piccole dimensioni che contengono dati che non cambiano molto spesso, è possibile recuperare i dati una sola volta e memorizzarli nella cache del client.For example, if you have small tables that contain data that does not change very often, then you can retrieve this data once and cache it on the client. Questo consente di evitare round trip ripetuti per il recupero degli stessi dati.This can avoid repeated roundtrips to retrieve the same data. Negli esempi esaminati in questa guida, il set di reparti di una piccola organizzazione sarà probabilmente di dimensioni ridotte e cambierà raramente. Si tratta di un caso ideale di dati che l'applicazione client può scaricare una sola volta e memorizzare nella cache come dati di ricerca.In the examples we have looked at in this guide, the set of departments in a small organization is likely to be small and change infrequently making it a good candidate for data that client application can download once and cache as look up data.

Relazioni di ereditarietàInheritance relationships

Se l'applicazione client usa un set di classi che fanno parte di una relazione di ereditarietà per rappresentare entità aziendali, è possibile rendere facilmente le entità persistenti nel servizio tabelle.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 the Table service. Ad esempio, nell'applicazione client potrebbe essere definito il set di classi seguente, dove Person è una classe astratta.For example, you might have the following set of classes defined in your client application where Person is an abstract class.

È possibile rendere persistenti le istanze delle due classi concrete nel servizio tabelle usando una singola tabella Persone con entità simili alle seguenti:You can persist instances of the two concrete classes in the Table service using a single Person table using entities in that look like this:

Per altre informazioni sull'uso di più tipi di entità nella stessa tabella nel codice del client, vedere la sezione Uso di tipi di entità eterogenei più avanti in questa guida.For more information about working with multiple entity types in the same table in client code, see the section Working with heterogeneous entity types later in this guide. In questa sezione sono disponibili esempi su come riconoscere il tipo di entità nel codice del client.This provides examples of how to recognize the entity type in client code.

Modelli di progettazione tabellaTable Design Patterns

Le sezioni precedenti illustrano in dettaglio come ottimizzare la progettazione della tabella sia per il recupero dei dati di entità mediante query che per l'inserimento, l'aggiornamento e l'eliminazione dei dati di entità.In previous sections, you have seen some detailed discussions about how to optimize your table design for both retrieving entity data using queries and for inserting, updating, and deleting entity data. Questa sezione descrive alcuni modelli adatti all'uso con le soluzioni di servizio tabelle.This section describes some patterns appropriate for use with Table service solutions. Fornisce inoltre informazioni su come risolvere alcuni dei problemi e dei compromessi evidenziati in precedenza in questa guida.In addition, you will see how you can practically address some of the issues and trade-offs raised previously in this guide. Il diagramma seguente contiene un riepilogo delle relazioni tra i diversi modelli:The following diagram summarizes the relationships between the different patterns:

La mappa dei modelli nella figura precedente evidenzia alcune relazioni tra i modelli (blu) e gli anti-modelli (arancione) documentati in questa guida.The pattern map above highlights some relationships between patterns (blue) and anti-patterns (orange) that are documented in this guide. Ovviamente esistono molti altri modelli utili.There are of course many other patterns that are worth considering. Ad esempio, uno degli scenari chiave per il servizio tabelle è l'uso del modello di vista materializzata dal modello Command Query Responsibility Segregation (CQRS).For example, one of the key scenarios for Table Service is to use the Materialized View Pattern from the Command Query Responsibility Segregation (CQRS) pattern.

Modello per indice secondario intrapartizioneIntra-partition secondary index pattern

Archivia più copie di ogni entità usando valori RowKey diversi (nella stessa partizione) per consentire ricerche rapide ed efficienti e ordinamenti alternativi usando valori RowKey diversi.Store multiple copies of each entity using different RowKey values (in the same partition) to enable fast and efficient lookups and alternate sort orders by using different RowKey values. Gli aggiornamenti tra copie possono essere mantenuti coerenti usando transazioni EGT.Updates between copies can be kept consistent using EGT's.

Contesto e problemaContext and problem

Il servizio tabelle indicizza automaticamente le entità usando i valori PartitionKey e RowKey.The Table service automatically indexes entities using the PartitionKey and RowKey values. Questo consente a un'applicazione client di recuperare un'entità in modo efficiente mediante questi valori.This enables a client application to retrieve an entity efficiently using these values. Ad esempio, usando la struttura della tabella riportata di seguito, un'applicazione client può usare una query di tipo punto per recuperare una singola entità dipendente attraverso il nome del reparto e l'ID del dipendente (i valori PartitionKey e RowKey).For example, using the table structure shown below, 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 può anche recuperare entità ordinate per ID dipendente in ogni reparto.A client can also retrieve entities sorted by employee id within each department.

Se si desidera poter trovare un'entità dipendente anche in base al valore di un'altra proprietà, ad esempio l'indirizzo di posta elettronica, è necessario usare un'analisi della partizione meno efficiente per trovare una corrispondenza.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. Il motivo è che il servizio tabelle non fornisce indici secondari.This is because the table service does not provide secondary indexes. Inoltre, non esiste un'opzione per richiedere un elenco di dipendenti ordinato in modo diverso rispetto all'ordine RowKey .In addition, there is no option to request a list of employees sorted in a different order than RowKey order.

SoluzioneSolution

Per ovviare alla mancanza di indici secondari, è possibile archiviare più copie di ogni entità usando per ogni copia un valore RowKey diverso.To work around the lack of secondary indexes, you can store multiple copies of each entity with each copy using a different RowKey value. Se si archivia un'entità con le strutture riportate di seguito, è possibile recuperare in modo efficiente entità dipendente in base all'id dipendente o all’indirizzo di posta elettronica. I valori di prefisso per RowKey, "empid_" e "email_", consentono di eseguire query per un singolo dipendente o un intervallo di dipendenti usando un intervallo di indirizzi e-mail o ID dipendente.If you store an entity with the structures shown below, you can efficiently retrieve employee entities based on email address or employee id. The prefix values for the 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.

I due criteri di filtro seguenti (uno che ricerca per ID dipendente e uno che ricerca per indirizzo di posta elettronica) specificano entrambi query di tipo punto: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') e (RowKey eq 'empid_000223)$filter=(PartitionKey eq 'Sales') and (RowKey eq 'empid_000223')
  • $filter=(PartitionKey eq 'Sales') e (RowKey eq 'email_jonesj@contoso.com')$filter=(PartitionKey eq 'Sales') and (RowKey eq 'email_jonesj@contoso.com')

Se si esegue una query su un intervallo di entità dipendente, è possibile specificare un intervallo ordinato per ID dipendente o un intervallo ordinato per indirizzo di posta elettronica eseguendo la query sulle entità con il prefisso appropriato in RowKey.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 by querying for entities with the appropriate prefix in the RowKey.

  • Per trovare tutti i dipendenti nel reparto vendite con un id dipendente in uso nell'intervallo che va da 000100 a 000199 utilizzare: $filter = (PartitionKey eq "Sales") e (RowKey ge'empid_000100') e (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')
  • Per trovare tutti i dipendenti del reparto vendite con un indirizzo di posta elettronica che inizia con la lettera "a" utilizzare: $filter = (PartitionKey eq "Sales") e (RowKey ge 'email_a') e (RowKey It'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')

    Si noti che la sintassi di filtro usata negli esempi precedenti proviene dall'API REST del servizio tabelle. Per altre informazioni, vedere Query Entities (Entità query).Note that the filter syntax used in the examples above is from the Table service REST API, for more information see Query Entities.

Considerazioni e problemiIssues and considerations

Prima di decidere come implementare questo modello, considerare quanto segue:Consider the following points when deciding how to implement this pattern:

  • L'uso dell'archiviazione tabelle è relativamente economico, pertanto l'aumento dei costi dovuto all'archiviazione di dati duplicati non dovrebbe rappresentare una preoccupazione.Table storage is relatively cheap to use so the cost overhead of storing duplicate data should not be a major concern. È però consigliabile valutare sempre il costo del progetto in base ai requisiti di archiviazione previsti e aggiungere entità duplicate solo per supportare le query che verranno eseguite dall'applicazione client.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 execute.
  • Poiché le entità di indice secondario vengono archiviate nella stessa partizione delle entità originali, è necessario assicurarsi di non superare gli obiettivi di scalabilità delle singole partizioni.Because the secondary index entities are stored in the same partition as the original entities, you should ensure that you do not exceed the scalability targets for an individual partition.
  • Per mantenere la coerenza tra entità duplicate è possibile usare transazioni ETG, che consentono di aggiornare le due copie dell'entità in modo atomico.You can keep your duplicate entities consistent with each other by using EGTs to update the two copies of the entity atomically. A questo scopo è necessario archiviare tutte le copie di un'entità nella stessa partizione.This implies that you should store all copies of an entity in the same partition. Per altre informazioni, vedere la sezione Transazioni di gruppi di entità.For more information, see the section Using Entity Group Transactions.
  • Il valore usato per RowKey deve essere univoco per ogni entità.The value used for the RowKey must be unique for each entity. Provare a usare valori di chiave composti.Consider using compound key values.
  • Il riempimento dei valori numerici in RowKey (ad esempio l'ID dipendente 000223) rende possibile l'ordinamento e il filtro corretto in base ai limiti superiori e inferiori.Padding numeric values in the RowKey (for example, the employee id 000223), enables correct sorting and filtering based on upper and lower bounds.
  • Non è necessario duplicare tutte le proprietà dell'entità.You do not necessarily need to duplicate all the properties of your entity. Se ad esempio le query che eseguono la ricerca di entità usando l'indirizzo di posta elettronica in RowKey non hanno mai bisogno dell'età del dipendente, queste entità potrebbero avere la struttura seguente:For example, if the queries that lookup the entities using the email address in the RowKey never need the employee's age, these entities could have the following structure:

  • In genere è preferibile archiviare dati duplicati e assicurarsi che sia possibile recuperare tutti i dati necessari con una singola query anziché usando una query per individuare un'entità e una seconda per cercare i dati richiesti.It is typically 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 lookup the required data.

Quando usare questo modelloWhen to use this pattern

Usare questo modello quando l'applicazione client deve recuperare le entità usando una serie di chiavi diverse, quando il client deve recuperare entità con criteri di ordinamento diversi e nei casi in cui è possibile identificare ogni entità attraverso una varietà di valori univoci.Use this pattern when your client application needs to retrieve entities using a variety of different keys, when your client needs to retrieve entities in different sort orders, and where you can identify each entity using a variety of unique values. È però necessario assicurarsi che durante l'esecuzione di ricerche di entità con valori RowKey diversi non vengano superati i limiti di scalabilità della partizione.However, you should be sure that you do not exceed the partition scalability limits when you are performing entity lookups using the different RowKey values.

Per l'implementazione di questo modello possono risultare utili i modelli e le informazioni aggiuntive seguenti:The following patterns and guidance may also be relevant when implementing this pattern:

Modello per indice secondario intrapartizioneInter-partition secondary index pattern

Archivia più copie di ogni entità usando valori RowKey diversi in partizioni separate o in tabelle separate per consentire ricerche rapide ed efficienti e ordinamenti alternativi usando valori RowKey diversi.Store multiple copies of each entity using different RowKey values in separate partitions or in separate tables to enable fast and efficient lookups and alternate sort orders by using different RowKey values.

Contesto e problemaContext and problem

Il servizio tabelle indicizza automaticamente le entità usando i valori PartitionKey e RowKey.The Table service automatically indexes entities using the PartitionKey and RowKey values. Questo consente a un'applicazione client di recuperare un'entità in modo efficiente mediante questi valori.This enables a client application to retrieve an entity efficiently using these values. Ad esempio, usando la struttura della tabella riportata di seguito, un'applicazione client può usare una query di tipo punto per recuperare una singola entità dipendente attraverso il nome del reparto e l'ID del dipendente (i valori PartitionKey e RowKey).For example, using the table structure shown below, 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 può anche recuperare entità ordinate per ID dipendente in ogni reparto.A client can also retrieve entities sorted by employee id within each department.

Se si desidera poter trovare un'entità dipendente anche in base al valore di un'altra proprietà, ad esempio l'indirizzo di posta elettronica, è necessario usare un'analisi della partizione meno efficiente per trovare una corrispondenza.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. Il motivo è che il servizio tabelle non fornisce indici secondari.This is because the table service does not provide secondary indexes. Inoltre, non esiste un'opzione per richiedere un elenco di dipendenti ordinato in modo diverso rispetto all'ordine RowKey .In addition, there is no option to request a list of employees sorted in a different order than RowKey order.

Si prevede un volume molto elevato di transazioni su queste entità e si vuole ridurre al minimo il rischio che il servizio tabelle esegua la limitazione del client.You are anticipating a very high volume of transactions against these entities and want to minimize the risk of the Table service throttling your client.

SoluzioneSolution

Per ovviare alla mancanza di indici secondari, è possibile archiviare più copie di ogni entità usando per ogni copia valori PartitionKey e RowKey diversi.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. Se si archivia un'entità con le strutture riportate di seguito, è possibile recuperare in modo efficiente entità dipendente in base all'id dipendente o all’indirizzo di posta elettronica. I valori di prefisso per PartitionKey, "empid_" e "email_", consentono di identificare l'indice da usare per una query.If you store an entity with the structures shown below, you can efficiently retrieve employee entities based on email address or employee id. The prefix values for the PartitionKey, "empid_" and "email_" enable you to identify which index you want to use for a query.

I due criteri di filtro seguenti (uno che ricerca per ID dipendente e uno che ricerca per indirizzo di posta elettronica) specificano entrambi query di tipo punto:The following two filter criteria (one looking up by employee id and one looking up by email address) both specify point queries:

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

Se si esegue una query su un intervallo di entità dipendente, è possibile specificare un intervallo ordinato per ID dipendente o un intervallo ordinato per indirizzo di posta elettronica eseguendo la query sulle entità con il prefisso appropriato in RowKey.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 by querying for entities with the appropriate prefix in the RowKey.

  • Per trovare tutti i dipendenti del reparto vendite con un ID dipendente nell'intervallo compreso tra 000100 e 000199 ordinati in base all'ID dipendente, usare: $filter=(PartitionKey eq 'empid_Sales') e (RowKey ge '000100') e (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')
  • Per trovare tutti i dipendenti del reparto vendite con un indirizzo di posta elettronica che inizia con 'a' ordinato in base all’indirizzo di posta elettronica utilizzare: $filter = (PartitionKey eq ' email_Sales') e (RowKey ge 'a') e (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')

Si noti che la sintassi di filtro usata negli esempi precedenti proviene dall'API REST del servizio tabelle. Per altre informazioni, vedere Query Entities (Entità query).Note that the filter syntax used in the examples above is from the Table service REST API, for more information see Query Entities.

Considerazioni e problemiIssues and considerations

Prima di decidere come implementare questo modello, considerare quanto segue:Consider the following points when deciding how to implement this pattern:

  • Per mantenere la coerenza finale tra le entità duplicate, è possibile usare il Modello per transazioni con coerenza finale per gestire le entità di indice primario e secondario.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'uso dell'archiviazione tabelle è relativamente economico, pertanto l'aumento dei costi dovuto all'archiviazione di dati duplicati non dovrebbe rappresentare una preoccupazione.Table storage is relatively cheap to use so the cost overhead of storing duplicate data should not be a major concern. È però consigliabile valutare sempre il costo del progetto in base ai requisiti di archiviazione previsti e aggiungere entità duplicate solo per supportare le query che verranno eseguite dall'applicazione client.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 execute.
  • Il valore usato per RowKey deve essere univoco per ogni entità.The value used for the RowKey must be unique for each entity. Provare a usare valori di chiave composti.Consider using compound key values.
  • Il riempimento dei valori numerici in RowKey (ad esempio l'ID dipendente 000223) rende possibile l'ordinamento e il filtro corretto in base ai limiti superiori e inferiori.Padding numeric values in the RowKey (for example, the employee id 000223), enables correct sorting and filtering based on upper and lower bounds.
  • Non è necessario duplicare tutte le proprietà dell'entità.You do not necessarily need to duplicate all the properties of your entity. Se ad esempio le query che eseguono la ricerca di entità usando l'indirizzo di posta elettronica in RowKey non hanno mai bisogno dell'età del dipendente, queste entità potrebbero avere la struttura seguente:For example, if the queries that lookup the entities using the email address in the RowKey never need the employee's age, these entities could have the following structure:

  • In genere è preferibile archiviare dati duplicati e assicurarsi che sia possibile recuperare tutti i dati necessari con una singola query anziché usando una query per individuare un'entità mediante l'indice secondario e un'altra per cercare i dati richiesti nell'indice primario.It is typically 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 using the secondary index and another to lookup the required data in the primary index.

Quando usare questo modelloWhen to use this pattern

Usare questo modello quando l'applicazione client deve recuperare le entità usando una serie di chiavi diverse, quando il client deve recuperare entità con criteri di ordinamento diversi e nei casi in cui è possibile identificare ogni entità attraverso una varietà di valori univoci.Use this pattern when your client application needs to retrieve entities using a variety of different keys, when your client needs to retrieve entities in different sort orders, and where you can identify each entity using a variety of unique values. Usare questo modello quando si vuole evitare il superamento dei limiti di scalabilità della partizione durante l'esecuzione di ricerche di entità con i diversi valori RowKey .Use this pattern when you want to avoid exceeding the partition scalability limits when you are performing entity lookups using the different RowKey values.

Per l'implementazione di questo modello possono risultare utili i modelli e le informazioni aggiuntive seguenti:The following patterns and guidance may also be relevant when implementing this pattern:

Modello per transazioni con coerenza finaleEventually consistent transactions pattern

abilita un comportamento di coerenza finale tra i limiti della partizione o i limiti del sistema di archiviazione usando le code di Azure.Enable eventually consistent behavior across partition boundaries or storage system boundaries by using Azure queues.

Contesto e problemaContext and problem

Le transazioni ETG consentono l'esecuzione di transazioni atomiche tra più entità che condividono la stessa chiave di partizione.EGTs enable atomic transactions across multiple entities that share the same partition key. Per motivi di scalabilità e prestazioni, si può scegliere di archiviare le entità con requisiti di coerenza in partizioni separate o in un sistema di archiviazione separato: in questo caso, non è possibile usare le transazioni ETG per mantenere la coerenza.For performance and scalability reasons, you might decide to store entities that have consistency requirements in separate partitions or in a separate storage system: in such a scenario, you cannot use EGTs to maintain consistency. Ad esempio, potrebbe essere necessario mantenere la coerenza finale tra:For example, you might have a requirement to maintain eventual consistency between:

  • Entità archiviate in due partizioni diverse nella stessa tabella, in tabelle diverse, in account di archiviazione diversi.Entities stored in two different partitions in the same table, in different tables, in in different storage accounts.
  • Un'entità archiviata nel servizio tabelle e un BLOB archiviato nel servizio BLOB.An entity stored in the Table service and a blob stored in the Blob service.
  • Un'entità archiviata nel servizio tabelle e un file in un file system.An entity stored in the Table service and a file in a file system.
  • Un'entità archiviata nel servizio tabelle, ma indicizzata mediante Ricerca di Azure.An entity store in the Table service yet indexed using the Azure Search service.

SoluzioneSolution

Usando le code di Azure, è possibile implementare una soluzione che offre coerenza finale tra due o più partizioni o sistemi di archiviazione.By using Azure queues, you can implement a solution that delivers eventual consistency across two or more partitions or storage systems. Per illustrare questo approccio, si supponga di avere l'esigenza di archiviare le entità relative ai dipendenti precedenti.To illustrate this approach, assume you have a requirement to be able to archive old employee entities. Queste entità sono raramente oggetto di query e devono essere escluse da tutte le attività associate ai dipendenti correnti.Old employee entities are rarely queried and should be excluded from any activities that deal with current employees. Per implementare questo requisito è necessario archiviare i dipendenti attivi nella tabella dei dipendenti Correnti e i dipendenti precedenti nella tabella dei dipendenti Archiviati.To implement this requirement you store active employees in the Current table and old employees in the Archive table. Per archiviare un dipendente è necessario eliminare l'entità dalla tabella dei dipendenti Correnti e aggiungerla a quella dei dipendenti Archiviati, ma non è possibile usare una transazione ETG per eseguire queste due operazioni.Archiving an employee requires you to delete the entity from the Current table and add the entity to the Archive table, but you cannot use an EGT to perform these two operations. Per evitare il rischio che, a causa di un errore, un'entità venga visualizzata in entrambe le tabelle o in nessuna di esse, l'operazione di archiviazione deve garantire la coerenza finale.To avoid the risk that a failure causes an entity to appear in both or neither tables, the archive operation must be eventually consistent. Il diagramma seguente illustra in sequenza i passaggi di questa operazione.The following sequence diagram outlines the steps in this operation. Nel testo che segue sono disponibili maggiori dettagli per i percorsi di eccezione.More detail is provided for exception paths in the text following.

Un client avvia l'operazione di archiviazione inserendo un messaggio in una coda di Azure, in questo esempio per l'archiviazione del dipendente 456.A client initiates the archive operation by placing a message on an Azure queue, in this example to archive employee #456. Un ruolo di lavoro esegue il polling della coda per individuare i nuovi messaggi. Quando ne trova uno, legge il messaggio e lascia una copia nascosta nella coda.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. Successivamente, il ruolo di lavoro recupera una copia dell'entità dalla tabella dei dipendenti Correnti, inserisce una copia nella tabella dei dipendenti Archiviati e quindi elimina l'originale dalla tabella dei dipendenti Correnti.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. Infine, se nei passaggi precedenti non si sono verificati errori, il ruolo di lavoro elimina il messaggio nascosto dalla coda.Finally, if there were no errors from the previous steps, the worker role deletes the hidden message from the queue.

In questo esempio, il passaggio 4 inserisce il dipendente nella tabella dei dipendenti Archiviati .In this example, step 4 inserts the employee into the Archive table. Potrebbe aggiungere il dipendente a un BLOB nel servizio BLOB o un file in un file system.It could add the employee to a blob in the Blob service or a file in a file system.

Ripristino da erroriRecovering from failures

È importante che le operazioni nei passaggi 4 e 5 siano idempotenti nei casi in cui il ruolo di lavoro deve riavviare l'operazione di archiviazione.It is important that the operations in steps 4 and 5 must be idempotent in case the worker role needs to restart the archive operation. Se si sta usando il servizio tabelle, per il passaggio 4 è consigliabile usare un'operazione "insert or replace"; per il passaggio 5 è consigliabile usare un'operazione "delete if exists" nella libreria client in uso.If you are using the Table service, 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 are using. Se si sta usando un altro sistema di archiviazione, è consigliabile usare un'operazione idempotente appropriata.If you are using another storage system, you must use an appropriate idempotent operation.

Se il ruolo di lavoro non completa mai il passaggio 6, dopo un timeout il messaggio ricompare nella coda, pronto per una nuova elaborazione da parte del ruolo di lavoro.If the worker role never completes step 6, then after a timeout the message reappears on the queue ready for the worker role to try to reprocess it. Il ruolo di lavoro può controllare quante volte un messaggio nella coda è stato letto e, se necessario, contrassegnarlo come messaggio non elaborabile da analizzare inviandolo a una coda separata.The worker role can check how many times a message on the queue has been read and, if necessary, flag it is a "poison" message for investigation by sending it to a separate queue. Per altre informazioni sulla lettura dei messaggi in coda e la verifica del numero di rimozioni dalla coda, vedere Get Messages.For more information about reading queue messages and checking the dequeue count, see Get Messages.

Alcuni errori del servizio tabelle e del servizio di accodamento sono temporanei e l'applicazione client deve includere la logica di ripetizione dei tentativi appropriata per gestirli.Some errors from the Table and Queue services are transient errors, and your client application should include suitable retry logic to handle them.

Considerazioni e problemiIssues and considerations

Prima di decidere come implementare questo modello, considerare quanto segue:Consider the following points when deciding how to implement this pattern:

  • Questa soluzione non prevede l'isolamento delle transazioni.This solution does not provide for transaction isolation. Ad esempio, un client potrebbe leggere le tabelle dei dipendenti Correnti e Archiviati mentre il ruolo di lavoro è tra i passaggi 4 e 5 e ottenere una vista incoerente dei dati.For example, a client could read the Current and Archive tables when the worker role was between steps 4 and 5, and see an inconsistent view of the data. Si noti che alla fine i dati saranno coerenti.Note that the data will be consistent eventually.
  • È necessario assicurarsi che i passaggi 4 e 5 siano idempotenti per garantire la coerenza finale.You must be sure that steps 4 and 5 are idempotent in order to ensure eventual consistency.
  • È possibile ridimensionare la soluzione usando più code e istanze del ruolo di lavoro.You can scale the solution by using multiple queues and worker role instances.

Quando usare questo modelloWhen to use this pattern

Usare questo modello quando si desidera garantire la coerenza finale tra entità esistenti in tabelle o partizioni diverse.Use this pattern when you want to guarantee eventual consistency between entities that exist in different partitions or tables. È possibile estendere il modello per garantire la coerenza finale per le operazioni tra il servizio tabelle e il servizio BLOB e altre origini dati di archiviazione non Azure, quali database o file system.You can extend this pattern to ensure eventual consistency for operations across the Table service and the Blob service and other non-Azure Storage data sources such as database or the file system.

Per l'implementazione di questo modello possono risultare utili i modelli e le informazioni aggiuntive seguenti:The following patterns and guidance may also be relevant when implementing this pattern:

Nota

Se l'isolamento delle transazioni è importante per la soluzione, è consigliabile riprogettare le tabelle per consentire l'uso delle transazioni ETG.If transaction isolation is important to your solution, you should consider redesigning your tables to enable you to use EGTs.

Modello per entità di indiceIndex Entities Pattern

mantiene le entità di indice per consentire ricerche efficienti che restituiscano elenchi di entità.Maintain index entities to enable efficient searches that return lists of entities.

Contesto e problemaContext and problem

Il servizio tabelle indicizza automaticamente le entità usando i valori PartitionKey e RowKey.The Table service automatically indexes entities using the PartitionKey and RowKey values. Consente a un'applicazione client di recuperare un'entità in modo efficiente mediante una query di tipo punto.This enables a client application to retrieve an entity efficiently using a point query. Ad esempio, usando la struttura della tabella riportata di seguito, un'applicazione client può recuperare in modo efficiente una singola entità dipendente usando il nome del reparto e l'ID del dipendente (i valori PartitionKey e RowKey).For example, using the table structure shown below, a client application can efficiently retrieve an individual employee entity by using the department name and the employee id (the PartitionKey and RowKey).

Se si desidera poter recuperare un elenco di entità dipendente anche in base al valore di un'altra proprietà non univoca, ad esempio il cognome, è necessario usare un'analisi della partizione meno efficiente per trovare una corrispondenza piuttosto che usare un indice per la ricerca diretta.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 their last name, you must use a less efficient partition scan to find matches rather than using an index to look them up directly. Il motivo è che il servizio tabelle non fornisce indici secondari.This is because the table service does not provide secondary indexes.

SoluzioneSolution

Per attivare la ricerca per cognome con la struttura delle entità illustrata in precedenza, è necessario gestire elenchi di ID dipendente.To enable lookup by last name with the entity structure shown above, you must maintain lists of employee ids. Per recuperare le entità dipendente con un determinato cognome, ad esempio Jones, è necessario innanzitutto individuare l'elenco di ID relativi ai dipendenti con il cognome Jones e quindi recuperare tali entità dipendente.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. Per l'archiviazione dell'elenco di ID dipendente sono disponibili tre opzioni principali:There are three main options for storing the lists of employee ids:

  • Usare l'archiviazione BLOB.Use blob storage.
  • Creare entità di indice nella stessa partizione delle entità dipendente.Create index entities in the same partition as the employee entities.
  • Creare entità di indice in una tabella o una partizione separata.Create index entities in a separate partition or table.

Opzione 1: usare l'archiviazione BLOBOption #1: Use blob storage

Per la prima opzione è necessario creare un BLOB per ogni cognome univoco e archiviare in ogni BLOB un elenco dei valori PartitionKey (reparto) e RowKey (ID dipendente) per i dipendenti con questo cognome.For the first option, you 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 that have that last name. Quando si aggiunge o elimina un dipendente, è necessario verificare la coerenza finale tra il contenuto del BLOB pertinente e le entità dipendente.When you add or delete an employee you should ensure that the content of the relevant blob is eventually consistent with the employee entities.

Opzione 2: creare entità di indice nella stessa partizioneOption #2: Create index entities in the same partition

Per la seconda opzione, usare entità di indice che archiviano i dati seguenti:For the second option, use index entities that store the following data:

La proprietà EmployeeIDs contiene un elenco di ID dipendente per i dipendenti con il cognome archiviato in RowKey.The EmployeeIDs property contains a list of employee ids for employees with the last name stored in the RowKey.

I passaggi seguenti illustrano il processo da seguire per aggiungere un nuovo dipendente se si usa la seconda opzione.The following steps outline the process you should follow when you are adding a new employee if you are using the second option. In questo esempio si aggiunge al reparto vendite un dipendente con ID 000152 e cognome Jones:In this example, we are adding an employee with Id 000152 and a last name Jones in the Sales department:

  1. Recuperare l'entità di indice con il valore PartitionKey "Sales" e il valore RowKey "Jones".Retrieve the index entity with a PartitionKey value "Sales" and the RowKey value "Jones." Salvare il valore ETag dell'entità per usarlo nel passaggio 2.Save the ETag of this entity to use in step 2.
  2. Creare una transazione del gruppo di entità (cioè un'operazione batch) che inserisca la nuova entità dipendente (con valore PartitionKey "Sales" e valore RowKey "000152") e aggiorni l'entità di indice (con valore PartitionKey "Sales" e valore RowKey "Jones") aggiungendo il nuovo ID dipendente all'elenco nel campo EmployeeIDs.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") by adding the new employee id to the list in the EmployeeIDs field. Per informazioni sulle transazioni di gruppi di entità, vedere la sezione Transazioni di gruppi di entità.For more information about entity group transactions, see Entity Group Transactions.
  3. Se la transazione del gruppo di entità ha esito negativo a causa di un errore di concorrenza ottimistica (un altro utente ha appena modificato l'entità di indice), è necessario ricominciare dal passaggio 1.If the entity group transaction fails because of an optimistic concurrency error (someone else has just modified the index entity), then you need to start over at step 1 again.

Se si usa la seconda opzione, è possibile adottare un approccio simile per l'eliminazione di un dipendente.You can use a similar approach to deleting an employee if you are using the second option. Modificare il cognome del dipendente è un'operazione leggermente più complessa, in quanto è necessario eseguire una transazione del gruppo di entità che aggiorna tre entità: l'entità dipendente, l'entità di indice per il cognome precedente e l'entità di indice per il nuovo cognome.Changing an employee's last name is slightly more complex because you will need to execute an entity group transaction that updates three entities: the employee entity, the index entity for the old last name, and the index entity for the new last name. È necessario recuperare ogni entità prima di apportare qualsiasi modifica, per recuperare i valori ETag da usare in seguito per eseguire gli aggiornamenti usando la concorrenza ottimistica.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 using optimistic concurrency.

I passaggi seguenti illustrano il processo da seguire per cercare tutti i dipendenti di un reparto con un determinato cognome se si usa la seconda opzione.The following steps outline the process you should follow when you need to look up all the employees with a given last name in a department if you are using the second option. In questo esempio si cercano tutti i dipendenti del reparto vendite il cui cognome è Jones:In this example, we are looking up all the employees with last name Jones in the Sales department:

  1. Recuperare l'entità di indice con il valore PartitionKey "Sales" e il valore RowKey "Jones".Retrieve the index entity with a PartitionKey value "Sales" and the RowKey value "Jones."
  2. Analizzare l'elenco di ID dipendente nel campo EmployeeIDs.Parse the list of employee Ids in the EmployeeIDs field.
  3. Se sono necessarie informazioni aggiuntive su ognuno dei dipendenti (ad esempio gli indirizzi e-mail), recuperare ognuna delle entità dipendente usando il valore PartitionKey "Sales" e i valori RowKey dall'elenco dei dipendenti ottenuti nel passaggio 2.If you need additional information about each of these employees (such as their email addresses), retrieve each of the employee entities using PartitionKey value "Sales" and RowKey values from the list of employees you obtained in step 2.

Opzione 3: creare entità di indice in una tabella o una partizione separataOption #3: Create index entities in a separate partition or table

Per la terza opzione, usare entità di indice che archiviano i dati seguenti:For the third option, use index entities that store the following data:

La proprietà EmployeeIDs contiene un elenco di ID dipendente per i dipendenti con il cognome archiviato in RowKey.The EmployeeIDs property contains a list of employee ids for employees with the last name stored in the RowKey.

Con la terza opzione non è possibile usare transazioni ETG per mantenere la coerenza, in quanto le entità di indice si trovano in una partizione separata rispetto alle entità dipendente.With the third option, you cannot use EGTs to maintain consistency because the index entities are in a separate partition from the employee entities. È necessario assicurarsi della coerenza finale tra le entità di indice e le entità dipendente.You should ensure that the index entities are eventually consistent with the employee entities.

Considerazioni e problemiIssues and considerations

Prima di decidere come implementare questo modello, considerare quanto segue:Consider the following points when deciding how to implement this pattern:

  • Questa soluzione richiede almeno due query per recuperare le entità corrispondenti: una sulle entità di indice per ottenere l'elenco di valori RowKey e altre query per il recupero di ogni entità dell'elenco.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.
  • Poiché una singola entità ha una dimensione massima di 1 MB, le opzioni 2 e 3 della soluzione presuppongono che l'elenco di ID dipendente per qualsiasi cognome non sia mai più grande di 1 MB.Given that 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 given last name is never greater than 1 MB. Se è probabile che l'elenco di ID dipendente abbia dimensioni superiori a 1 MB, usare l'opzione 1 e archiviare i dati di indice nell'archiviazione BLOB.If the list of employee ids is likely to be greater than 1 MB in size, use option #1 and store the index data in blob storage.
  • Se si usa l'opzione 2 (uso di transazioni EGT per gestire l'aggiunta e l'eliminazione dei dipendenti e la modifica del cognome di un dipendente), è necessario valutare se il volume delle transazioni raggiungerà i limiti di scalabilità in una determinata partizione.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 given partition. In tal caso, è opportuno considerare una soluzione con coerenza finale (opzione 1 o 3) che gestisca le richieste di aggiornamento mediante code e consenta di archiviare le entità di indice in una partizione separata rispetto alle entità dipendente.If this is the case, you should consider an eventually consistent solution (option #1 or option #3) that uses queues to handle the update requests and enables you to store your index entities in a separate partition from the employee entities.
  • L'opzione 2 di questa soluzione presuppone che si vogliano effettuare ricerche in base al cognome all'interno di un reparto, ad esempio recuperare un elenco di dipendenti del reparto vendite il cui cognome è Jones.Option #2 in this solution assumes that you want to look up by last name within a department: for example, you want to retrieve a list of employees with a last name Jones in the Sales department. Se si desidera poter cercare tutti i dipendenti il cui cognome è Jones nell'intera organizzazione, usare l'opzione 1 o l'opzione 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.
  • È possibile implementare una soluzione basata su code che garantisca coerenza finale. Per altri dettagli, vedere Modello per transazioni con coerenza finale.You can implement a queue-based solution that delivers eventual consistency (see the Eventually consistent transactions pattern for more details).

Quando usare questo modelloWhen to use this pattern

Usare questo modello quando si desidera cercare un set di entità che condividono un valore di proprietà comune, ad esempio tutti i dipendenti con il cognome Jones.Use this pattern when you want to lookup a set of entities that all share a common property value, such as all employees with the last name Jones.

Per l'implementazione di questo modello possono risultare utili i modelli e le informazioni aggiuntive seguenti:The following patterns and guidance may also be relevant when implementing this pattern:

Modello di denormalizzazioneDenormalization pattern

combina i dati correlati in una singola entità per consentire di recuperare tutti i dati necessari con un sola query di tipo punto.Combine related data together in a single entity to enable you to retrieve all the data you need with a single point query.

Contesto e problemaContext and problem

In un database relazionale, in genere i dati vengono normalizzati per rimuovere i risultati duplicati nelle query che recuperano dati da più tabelle.In a relational database, you typically normalize data to remove duplication resulting in queries that retrieve data from multiple tables. Se si normalizzano i dati nelle tabelle di Azure, è necessario eseguire più round trip dal client al server per recuperare i dati correlati.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. Con la struttura della tabella mostrata di seguito, ad esempio, per recuperare i dettagli per un reparto sono necessari due round trip: uno per recuperare l'entità reparto che include l'ID del manager e una seconda richiesta per recuperare i dettagli sul manager in un'entità dipendente.For example, with the table structure shown below you need two round trips to retrieve the details for a department: one to fetch the department entity that includes the manager's id, and then another request to fetch the manager's details in an employee entity.

SoluzioneSolution

Anziché archiviare i dati in due entità separate, denormalizzare i dati e conservare una copia dei dettagli sul manager nell'entità reparto.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. Ad esempio: For example:

Archiviando le entità reparto con queste proprietà, è possibile recuperare tutti i dettagli necessari su un reparto mediante una query di tipo punto.With department entities stored with these properties, you can now retrieve all the details you need about a department using a point query.

Considerazioni e problemiIssues and considerations

Prima di decidere come implementare questo modello, considerare quanto segue:Consider the following points when deciding how to implement this pattern:

  • Archiviare alcuni dati due volte comporta un aumento dei costi.There is some cost overhead associated with storing some data twice. Il miglioramento delle prestazioni (risultante dal minor numero di richieste al servizio di archiviazione) in genere compensa l'incremento marginale dei costi di archiviazione, che per altro è parzialmente compensato dalla riduzione del numero di transazioni necessarie per recuperare i dettagli relativi a un reparto.The performance benefit (resulting from fewer requests to the storage service) typically outweighs the marginal increase in storage costs (and this cost is partially offset by a reduction in the number of transactions you require to fetch the details of a department).
  • È necessario mantenere la coerenza tra le due entità in cui sono archiviate le informazioni sui manager.You must maintain the consistency of the two entities that store information about managers. Il problema della coerenza può essere gestito usando transazioni ETG per aggiornare più entità in una singola transazione atomica: in questo caso, l'entità reparto e l'entità dipendente per il responsabile del reparto vengono archiviate nella stessa partizione.You can handle the consistency issue by using EGTs to update multiple entities in a single atomic transaction: in this case, the department entity, and the employee entity for the department manager are stored in the same partition.

Quando usare questo modelloWhen to use this pattern

Usare questo modello quando è necessario cercare spesso informazioni correlate.Use this pattern when you frequently need to look up related information. Questo modello riduce il numero di query che il client deve eseguire per recuperare i dati necessari.This pattern reduces the number of queries your client must make to retrieve the data it requires.

Per l'implementazione di questo modello possono risultare utili i modelli e le informazioni aggiuntive seguenti:The following patterns and guidance may also be relevant when implementing this pattern:

Modello per chiave compostaCompound key pattern

Usa valori RowKey composti per consentire a un client di cercare dati correlati con una sola query di tipo punto.Use compound RowKey values to enable a client to lookup related data with a single point query.

Contesto e problemaContext and problem

In un database relazionale è piuttosto normale usare join nelle query per restituire dati correlati al client in una singola query.In a relational database, it is quite natural to use joins in queries to return related pieces of data to the client in a single query. Ad esempio, si può usare l'ID dipendente per cercare un elenco di entità correlate che contengono i dati relativi alle prestazioni e alle valutazioni per tale dipendente.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.

Si supponga di archiviare le entità dipendente nel servizio tabelle usando la struttura seguente:Assume you are storing employee entities in the Table service using the following structure:

È inoltre necessario archiviare i dati cronologici relativi alle valutazioni e alle prestazioni per ogni anno che il dipendente ha lavorato presso l'organizzazione, nonché poter accedere a queste informazioni in base all'anno.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. Una possibilità consiste nel creare un'altra tabella di archiviazione delle entità con la struttura seguente:One option is to create another table that stores entities with the following structure:

Si noti che con questo approccio è possibile decidere di duplicare alcune informazioni (ad esempio nome e cognome) nella nuova entità, in modo da poter recuperare i dati con una singola richiesta.Notice that with this approach you may 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. Non è tuttavia possibile mantenere la coerenza assoluta, in quanto non si può usare una transazione EGT per aggiornare le entità in modo atomico.However, you cannot maintain strong consistency because you cannot use an EGT to update the two entities atomically.

SoluzioneSolution

Archiviare un nuovo tipo di entità nella tabella originale usando entità con la struttura seguente:Store a new entity type in your original table using entities with the following structure:

Si noti che ora il valore di RowKey è una chiave composta costituita dall'ID dipendente e dall'anno dei dati di valutazione, che consente di recuperare le prestazioni e le valutazioni del dipendente con una singola richiesta per una singola entità.Notice how the RowKey is now a compound key made up of the employee id and the year of the review data that enables you to retrieve the employee's performance and review data with a single request for a single entity.

L'esempio seguente illustra come recuperare tutti i dati di valutazione per uno specifico dipendente (ad esempio il dipendente 000123 del reparto vendite):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

Considerazioni e problemiIssues and considerations

Prima di decidere come implementare questo modello, considerare quanto segue:Consider the following points when deciding how to implement this pattern:

  • È consigliabile usare un carattere separatore appropriato che semplifichi l'analisi del valore RowKey, ad esempio 000123_2012.You should use a suitable separator character that makes it easy to parse the RowKey value: for example, 000123_2012.
  • Inoltre, si sta archiviando l'entità nella stessa partizione di altre entità che contengono dati correlati per lo stesso dipendente, dunque è possibile usare transazioni EGT per mantenere la coerenza assoluta.You are also storing this entity in the same partition as other entities that contain related data for the same employee, which means you can use EGTs to maintain strong consistency.
  • Per determinare se questo modello è appropriato, considerare la frequenza con cui si eseguiranno query sui dati.You should consider how frequently you will query the data to determine whether this pattern is appropriate. Ad esempio, se si accederà raramente ai dati di valutazione e spesso ai dati principali sul dipendente, è consigliabile conservarli come entità separate.For example, if you will access the review data infrequently and the main employee data often you should keep them as separate entities.

Quando usare questo modelloWhen to use this pattern

Usare questo modello quando è necessario archiviare una o più entità correlate su cui si eseguono query frequenti.Use this pattern when you need to store one or more related entities that you query frequently.

Per l'implementazione di questo modello possono risultare utili i modelli e le informazioni aggiuntive seguenti:The following patterns and guidance may also be relevant when implementing this pattern:

Modello della parte finale del logLog tail pattern

Recupera le n entità aggiunte più di recente a una partizione in base a un valore RowKey che usa un ordinamento inverso di data e ora.Retrieve the n entities most recently added to a partition by using a RowKey value that sorts in reverse date and time order.

Contesto e problemaContext and problem

Un requisito comune è poter recuperare le entità create più di recente, ad esempio le ultime dieci note di rimborso spese inviate da un dipendente.A common requirement is be able to retrieve the most recently created entities, for example the ten most recent expense claims submitted by an employee. Le query sulle tabelle supportano un'operazione di query $top per restituire le prime n entità di un set. Non esiste un'operazione di query equivalente per la restituzione delle ultime n entità di un set.Table queries support a $top query operation to return the first n entities from a set: there is no equivalent query operation to return the last n entities in a set.

SoluzioneSolution

Archiviare le entità usando un valore RowKey che usa un ordinamento inverso di data e ora, in modo che la voce più recente sia sempre la prima della tabella.Store the entities using a RowKey that naturally sorts in reverse date/time order by using so the most recent entry is always the first one in the table.

Ad esempio, per poter recuperare le ultime dieci note di rimborso spese inviate da un dipendente, è possibile usare un valore di tick inverso derivato dal valore di data/ora corrente.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'esempio di codice C# seguente illustra un modo per creare un valore "invertedTicks" appropriato per un valore RowKey che ordina dal più recente al meno recente: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);

Per tornare al valore di data e ora, usare il codice seguente:You can get back to the date time value using the following code:

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

La query sulla tabella ha un aspetto simile al seguente:The table query looks like this:

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

Considerazioni e problemiIssues and considerations

Prima di decidere come implementare questo modello, considerare quanto segue:Consider the following points when deciding how to implement this pattern:

  • È necessario aggiungere zeri iniziali al valore di tick inverso per assicurarsi che il valore di stringa venga ordinato come previsto.You must pad the reverse tick value with leading zeroes to ensure the string value sorts as expected.
  • È necessario tenere presenti gli obiettivi di scalabilità a livello di partizione.You must be aware of the scalability targets at the level of a partition. Fare attenzione a non creare partizioni critiche.Be careful not create hot spot partitions.

Quando usare questo modelloWhen to use this pattern

Usare questo modello quando si desidera accedere alle entità in ordine di data/ora inverso o quando è necessario accedere alle entità aggiunte più di recente.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.

Per l'implementazione di questo modello possono risultare utili i modelli e le informazioni aggiuntive seguenti:The following patterns and guidance may also be relevant when implementing this pattern:

Modello di eliminazione volume elevatoHigh volume delete pattern

Abilitare l'eliminazione di un volume elevato di entità mediante l'archiviazione di tutte le entità per l'eliminazione simultanea nella relativa tabella separata; per eliminare le entità, eliminare la tabella.Enable the deletion of a high volume of entities by storing all the entities for simultaneous deletion in their own separate table; you delete the entities by deleting the table.

Contesto e problemaContext and problem

Molte applicazioni eliminano vecchi dati non più necessari a un'applicazione client o che l'applicazione ha archiviato in un altro supporto di archiviazione.Many applications delete old data which no longer needs to be available to a client application, or that the application has archived to another storage medium. In genere questi dati vengono identificati da una data; è presente un requisito che prevede l'eliminazione dei record di tutte le richieste di accesso risalenti a oltre 60 giorni prima.You typically identify such data by a date: for example, you have a requirement to delete records of all login requests that are more than 60 days old.

Una possibile progettazione consiste nell'usare la data e l'ora della richiesta di accesso in RowKey:One possible design is to use the date and time of the login request in the RowKey:

Questo approccio evita hotspot di partizione perché l'applicazione può inserire ed eliminare entità di accesso per ogni utente in una partizione separata,This approach avoids partition hotspots because the application can insert and delete login entities for each user in a separate partition. ma può rivelarsi dispendioso in termini di denaro e tempo se si dispone di un numero elevato di entità perché è necessario innanzitutto eseguire un'analisi di tabella per identificare tutte le entità da eliminare e successivamente eliminare ogni entità precedente.However, this approach may be costly and time consuming if you have a large number of entities because 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. Si noti che è possibile ridurre il numero di round trip al server necessari per eliminare le entità precedenti raggruppando più richieste di eliminazione nelle transazioni EGT.Note that you can reduce the number of round trips to the server required to delete the old entities by batching multiple delete requests into EGTs.

SoluzioneSolution

Usare una tabella separata per ogni giorno di tentativi di accesso.Use a separate table for each day of login attempts. È possibile usare la progettazione di entità riportata sopra per evitare hotspot durante l'inserimento di entità; l'eliminazione di entità comporterà semplicemente l'eliminazione di una tabella al giorno (una singola operazione di archiviazione) invece della ricerca ed eliminazione di centinaia o migliaia di singole entità ogni giorno.You can use the entity design above to avoid hotspots when you are inserting entities, and 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 login entities every day.

Considerazioni e problemiIssues and considerations

Prima di decidere come implementare questo modello, considerare quanto segue:Consider the following points when deciding how to implement this pattern:

  • La progettazione supporta altre modalità di uso dei dati da parte dell'applicazione, come la ricerca di entità specifiche, il collegamento con altri dati o la generazione di informazioni aggregate?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?
  • La progettazione consente di evitare hotspot durante l'inserimento di nuove entità?Does your design avoid hot spots when you are inserting new entities?
  • Se si vuole riutilizzare lo stesso nome di tabella dopo l'eliminazione, prevedere un ritardo.Expect a delay if you want to reuse the same table name after deleting it. È consigliabile usare sempre nomi di tabella univoci.It's better to always use unique table names.
  • Prevedere una limitazione delle richieste quando si usa per la prima volta una nuova tabella mentre il servizio tabelle apprende i modelli di accesso e le partizioni vengono distribuite in nodi.Expect some throttling when you first use a new table while the Table service learns the access patterns and distributes the partitions across nodes. È necessario considerare la frequenza con cui è necessario creare nuove tabelle.You should consider how frequently you need to create new tables.

Quando usare questo modelloWhen to use this pattern

Usare questo modello quando si dispone di un volume elevato di entità che è necessario eliminare contemporaneamente.Use this pattern when you have a high volume of entities that you must delete at the same time.

Per l'implementazione di questo modello possono risultare utili i modelli e le informazioni aggiuntive seguenti:The following patterns and guidance may also be relevant when implementing this pattern:

Modello di serie di datiData series pattern

Archiviare serie di dati complete in un'unica entità per ridurre al minimo il numero di richieste effettuate.Store complete data series in a single entity to minimize the number of requests you make.

Contesto e problemaContext and problem

Spesso un'applicazione archivia una serie di dati richiesti di frequente per recuperarli tutti simultaneamente.A common scenario is for an application to store a series of data that it typically needs to retrieve all at once. L'applicazione potrebbe, ad esempio, registrare il numero di messaggi immediati che ogni dipendente invia ogni ora e quindi usare queste informazioni per tracciare il numero di messaggi inviati da ogni utente nelle 24 ore precedenti.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. Una progettazione potrebbe essere l'archiviazione di 24 entità per ogni dipendente:One design might be to store 24 entities for each employee:

Con questa progettazione è possibile individuare e aggiornare l'entità da aggiornare per ogni dipendente ogni volta che l'applicazione deve aggiornare il valore del numero di messaggi.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. Tuttavia, per recuperare le informazioni allo scopo di tracciare un grafico dell'attività per le 24 ore precedenti, è necessario recuperare 24 entità.However, to retrieve the information to plot a chart of the activity for the preceding 24 hours, you must retrieve 24 entities.

SoluzioneSolution

Usare la progettazione seguente con una proprietà separata per archiviare il numero di messaggi per ogni ora:Use the following design with a separate property to store the message count for each hour:

Con questa progettazione è possibile usare un'operazione di unione per aggiornare il numero di messaggi per un dipendente per un'ora specifica.With this design, you can use a merge operation to update the message count for an employee for a specific hour. A questo punto, è possibile recuperare tutte le informazioni necessarie per tracciare il grafico usando una richiesta per una singola entità.Now, you can retrieve all the information you need to plot the chart using a request for a single entity.

Considerazioni e problemiIssues and considerations

Prima di decidere come implementare questo modello, considerare quanto segue:Consider the following points when deciding how to implement this pattern:

  • Se la serie di dati completa non rientra in una singola entità (un'entità può contenere fino a 252 proprietà), usare un archivio dati alternativo, ad esempio un BLOB.If your complete data series does not fit into a single entity (an entity can have up to 252 properties), use an alternative data store such as a blob.
  • Se sono presenti più client che aggiornano un'entità contemporaneamente, sarà necessario usare il ETag per implementare la concorrenza ottimistica.If you have multiple clients updating an entity simultaneously, you will need to use the ETag to implement optimistic concurrency. Se si dispone di molti client, potrebbe verificarsi un conflitto elevato.If you have many clients, you may experience high contention.

Quando usare questo modelloWhen to use this pattern

Usare questo modello quando è necessario aggiornare e recuperare una serie di dati associata a una singola entità.Use this pattern when you need to update and retrieve a data series associated with an individual entity.

Per l'implementazione di questo modello possono risultare utili i modelli e le informazioni aggiuntive seguenti:The following patterns and guidance may also be relevant when implementing this pattern:

Modello di entità di grandi dimensioniWide entities pattern

Usare più entità fisiche per archiviare entità logiche con più di 252 proprietà.Use multiple physical entities to store logical entities with more than 252 properties.

Contesto e problemaContext and problem

Una singola entità può avere più di 252 proprietà (escludendo le proprietà di sistema obbligatorie) e non è possibile memorizzare più di 1 MB di dati in totale.An individual entity can have no more than 252 properties (excluding the mandatory system properties) and cannot store more than 1 MB of data in total. In un database relazionale è in genere possibile aggirare gli eventuali limiti sulle dimensioni di una riga aggiungendo una nuova tabella e applicando una relazione 1 a 1 tra di esse.In a relational database, you would typically get round any limits on the size of a row by adding a new table and enforcing a 1-to-1 relationship between them.

SoluzioneSolution

Usando il servizio tabelle, è possibile archiviare più entità per rappresentare un singolo oggetto aziendale di grandi dimensioni con più di 252 proprietà.Using the Table service, you can store multiple entities to represent a single large business object with more than 252 properties. Ad esempio, se si vuole archiviare un conteggio del numero di messaggi immediati inviati da ogni dipendente negli ultimi 365 giorni, è possibile usare la progettazione seguente che si avvale di due entità con schemi diversi: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 could use the following design that uses two entities with different schemas:

Per apportare una modifica che richiede l'aggiornamento di entrambe le entità per mantenerle sincronizzate tra loro, è possibile usare una transazione 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. Diversamente, è possibile usare una singola operazione di unione per aggiornare il numero di messaggi per un giorno specifico.Otherwise, you can use a single merge operation to update the message count for a specific day. Per recuperare tutti i dati per un singolo dipendente, è necessario recuperare entrambe le entità, operazione che è possibile eseguire con due richieste efficienti che usano un valore PartitionKey e un valore RowKey.To retrieve all the data for an individual employee you must retrieve both entities, which you can do with two efficient requests that use both a PartitionKey and a RowKey value.

Considerazioni e problemiIssues and considerations

Prima di decidere come implementare questo modello, considerare quanto segue:Consider the following points when deciding how to implement this pattern:

  • Il recupero di un'entità logica completa richiede almeno due transazioni di archiviazione, una per recuperare ogni entità fisica.Retrieving a complete logical entity involves at least two storage transactions: one to retrieve each physical entity.

Quando usare questo modelloWhen to use this pattern

Usare questo modello quando è necessario archiviare entità le cui dimensioni o il cui numero di proprietà superano i limiti per una singola entità nel servizio tabelle.Use this pattern when need to store entities whose size or number of properties exceeds the limits for an individual entity in the Table service.

Per l'implementazione di questo modello possono risultare utili i modelli e le informazioni aggiuntive seguenti:The following patterns and guidance may also be relevant when implementing this pattern:

Modello di entità di grandi dimensioniLarge entities pattern

Usare l'archiviazione BLOB per archiviare valori di proprietà di grandi dimensioni.Use blob storage to store large property values.

Contesto e problemaContext and problem

Una singola entità non può memorizzare più di 1 MB di dati in totale.An individual entity cannot store more than 1 MB of data in total. Se una o più proprietà archiviano valori che causano il superamento delle dimensioni totali dell'entità, non è possibile archiviare l'intera entità nel servizio tabelle.If one or several of your properties store values that cause the total size of your entity to exceed this value, you cannot store the entire entity in the Table service.

SoluzioneSolution

Se l'entità supera le dimensioni di 1 MB perché una o più proprietà contengono una grande quantità di dati, è possibile archiviare i dati nel servizio BLOB e quindi archiviare l'indirizzo del BLOB in una proprietà nell'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 the Blob service and then store the address of the blob in a property in the entity. Ad esempio, è possibile archiviare la foto di un dipendente nell'archiviazione BLOB e archiviare un collegamento a foto nella proprietà Photo dell'entità del dipendente: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:

Considerazioni e problemiIssues and considerations

Prima di decidere come implementare questo modello, considerare quanto segue:Consider the following points when deciding how to implement this pattern:

  • Per mantenere la coerenza finale tra l'entità nel servizio tabelle e i dati nel servizio BLOB, usare il Modello per transazioni con coerenza finale per mantenere le identità.To maintain eventual consistency between the entity in the Table service and the data in the Blob service, use the Eventually consistent transactions pattern to maintain your entities.
  • Il recupero di un'entità completa richiede almeno due transazioni di archiviazione: una per recuperare l'entità e un'altra per recuperare i dati BLOB.Retrieving a complete entity involves at least two storage transactions: one to retrieve the entity and one to retrieve the blob data.

Quando usare questo modelloWhen to use this pattern

Usare questo modello quando è necessario archiviare entità le cui dimensioni superano i limiti per una singola entità nel servizio tabelle.Use this pattern when you need to store entities whose size exceeds the limits for an individual entity in the Table service.

Per l'implementazione di questo modello possono risultare utili i modelli e le informazioni aggiuntive seguenti:The following patterns and guidance may also be relevant when implementing this pattern:

Anti-modello prepend/appendPrepend/append anti-pattern

Quando si dispone di un volume elevato di inserimenti, aumentare la scalabilità suddividendoli tra più partizioni.Increase scalability when you have a high volume of inserts by spreading the inserts across multiple partitions.

Contesto e problemaContext and problem

L'anteposizione o l'aggiunta di entità alle entità archiviate determina in genere l'aggiunta da parte dell'applicazione di nuove entità alla prima o ultima partizione di una sequenza di partizioni.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. In questo caso, tutti gli inserimenti in un determinato momento vengono eseguiti nella stessa partizione, creando un hotspot che impedisce al servizio tabelle di bilanciare il carico degli inserimenti tra più nodi e causando il possibile raggiungimento degli obiettivi di scalabilità per partizione da parte dell'applicazione.In this case, all of the inserts at any given time are taking place in the same partition, creating a hotspot that prevents the table service from load balancing inserts across multiple nodes, and possibly causing your application to hit the scalability targets for partition. Se ad esempio si dispone di un'applicazione che registra l'accesso alla rete e alle risorse da parte dei dipendenti, la struttura dell'entità mostrata sotto potrebbe determinare la trasformazione della partizione dell'ora corrente in un hotspot se il volume delle transazioni raggiunge l'obiettivo di scalabilità per una singola partizione:For example, if you have an application that logs network and resource access by employees, then an entity structure as shown below could result in the current hour's partition becoming a hotspot if the volume of transactions reaches the scalability target for an individual partition:

SoluzioneSolution

La struttura di un'entità alternativa seguente evita gli hotspot in qualsiasi partizione specifica quando l'applicazione effettua la registrazione di eventi:The following alternative entity structure avoids a hotspot on any particular partition as the application logs events:

Si noti come in questo esempio entrambi i valori PartitionKey e RowKey siano chiavi composte.Notice with this example how both the PartitionKey and RowKey are compound keys. Il valore PartitionKey usa sia l'ID reparto che l'ID dipendente per distribuire la registrazione in più partizioni.The PartitionKey uses both the department and employee id to distribute the logging across multiple partitions.

Considerazioni e problemiIssues and considerations

Prima di decidere come implementare questo modello, considerare quanto segue:Consider the following points when deciding how to implement this pattern:

  • La struttura chiave alternativa che evita la creazione di partizioni critiche negli inserimenti supporta in modo efficiente le query effettuate dall'applicazione client?Does the alternative key structure that avoids creating hot partitions on inserts efficiently support the queries your client application makes?
  • Il volume delle transazioni previste è indicativo della probabilità che si raggiungano gli obiettivi di scalabilità per una singola partizione e si sia limitati dal servizio di archiviazione?Does your anticipated volume of transactions mean that you are likely to reach the scalability targets for an individual partition and be throttled by the storage service?

Quando usare questo modelloWhen to use this pattern

Evitare l'anti-modello prepend/append quando il volume delle transazioni determinerà probabilmente una limitazione da parte del servizio di archiviazione quando si accede a una partizione critica.Avoid the prepend/append anti-pattern when your volume of transactions is likely to result in throttling by the storage service when you access a hot partition.

Per l'implementazione di questo modello possono risultare utili i modelli e le informazioni aggiuntive seguenti:The following patterns and guidance may also be relevant when implementing this pattern:

Anti-modello dei dati di logLog data anti-pattern

In genere è necessario usare il servizio BLOB invece del servizio tabelle per archiviare i dati di log.Typically, you should use the Blob service instead of the Table service to store log data.

Contesto e problemaContext and problem

Un caso di utilizzo comune per i dati di log è il recupero di una selezione di voci di log per un intervallo specifico di data/ora. Ad esempio, per trovare tutti i messaggi di errore e critici registrati dall'applicazione tra le ore 15.04 e le ore 15.06 in una data specificaA common use case for log data is to retrieve a selection of log entries for a specific date/time range: 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. senza usare la data e l'ora del messaggio del log per determinare la partizione in cui sono state salvate le entità, verrà creata una partizione critica perché in qualsiasi momento tutte le entità del log condividono lo stesso valore PartitionKey. Vedere la sezione Anti-modello prepend/append.You do not want to use the date and time of the log message to determine the partition you save log entities to: that results in a hot partition because at any given time, all the log entities will share the same PartitionKey value (see the section Prepend/append anti-pattern). Ad esempio, lo schema di entità seguente per un messaggio di log determina una partizione critica perché l'applicazione scrive tutti i messaggi di log nella partizione per la data e l'ora correnti: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:

In questo esempio il valore RowKey include la data e l'ora del messaggio di log per garantire che i messaggi di log vengano archiviati in ordine di data/ora e include un ID del messaggio nel caso in cui più messaggi di log condividano la stessa data e la stessa ora.In this example, the RowKey includes the date and time of the log message to ensure that log messages are stored sorted in date/time order, and includes a message id in case multiple log messages share the same date and time.

Un altro approccio prevede l'uso di un valore PartitionKey per assicurarsi che l'applicazione scriva i messaggi in un intervallo di partizioni.Another approach is to use a PartitionKey that ensures that the application writes messages across a range of partitions. Ad esempio, se l'origine del messaggio di log consente di distribuire i messaggi in più partizioni, è possibile usare lo schema di entità seguente:For example, if the source of the log message provides a way to distribute messages across many partitions, you could use the following entity schema:

Tuttavia, il problema con questo schema risiede nel fatto che per recuperare tutti i messaggi di log per un intervallo di tempo specifico è necessario cercare ogni partizione nella tabella.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.

SoluzioneSolution

Nella sezione precedente è stato preso in esame il problema associato ai tentativi di usare il servizio tabelle per archiviare le voci di log e sono state proposte due progettazioni, entrambe insoddisfacenti.The previous section highlighted the problem of trying to use the Table service to store log entries and suggested two, unsatisfactory, designs. Una soluzione ha determinato una partizione critica che comporta il rischio di prestazioni insufficienti della scrittura dei messaggi di log; l'altra soluzione ha determinato prestazioni insufficienti delle query a causa del requisito di analizzare ogni partizione della tabella per recuperare i messaggi di log per un intervallo di tempo specifico.One solution led to a hot partition with the risk of poor performance writing log messages; 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. L'archiviazione BLOB offre una soluzione migliore per questo tipo di scenario ed è in questo modo che Analisi archiviazione di Azure archivia i dati di log raccolti.Blob storage offers a better solution for this type of scenario and this is how Azure Storage Analytics stores the log data it collects.

Questa sezione illustra come Analisi archiviazione archivia i dati di log nell'archiviazione BLOB per esemplificare questo approccio all'archiviazione dei dati per la quale vengono in genere eseguite query per intervallo.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.

Analisi archiviazione archivia i messaggi di log in un formato delimitato in più BLOB.Storage Analytics stores log messages in a delimited format in multiple blobs. Il formato delimitato semplifica l'analisi dei dati nel messaggio di log da parte di un'applicazione client.The delimited format makes it easy for a client application to parse the data in the log message.

Analisi archiviazione usa una convenzione di denominazione per i BLOB che consente di localizzare uno BLOB o più BLOB che contengono i messaggi di log per i quali si sta effettuando la ricerca.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. Ad esempio, un BLOB denominato "queue/2014/07/31/1800/000001.log" contiene messaggi di log correlati al servizio di accodamento per l'ora che inizia alle 18.00 del 31 luglio 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 31 July 2014. "000001" indica che si tratta del primo file di log per il periodo.The "000001" indicates that this is the first log file for this period. Analisi archiviazione registra inoltre i timestamp del primo e dell'ultimo messaggio di log archiviati nel file come parte dei metadati del 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 per l'archiviazione BLOB consente di individuare i BLOB in un contenitore in base a un prefisso del nome: per individuare tutti i BLOB contenenti i dati di log della coda per l'ora che inizia alle 18.00, è possibile usare il prefisso "queue/2014/07/31/1800".The API for blob storage enables you locate blobs in a container based on a name prefix: 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."

Analisi archiviazione esegue il buffer dei messaggi di log e quindi aggiorna periodicamente il BLOB appropriato o ne crea uno nuovo con il batch di voci di log più recente.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. Ciò riduce il numero di scritture che deve eseguire nel servizio BLOB.This reduces the number of writes it must perform to the blob service.

Se si implementa una soluzione simile nella propria applicazione, è necessario considerare come gestire il compromesso tra affidabilità (scrittura di ogni voce di log nell'archiviazione BLOB quando questa si verifica) e il costo e LA scalabilità (buffering degli aggiornamenti dell'applicazione e relativa scrittura nell'archiviazione BLOB in blocchi).If you are implementing a similar solution in your own application, you must consider how to manage the trade-off between reliability (writing every log entry to blob storage as it happens) and cost and scalability (buffering updates in your application and writing them to blob storage in batches).

Considerazioni e problemiIssues and considerations

Prima di decidere come archiviare i dati di log, considerare quanto segue:Consider the following points when deciding how to store log data:

  • Se si crea una progettazione di tabella che consente di evitare potenziali partizioni critiche, è possibile che non si possa accedere ai dati di log in modo efficiente.If you create a table design that avoids potential hot partitions, you may find that you cannot access your log data efficiently.
  • Per elaborare i dati di log, spesso un client deve caricare molti record.To process log data, a client often needs to load many records.
  • Nonostante i dati di log siano spesso strutturati, l'archiviazione BLOB può essere una soluzione migliore.Although log data is often structured, blob storage may be a better solution.

Considerazioni sull'implementazioneImplementation considerations

Questa sezione illustra alcune considerazioni da tenere presente quando si implementano i modelli descritti nelle sezioni precedenti.This section discusses some of the considerations to bear in mind when you implement the patterns described in the previous sections. Nella maggior parte di questa sezione vengono usati esempi scritti in C# che usano la libreria client di archiviazione (versione 4.3.0 al momento della stesura di questo documento).Most of this section uses examples written in C# that use the Storage Client Library (version 4.3.0 at the time of writing).

Recupero di entitàRetrieving entities

Come descritto nella sezione Progettazione per le query, la query più efficiente è una query di tipo punto.As discussed in the section Design for querying, the most efficient query is a point query. Tuttavia, in alcuni scenari potrebbe essere necessario recuperare più entità.However, in some scenarios you may need to retrieve multiple entities. Questa sezione descrive alcuni approcci comuni al recupero di entità mediante la libreria client di archiviazione.This section describes some common approaches to retrieving entities using the Storage Client Library.

Esecuzione di una query di tipo punto mediante la libreria client di archiviazioneExecuting a point query using the Storage Client Library

Il modo più semplice per eseguire una query di tipo punto consiste nell'usare l'operazione di tabella Retrieve come illustrato nel frammento di codice C# seguente che recupera un'entità con un PartitionKey di valore "Sales" e un RowKey di valore "212":The easiest way to execute a point query is to use the Retrieve table operation as shown in the following C# code snippet that 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;
    ...
}  

Si noti come in questo esempio l'entità recuperata prevista sia di tipo EmployeeEntity.Notice how this example expects the entity it retrieves to be of type EmployeeEntity.

Recupero di più entità usando LINQRetrieving multiple entities using LINQ

È possibile recuperare più entità usando LINQ con la libreria client di archiviazione e specificando una query con una clausola where .You can retrieve multiple entities by using LINQ with Storage Client Library and specifying a query with a where clause. Per evitare un'analisi di tabella, è consigliabile includere sempre il valore PartitionKey nella clausola where e, se possibile, il valore RowKey per evitare analisi di tabelle e partizioni.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. Il servizio tabelle supporta un set limitato di operatori di confronto (maggiore di, maggiore di o uguale a, minore di, minore di o uguale a e non uguale a) da usare per determinare la clausola where.The table service 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. Il frammento di codice C# seguente consente di trovare tutti i dipendenti il cui cognome inizia con la lettera "B" (presupponendo che il valore RowKey archivi il cognome) del reparto vendite (supponendo che il valore PartitionKey archivi il nome del reparto):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();  

Si noti come la query specifichi sia un valore RowKey che un valore PartitionKey per garantire prestazioni migliori.Notice how the query specifies both a RowKey and a PartitionKey to ensure better performance.

L'esempio di codice seguente illustra la funzionalità equivalente usando l'API fluent (per altre informazioni sulle API fluent in generale, vedere l'articolo relativo alle procedure consigliate per la progettazione di un’API fluent):The following code sample shows equivalent functionality 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'esempio annida più metodi CombineFilters per includere le tre condizioni di filtro.The sample nests multiple CombineFilters methods to include the three filter conditions.

Recupero di un numero elevato di entità da una queryRetrieving large numbers of entities from a query

Una query ottimale restituisce una singola entità in base a un valore PartitionKey e a un valore RowKey.An optimal query returns an individual entity based on a PartitionKey value and a RowKey value. In alcuni scenari, tuttavia, potrebbe essere presente il requisito di restituire molte entità dalla stessa partizione o anche da più partizioni.However, in some scenarios you may have a requirement to return many entities from the same partition or even from many partitions.

È sempre necessario eseguire test completi delle prestazioni dell'applicazione in tali scenari.You should always fully test the performance of your application in such scenarios.

Una query sul servizio tabelle può restituire un massimo di 1.000 entità contemporaneamente e può essere eseguita per un massimo di cinque secondi.A query against the table service may return a maximum of 1,000 entities at one time and may execute for a maximum of five seconds. Se il set di risultati contiene più di 1.000 entità, nel caso in cui la query non venga completata entro cinque secondi, o se la query supera il limite della partizione, il servizio tabelle restituisce un token di continuazione per consentire all'applicazione client di richiedere il successivo set di entità.If the result set contains more than 1,000 entities, if the query did not complete within five seconds, or if the query crosses the partition boundary, the Table service returns a continuation token to enable the client application to request the next set of entities. Per altre informazioni sul funzionamento dei token di continuazione, vedere Timeout e paginazione delle query.For more information about how continuation tokens work, see Query Timeout and Pagination.

La libreria client di archiviazione può gestire automaticamente i token di continuazione per l'utente mentre restituisce entità dal servizio tabelle.If you are using the Storage Client Library, it can automatically handle continuation tokens for you as it returns entities from the Table service. L'esempio di codice C# seguente che usa la libreria client di archiviazione gestisce automaticamente i token di continuazione se il servizio tabelle li restituisce in una risposta:The following C# code sample using the Storage Client Library automatically handles continuation tokens if the table service 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)
{
        ...
}  

Il codice C# seguente gestisce i token di continuazione in modo esplicito: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);  

Usando i token di continuazione in modo esplicito è possibile controllare quando l'applicazione recupera il successivo segmento di dati.By using continuation tokens explicitly, you can control when your application retrieves the next segment of data. Ad esempio, se l'applicazione client consente agli utenti di spostarsi tra le entità archiviate in una tabella, un utente può decidere di non spostarsi tra tutte le entità recuperate dalla query in modo che l'applicazione usi solo un token di continuazione per recuperare il segmento successivo quando l'utente ha terminato il paging di tutte le entità nel segmento corrente.For example, if your client application enables users to page through the entities stored in a table, a user may decide not to page through all the entities retrieved by the query so 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. Questo approccio offre diversi vantaggi:This approach has several benefits:

  • Consente di limitare la quantità di dati da recuperare dal servizio tabelle e da spostare tramite la rete.It enables you to limit the amount of data to retrieve from the Table service and that you move over the network.
  • Consente di eseguire operazioni di I/O asincrone in .NET.It enables you to perform asynchronous IO in .NET.
  • Consente di serializzare il token di continuazione in un archivio permanente in modo da poter proseguire in caso di arresto anomalo dell'applicazione.It enables you to serialize the continuation token to persistent storage so you can continue in the event of an application crash.

Nota

Un token di continuazione in genere restituisce un segmento contenente al massimo 1.000 entità.A continuation token typically returns a segment containing 1,000 entities, although it may be fewer. Ciò avviene anche se si limita il numero di voci restituite da una query usando Take per restituire le prime n entità che corrispondono ai criteri di ricerca: il servizio tabelle può restituire un segmento contenente meno di n entità con un token di continuazione per consentire il recupero delle entità rimanenti.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: the table service may return a segment containing fewer than n entities along with a continuation token to enable you to retrieve the remaining entities.

Il codice C# seguente illustra come modificare il numero di entità restituite all'interno di un segmento:The following C# code shows how to modify the number of entities returned inside a segment:

employeeQuery.TakeCount = 50;  

Proiezione lato serverServer-side projection

Una singola entità può avere fino a 255 proprietà e dimensioni fino a 1 MB.A single entity can have up to 255 properties and be up to 1 MB in size. Quando si eseguono query sulla tabella e si recuperano entità, potrebbero non essere necessarie tutte le proprietà ed è possibile evitare di trasferire dati inutilmente (in modo da ridurre la latenza e i costi).When you query the table and retrieve entities, you may not need all the properties and can avoid transferring data unnecessarily (to help reduce latency and cost). È possibile usare la proiezione lato server per trasferire solo le proprietà necessarie.You can use server-side projection to transfer just the properties you need. L'esempio seguente recupera solo la proprietà Email (insieme a PartitionKey, RowKey, Timestamp ed ETag) dalle entità selezionate dalla query.The following example is 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);
}  

Si noti come il valore RowKey è disponibile anche se non è stato incluso nell'elenco delle proprietà da recuperare.Notice how the RowKey value is available even though it was not included in the list of properties to retrieve.

Modifica di entitàModifying entities

La libreria client di archiviazione consente di modificare le entità archiviate nel servizio tabelle mediante l'inserimento, l'eliminazione e l'aggiornamento di entità.The Storage Client Library enables you to modify your entities stored in the table service by inserting, deleting, and updating entities. È possibile usare le transazioni EGT per eseguire in batch più operazioni di inserimento, aggiornamento ed eliminazione insieme allo scopo di ridurre il numero di round trip necessari e migliorare le prestazioni della soluzione.You can use EGTs to batch multiple insert, update, and delete operations together to reduce the number of round trips required and improve the performance of your solution.

Si noti che le eccezioni generate quando la libreria client di archiviazione esegue una transazione EGT in genere includono l'indice dell'entità che ha causato l'esito negativo del batch.Note that exceptions thrown when the Storage Client Library executes an EGT typically include the index of the entity that caused the batch to fail. Ciò è utile quando si esegue il debug di codice che usa le transazioni EGT.This is helpful when you are debugging code that uses EGTs.

È inoltre opportuno considerare l'influenza della progettazione sul modo in cui l'applicazione gestisce le operazioni di concorrenza e aggiornamento.You should also consider how your design affects how your client application handles concurrency and update operations.

Gestione della concorrenzaManaging concurrency

Per impostazione predefinita, il servizio tabelle implementa controlli di concorrenza ottimistica a livello di singole entità per le operazioni Insert, Merge e Delete, sebbene sia possibile per un client forzare il servizio tabelle in modo da ignorare questi controlli.By default, the table service implements optimistic concurrency checks at the level of individual entities for Insert, Merge, and Delete operations, although it is possible for a client to force the table service to bypass these checks. Per altre informazioni sulla gestione della concorrenza nel servizio tabelle, vedere Gestione della concorrenza in Archiviazione di Microsoft Azure.For more information about how the table service manages concurrency, see Managing Concurrency in Microsoft Azure Storage.

Unione o sostituzioneMerge or replace

Il metodo Replace della classe TableOperation sostituisce sempre l'entità completa nel servizio tabelle.The Replace method of the TableOperation class always replaces the complete entity in the Table service. Se non si include una proprietà nella richiesta quando tale proprietà è presente nell'entità archiviata, la richiesta rimuove la proprietà dall'entità archiviata.If you do not include a property in the request when that property exists in the stored entity, the request removes that property from the stored entity. A meno che non si voglia rimuovere una proprietà in modo esplicito da un'entità archiviata, è necessario includere ogni proprietà nella richiesta.Unless you want to remove a property explicitly from a stored entity, you must include every property in the request.

È possibile usare il metodo Merge della classe TableOperation per ridurre la quantità di dati inviati al servizio tabelle quando si vuole aggiornare un'entità.You can use the Merge method of the TableOperation class to reduce the amount of data that you send to the Table service when you want to update an entity. Il metodo Merge sostituisce le eventuali proprietà nell'entità archiviata con i valori di proprietà dell'entità inclusa nella richiesta, ma lascia invariate le proprietà nell'entità archiviata che non sono incluse nella richiesta.The Merge method replaces any properties in the stored entity with property values from the entity included in the request, but leaves intact any properties in the stored entity that are not included in the request. Ciò è utile se si dispone di entità di grandi dimensioni e si desidera solo aggiornare un numero limitato di proprietà in una richiesta.This is useful if you have large entities and only need to update a small number of properties in a request.

Nota

I metodi Replace e Merge hanno esito negativo se l'entità non esiste.The Replace and Merge methods fail if the entity does not exist. In alternativa, se l'entità non esiste, è possibile usare i metodi InsertOrReplace e InsertOrMerge per creare una nuova entità.As an alternative, you can use the InsertOrReplace and InsertOrMerge methods that create a new entity if it doesn't exist.

Uso di tipi di entità eterogeneiWorking with heterogeneous entity types

Il servizio tabelle è un archivio di tabelle senza schema. Ciò significa che una singola tabella può archiviare entità di più tipi, offrendo una grande flessibilità di progettazione.The Table service is a schema-less table store that means that a single table can store entities of multiple types providing great flexibility in your design. L'esempio seguente illustra una tabella che archivia entità dipendente ed entità reparto:The following example illustrates a table storing both employee and department entities:

PartitionKeyPartitionKey RowKeyRowKey TimestampTimestamp
FirstNameFirstName LastNameLastName AgeAge EmailEmail
FirstNameFirstName LastNameLastName AgeAge EmailEmail
DepartmentNameDepartmentName EmployeeCountEmployeeCount
FirstNameFirstName LastNameLastName AgeAge EmailEmail

Si noti che ogni entità deve disporre comunque dei valori PartitionKey, RowKey e Timestamp, ma può avere qualsiasi set di proprietà.Note that each entity must still have PartitionKey, RowKey, and Timestamp values, but may have any set of properties. Inoltre, non esiste alcuna indicazione relativa al tipo di un'entità, a meno che non si scelga di memorizzare le informazioni in una posizione.Furthermore, there is nothing to indicate the type of an entity unless you choose to store that information somewhere. Esistono due opzioni per identificare il tipo di entità:There are two options for identifying the entity type:

  • Anteporre il tipo di entità per il valore RowKey (o eventualmente il valore PartitionKey).Prepend the entity type to the RowKey (or possibly the PartitionKey). Ad esempio, EMPLOYEE_000123 o DEPARTMENT_SALES come valori RowKey.For example, EMPLOYEE_000123 or DEPARTMENT_SALES as RowKey values.
  • Usare una proprietà separata per registrare il tipo di entità come illustrato nella tabella seguente.Use a separate property to record the entity type as shown in the table below.
PartitionKeyPartitionKey RowKeyRowKey TimestampTimestamp
EntityTypeEntityType FirstNameFirstName LastNameLastName AgeAge EmailEmail
EmployeeEmployee
EntityTypeEntityType FirstNameFirstName LastNameLastName AgeAge EmailEmail
EmployeeEmployee
EntityTypeEntityType DepartmentNameDepartmentName EmployeeCountEmployeeCount
departmentDepartment
EntityTypeEntityType FirstNameFirstName LastNameLastName AgeAge EmailEmail
EmployeeEmployee

La prima opzione che precede l'entità per il valore RowKeyè utile se sussiste la possibilità che due entità di tipi diversi abbiano lo stesso valore di chiave.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. Inoltre, raggruppa entità dello stesso tipo insieme nella partizione.It also groups entities of the same type together in the partition.

Le tecniche descritte in questa sezione sono particolarmente rilevanti per la discussione Relazioni di ereditarietà trattata all'inizio di questa Guida nella sezione Modellazione di relazioni.The techniques discussed in this section are especially relevant to the discussion Inheritance relationships earlier in this guide in the section Modelling relationships.

Nota

È necessario considerare l'inclusione di un numero di versione nel valore del tipo di entità per consentire alle applicazioni client di sviluppare oggetti POCO e usare versioni diverse.You should consider including a version number in the entity type value to enable client applications to evolve POCO objects and work with different versions.

La restante parte di questa sezione descrive alcune delle funzionalità della libreria client di archiviazione che semplificano l'uso di più tipi di entità nella stessa tabella.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.

Recupero di tipi di entità eterogeneiRetrieving heterogeneous entity types

Se si usa la libreria client di archiviazione, sono disponibili tre opzioni per l'uso di più tipi di entità.If you are using the Storage Client Library, you have three options for working with multiple entity types.

Se si conosce il tipo dell'entità archiviata con valori RowKey e PartitionKey specifici, è possibile specificare il tipo di entità quando si recupera l'entità, come illustrato nei due esempi precedenti in cui vengono recuperate entità di tipo EmployeeEntity: Esecuzione di una query di tipo punto mediante la libreria client di archiviazione e Recupero di più entità usando LINQ.If you know the type of the entity stored with a specific RowKey and PartitionKey values, then you can specify the entity type when you retrieve the entity as shown in the previous two examples that retrieve entities of type EmployeeEntity: Executing a point query using the Storage Client Library and Retrieving multiple entities using LINQ.

La seconda opzione prevede l'uso del tipo DynamicTableEntity (un contenitore di proprietà) anziché un tipo di entità POCO concreto (questa opzione può anche migliorare le prestazioni perché non richiede la serializzazione e la deserializzazione dell'entità nei tipi .NET).The second option is to use the DynamicTableEntity type (a property bag) instead of a concrete POCO entity type (this option may also improve performance because there is no need to serialize and deserialize the entity to .NET types). Il codice C# seguente può recuperare più entità di tipo diverso dalla tabella, ma restituisce tutte le entità come istanze DynamicTableEntity .The following C# code potentially retrieves multiple entities of different types from the table, but returns all entities as DynamicTableEntity instances. Usa quindi la proprietà EntityType per determinare il tipo di ogni 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
        }
    }
}  

Si noti che per recuperare le altre proprietà è necessario usare il metodo TryGetValue sulla proprietà Properties della classe DynamicTableEntity.Note that to retrieve other properties you must use the TryGetValue method on the Properties property of the DynamicTableEntity class.

Una terza opzione prevede l'uso combinato del tipo DynamicTableEntity e di un'istanza EntityResolver.A third option is to combine using the DynamicTableEntity type and an EntityResolver instance. Ciò consente di risolvere a più tipi POCO nella stessa query.This enables you to resolve to multiple POCO types in the same query. In questo esempio il delegato EntityResolver usa la proprietà EntityType per distinguere i due tipi di entità restituite dalla query.In this example, the EntityResolver delegate is using the EntityType property to distinguish between the two types of entity that the query returns. Il metodo Resolve usa il delegato resolver per risolvere le istanze DynamicTableEntity alle istanze 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)
        {
    ...
        }
}  

Modifica dei tipi di entità eterogeneiModifying heterogeneous entity types

Per eliminare un'entità non è necessario conoscerne il tipo, che è comunque sempre noto quando l'entità viene inserita.You do not need to know the type of an entity to delete it, and you always know the type of an entity when you insert it. Tuttavia, è possibile usare il tipo DynamicTableEntity per aggiornare un'entità senza conoscerne il tipo e senza usare una classe di entità POCO.However, you can use DynamicTableEntity type to update an entity without knowing its type and without using a POCO entity class. L'esempio di codice seguente consente di recuperare una singola entità e controlla che la proprietà EmployeeCount esista prima di aggiornarla.The following code sample retrieves a single entity, and checks 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));  

Controllo dell'accesso con le firme di accesso condivisoControlling access with Shared Access Signatures

È possibile usare i token delle firme di accesso condiviso (SAS) per consentire alle applicazioni client di modificare le entità di tabella, ed eseguire query sulle stesse, direttamente senza la necessità di eseguire l'autenticazione direttamente con il servizio tabelle.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 the table service. In genere, l'uso di SAS nell'applicazione comporta tre vantaggi principali:Typically, there are three main benefits to using SAS in your application:

  • Non è necessario distribuire la chiave dell'account di archiviazione in una piattaforma non sicura (ad esempio un dispositivo mobile) per consentire a tale dispositivo di accedere e modificare le entità nel servizio tabelle.You do not 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 the Table service.
  • È possibile scaricare una parte del lavoro eseguito dai ruoli Web e di lavoro nella gestione delle entità per i dispositivi client, ad esempio computer e dispositivi mobili degli utenti finali.You can offload some of the work that web and worker roles perform in managing your entities to client devices such as end-user computers and mobile devices.
  • È possibile assegnare un set vincolato e limitato nel tempo di autorizzazioni a un client (ad esempio, l'accesso di sola lettura a risorse specifiche).You can assign a constrained and time limited set of permissions to a client (such as allowing read-only access to specific resources).

Per altre informazioni sull'uso di token di firma di accesso condiviso con il servizio tabelle, vedere Uso delle firme di accesso condiviso.For more information about using SAS tokens with the Table service, see Using Shared Access Signatures (SAS).

Tuttavia, è comunque necessario generare i token delle firme di accesso condiviso che consentono a un'applicazione client di accedere alle entità nel servizio tabelle: questa operazione deve essere eseguita in un ambiente che dispone di un accesso sicuro alle chiavi dell'account di archiviazione.However, you must still generate the SAS tokens that grant a client application to the entities in the table service: you should do this in an environment that has secure access to your storage account keys. In genere, è possibile usare un ruolo Web o di lavoro per generare i token delle firme di accesso condiviso e distribuirli alle applicazioni client che richiedono l'accesso alle entità.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. Poiché la generazione e la distribuzione dei token delle firme di accesso condiviso ai client comportano comunque un sovraccarico, è consigliabile valutare il modo migliore di ridurre tale sovraccarico, soprattutto in scenari con volumi elevati.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.

È possibile generare un token delle firme di accesso condiviso che concede l'accesso a un sottoinsieme delle entità in una tabella.It is possible to generate a SAS token that grants access to a subset of the entities in a table. Per impostazione predefinita, viene creato un token della firma di accesso condiviso per un'intera tabella, ma è anche possibile specificare che il token della firma di accesso condiviso conceda l'accesso a un intervallo di valori PartitionKey o a un intervallo di valori PartitionKey e RowKey.By default, you create a SAS token for an entire table, but it is 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. Si potrebbe scegliere di generare token SAS per i singoli utenti del sistema in modo che il token SAS di ogni utente consenta di accedere solo alle proprie entità nel servizio tabelle.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 the table service.

Operazioni asincrone e paralleleAsynchronous and parallel operations

A condizione che le richieste vengano distribuite in più partizioni, è possibile migliorare la velocità effettiva e la velocità di risposta del client usando le query parallele o asincrone.Provided you are spreading your requests across multiple partitions, you can improve throughput and client responsiveness by using asynchronous or parallel queries. Ad esempio, si potrebbero avere due o più istanze del ruolo di lavoro che accedono alle tabelle in parallelo.For example, you might have two or more worker role instances accessing your tables in parallel. Si potrebbero avere singoli ruoli di lavoro responsabili di specifici set di partizioni o semplicemente avere più istanze del ruolo di lavoro, ciascuna in grado di accedere a tutte le partizioni in una tabella.You could 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.

All'interno di un'istanza del client, è possibile migliorare la velocità effettiva effettuando operazioni di archiviazione in modo asincrono.Within a client instance, you can improve throughput by executing storage operations asynchronously. La libreria client di archiviazione semplifica la scrittura di query e modifiche asincrone.The Storage Client Library makes it easy to write asynchronous queries and modifications. Ad esempio, è possibile iniziare con il metodo sincrono che recupera tutte le entità in una partizione come mostrato nel codice C# seguente: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);
}  

È possibile modificare facilmente questo codice affinché la query venga eseguita in modo asincrono come segue: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);
}  

In questo esempio asincrono è possibile visualizzare le modifiche seguenti dalla versione sincrona:In this asynchronous example, you can see the following changes from the synchronous version:

  • La firma del metodo include ora il modificatore async e restituisce un'istanza Task.The method signature now includes the async modifier and returns a Task instance.
  • Invece di chiamare il metodo ExecuteSegmented per recuperare i risultati, il metodo ora chiama il metodo ExecuteSegmentedAsync e usa il modificatore await per recuperare i risultati in modo asincrono.Instead of calling the ExecuteSegmented method to retrieve results, the method now calls the ExecuteSegmentedAsync method and uses the await modifier to retrieve results asynchronously.

L'applicazione client può chiamare questo metodo più volte (con valori diversi per il parametro department ) e ogni query verrà eseguita su un thread separato.The client application can call this method multiple times (with different values for the department parameter), and each query will run on a separate thread.

Si noti che non è presente alcuna versione asincrona del metodo Execute nella classe TableQuery perché l'interfaccia IEnumerable non supporta l'enumerazione asincrona.Note that there is no asynchronous version of the Execute method in the TableQuery class because the IEnumerable interface does not support asynchronous enumeration.

È inoltre possibile inserire, aggiornare ed eliminare entità in modo asincrono.You can also insert, update, and delete entities asynchronously. Nell'esempio C# seguente viene illustrato un metodo semplice e sincrono per inserire o sostituire un'entità dipendente: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);
}  

È possibile modificare facilmente questo codice affinché l'aggiornamento venga eseguito in modo asincrono come segue: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);
}  

In questo esempio asincrono è possibile visualizzare le modifiche seguenti dalla versione sincrona:In this asynchronous example, you can see the following changes from the synchronous version:

  • La firma del metodo include ora il modificatore async e restituisce un'istanza Task.The method signature now includes the async modifier and returns a Task instance.
  • Invece di chiamare il metodo Execute per aggiornare l'entità, il metodo ora chiama il metodo ExecuteAsync e usa il modificatore await per recuperare i risultati in modo asincrono.Instead of calling the Execute method to update the entity, the method now calls the ExecuteAsync method and uses the await modifier to retrieve results asynchronously.

L'applicazione client può chiamare più metodi asincroni come questo e ogni chiamata al metodo verrà eseguita su un thread separato.The client application can call multiple asynchronous methods like this one, and each method invocation will run on a separate thread.

CreditsCredits

Vorremmo ringraziare i seguenti membri del team di Azure per il loro contributo: Dominic Betts, Jason Hogg, Jean Ghanem, Jai Haridas, Jeff Irwin, Vamshidhar Kommineni, Vinay Shah, Serdar Ozler e Tom Hollander di Microsoft DX.We would like to thank the following members of the Azure team for their contributions: Dominic Betts, Jason Hogg, Jean Ghanem, Jai Haridas, Jeff Irwin, Vamshidhar Kommineni, Vinay Shah and Serdar Ozler as well as Tom Hollander from Microsoft DX.

I nostri ringraziamenti vanno inoltre ai Microsoft MVP seguenti per i preziosi commenti forniti durante i cicli di revisione: Igor Papirov e Edward Bakker.We would also like to thank the following Microsoft MVP's for their valuable feedback during review cycles: Igor Papirov and Edward Bakker.