Azure ストレージ テーブルの設計ガイド: スケーラブルな設計とハイパフォーマンスなテーブルAzure Storage Table Design Guide: Designing Scalable and Performant Tables

ヒント

この記事の内容は、従来の Azure Table Storage を対象としています。The content in this article applies to the original Azure Table storage. ただし現在は、Table Storage の Premium プランである Azure Cosmos DB Table API が存在しており、スループットが最適化されたテーブル、グローバル配布、自動のセカンダリ インデックスが提供されています。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. 詳細を確認し、Premium 版を使ってみるには、Azure Cosmos DB の Table API に関する記事を参照してください。To learn more and try out the premium experience, please check out Azure Cosmos DB Table API.

スケーラビリティとパフォーマンスに優れたテーブルを設計するにあたっては、さまざまな事柄を考慮する必要があります。具体的にはパフォーマンス、スケーラビリティ、コストなどですが、To design scalable and performant tables you must consider a number of factors such as performance, scalability, and cost. 過去にリレーショナル データベースのスキーマを設計した経験がある方なら、こうした考慮事項はご存じであると思われます。しかし、Azure Table service ストレージ モデルとリレーショナル モデルには類似の要素が多いとはいえ、重要な違いが多数あるのも事実です。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. こうした相違点は、リレーショナル データベースの扱いに慣れた方には直感的にわかりづらかったり、扱いづらかったりする設計につながりがちですが、Azure Table service などの NoSQL キー/値ストアを設計する場合には好都合です。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. 設計の相違点の多くは、Table service が何十億ものデータ エンティティ (リレーショナル データベース用語では行) を含むクラウド アプリケーションをサポートするためのデータや、大量のデータトランザクションをサポートするよう設計されている 点を考慮します。そのため、データの格納方法や Table service の動作方法について違った考え方が必要になります。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. NoSQL データ ストアを適切に設計すれば、リレーショナル データベースを使うソリューションよりも、ソリューションのスケーラビリティが大幅に高まり、コストも抑えられます。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. このガイドでは、これらのトピックについて説明します。This guide helps you with these topics.

Azure Table serviceAbout the Azure Table service

このセクションでは、パフォーマンスとスケーラビリティを重視した設計に関連する Table service の主要機能を取り上げます。This section highlights some of the key features of the Table service that are especially relevant to designing for performance and scalability. 初めて Azure Storage と Table service をご利用になる場合は、この文書を読み進める前に、「Microsoft Azure Storage の概要」と「.NET を使用して Azure Table Storage を使用する」をお読みください。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. このガイドで主に取り上げるのは Table service についてですが、Azure のキューや Blob service と、それらのサービスをソリューションで Table service と共に使用する方法についても触れます。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.

Table service とは 名前が示すとおり、Table service ではデータの格納にテーブル形式を使います。What is the Table service? 名前からおわかりのように、Table service は表形式を使用してデータを格納します。As you might expect from the name, the Table service uses a tabular format to store data. 各エンティティは、それ自体を一意に識別するためのキーのペアと、Table サービスがエンティティの最終更新日時をトラッキングするためのタイムスタンプ列を持ちます (エンティティの更新は自動的に行われます。In the standard terminology, each row of the table represents an entity, and the columns store the various properties of that entity. 各エンティティには、エンティティを識別する一意のキー ペア、エンティティが最後に更新された日時を追跡するために Table service によって使用されるタイムスタンプ列が含まれます (これは自動的に行われるため、タイムスタンプを任意の値を使って手動で上書きすることはできません)。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). Table service では、この最終更新日時のタイムスタンプ (LMT) を使ってオプティミスティック同時実行を管理します。The Table service uses this last-modified timestamp (LMT) to manage optimistic concurrency.

注意

Table service REST API 操作により、最終更新タイムスタンプ (LMT) から派生する ETag 値も返されます。The Table service REST API operations also return an ETag value that it derives from the last-modified timestamp (LMT). このドキュメントでは、ETag と LMT という用語を区別なく使います。基となる同じデータを表しているためです。In this document we will use the terms ETag and LMT interchangeably because they refer to the same underlying data.

次の例は、従業員と部署のエンティティを格納する、シンプルなテーブル設計を示しています。The following example shows a simple table design to store employee and department entities. このガイドで紹介する例の多くは、このシンプルな設計が基になっています。Many of the examples shown later in this guide are based on this simple design.

パーティション キーPartitionKey 行キーRowKey TimestampTimestamp
MarketingMarketing 0000100001 2014-08-22T00:50:32Z2014-08-22T00:50:32Z
FirstNameFirstName LastNameLastName AgeAge 電子メールEmail
DonDon HallHall 3434 donh@contoso.com
MarketingMarketing 0000200002 2014-08-22T00:50:34Z2014-08-22T00:50:34Z
FirstNameFirstName LastNameLastName AgeAge 電子メールEmail
JunJun CaoCao 4747 junc@contoso.com
MarketingMarketing 部署Department 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 電子メールEmail
KenKen KwokKwok 2323 kenk@contoso.com

今のところ、リレーショナル データベースのテーブルと非常によく似ており、異なるキーが必須の列となっていて、同じテーブルに複数の種類のエンティティを格納できます。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. さらに、FirstNameAge などのユーザー定義プロパティには、リレーショナル データベース内の列のように、整数や文字列などのデータ型があります。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. ただし、リレーショナル データベースとは違って、Table service にはスキーマがないため、エンティティごとにプロパティのデータ型は同じである必要ありません。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. 1 つのプロパティに複雑なデータ型を格納するには、JSON や XML などのシリアル化された形式を使う必要があります。To store complex data types in a single property, you must use a serialized format such as JSON or XML. サポート対象のデータ型と日付の範囲、名付け規則、サイズ制限などの Table サービスの詳細については、「 Table サービス データ モデルについて」を参照してください。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.

お分かりかと思いますが、テーブル デザインの基盤には、PartitionKeyRowKey の選択が適しています。As you will see, your choice of PartitionKey and RowKey is fundamental to good table design. テーブルに格納されている各エンティティは、PartitionKeyRowKey の一意の組み合わせである必要があります。Every entity stored in a table must have a unique combination of PartitionKey and RowKey. リレーショナル データベース テーブル内のキーと同様に、PartitionKeyRowKey の値には、高速検索を可能にするクラスター化インデックスを作成するためのインデックスが作成されています。ただし、Table service はセカンダリ インデックスを作成しないため、これら 2 つだけがインデックス付きプロパティとなります (制限については、数パターンを後述しています)。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).

テーブルは 1 つまたは複数のパーティションから構成されており、ソリューションを最適化するためには、適切な PartitionKeyRowKey を選択して設計を決定します。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. ソリューションによっては、すべてのエンティティがパーティションを使って整理された 1 つのテーブルだけで構成されるものもありますが、通常は複数のテーブルが含まれます。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. テーブルを使えばエンティティを論理的に整理できるほか、アクセス制御リストを使ってデータへのアクセスを管理できます。また、1 回のストレージ操作でテーブル全体を削除できます。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.

テーブルのパーティションTable partitions

アカウント名、テーブル名、 PartitionKey を組み合わせ、テーブル サービスがエンティティを格納する場所をストレージ サービス内のパーティションに特定します。The account name, table name and PartitionKey together identify the partition within the storage service where the table service stores the entity. エンティティのアドレス指定スキームの一部であると同時に、パーティションはトランザクションのスコープが定義 し(下記の エンティティ グループ トランザクション を参照してください)、テーブル サービスのスケーラビリティを形成します。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. パーティションの詳細については、 Azure ストレージのスケーラビリティおよびパフォーマンスのターゲットを確認してください。For more information on partitions see Azure Storage Scalability and Performance Targets.

Table service では、個々のノードが 1 つ以上の完全なパーティションを提供し、サービスのスケーリングはノード間でパーティションの負荷を動的に分散させることで行われます。In the Table service, an individual node services one or more complete partitions and the service scales by dynamically load-balancing partitions across nodes. ノードに負荷がかかる場合は、テーブル サービスのパーティション範囲を 別のノードと分割し、トラフィックが少ないときにサービスをマージして、パーティション範囲を複数のトラフィックの少ないノードから 1 つのノードに戻すことができます。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.

Table service の内部詳細、特に、サービスのパーティション管理方法については、ホワイト ペーパー Microsoft Azure のストレージ: 強力な一貫性を備えた高使用可能なクラウド ストレージ サービスを参照してください。For 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.

エンティティ グループ トランザクションEntity Group Transactions

エンティティ グループ トランザクション (EGT) は、Table service で複数のエンティティ間でアトミックな更新を行うための唯一の組み込みのメカニズムです。In the Table service, Entity Group Transactions (EGTs) are the only built-in mechanism for performing atomic updates across multiple entities. EGT は、一部のドキュメントではバッチ トランザクションとも呼ばれています。EGTs are also referred to as batch transactions in some documentation. EGT では、同じパーティションに格納されたエンティティしか処理できないため (特定のテーブルで同じパーティション キーを共有)、複数のエンティティにまたがるアトミックなトランザクションが必要な場合は、それらのエンティティを同じパーティションに格納する必要があります。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. これが、異なる種類のエンティティに複数のテーブルを使わずに、異なる種類のエンティティを同じテーブル (とパーティション) に格納する主な理由です。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. 単一の EGT で最大 100 個のエンティティを処理できます。A single EGT can operate on at most 100 entities. 複数の並行処理 EGT を送信する場合は、それらの EGT が EGT 間の共通であるエンティティには動作しないことを確認することが重要です。さもないと、処理が遅くなる可能性があります。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.

EGT により、設計で評価が必要なトレードオフが生じる可能性もあります。使用するパーティションが増えると、ノード間で要求を負荷分散しやすくなるため、アプリケーションのスケーラビリティが向上するものの、アプリケーションでアトミックなトランザクションを実行し、データの強力な一貫性を維持する力が限られるおそれがあります。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. さらに、1 つのノードの予想されるトランザクションのスループットを制限する、パーティション レベルの特定のスケーラビリティ ターゲットがあります。Azure Storage アカウントと Table サービスのスケーラビリティ ターゲットの詳細については、「Azure Storage のスケーラビリティおよびパフォーマンスのターゲット」をご覧ください。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. このガイドの後のセクションでは、このようなトレードオフを管理しやすくするさまざまな設計戦略を紹介すると共に、クライアント アプリケーションの固有の要件に基づいてパーティション キーを選択する最適な方法についても説明します。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.

容量に関する考慮事項Capacity considerations

次の表に、Table service ソリューションの設計時に考慮する必要のある主要な値をまとめます。The following table includes some of the key values to be aware of when you are designing a Table service solution:

Azure ストレージ アカウントの合計容量Total capacity of an Azure storage account 500 TB500 TB
Azure のストレージ アカウントのテーブルの数Number of tables in an Azure storage account ストレージ アカウントの容量のみによる制限Limited only by the capacity of the storage account
テーブルのパーティションの数Number of partitions in a table ストレージ アカウントの容量のみによる制限Limited only by the capacity of the storage account
パーティション内のエンティティの数Number of entities in a partition ストレージ アカウントの容量のみによる制限Limited only by the capacity of the storage account
個別のエンティティのサイズSize of an individual entity 1 MBまでの最大 255 個のプロパティ (PartitionKeyRowKeyタイムスタンプを含む)Up to 1 MB with a maximum of 255 properties (including the PartitionKey, RowKey, and Timestamp)
PartitionKeySize of the PartitionKey 最大 1 KB の文字列A string up to 1 KB in size
RowKeySize of the RowKey 最大 1 KB の文字列A string up to 1 KB in size
エンティティ グループ トランザクションのサイズSize of an Entity Group Transaction トランザクションには最大で 100 個のエンティティを含めることができ、ペイロードは 4 MB 未満にする必要があります。A transaction can include at most 100 entities and the payload must be less than 4 MB in size. EGT では 1 回に 1 つのエンティティしか更新できません。An EGT can only update an entity once.

詳細については、「 Table サービス データ モデルについて」を参照してください。For more information, see Understanding the Table Service Data Model.

コストに関する考慮事項Cost considerations

テーブル ストレージは比較的安価ですが、Table service を使うソリューションの評価の一環として、容量の使用とトランザクションの量を踏まえてコストを見積もる必要があります。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. ただし、多くのシナリオでは、ソリューションのパフォーマンスとスケーラビリティを向上させるために、非正規化されたデータまたは重複するデータを格納するのも有効です。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. 価格の詳細については、「 Azure Storage 料金」を参照してください。For more information about pricing, see Azure Storage Pricing.

テーブル設計のガイドラインGuidelines for table design

これらのリストにはテーブルを設計する際の主要なガイドラインがまとめられており、これらガイドは後ほど詳細にテーブルへの対処方法を説明します。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. これらのガイドラインは、リレーショナル データベースの設計のために通常参照するガイドラインと、非常に異なります。These guidelines are very different from the guidelines you would typically follow for relational database design.

Table service ソリューションを効率的に 読み込む 設計:Designing your Table service solution to be read efficient:

  • 読み込みが多いアプリケーションでクエリを実行するための設計Design for querying in read-heavy applications. テーブルを設計するときは、エンティティの更新方法について考える前に、実行するクエリ (特に、待機時間に影響を受けやすいもの) を検討してください。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. これは通常、効率的でパフォーマンスの高いソリューションになります。This typically results in an efficient and performant solution.
  • クエリでは、PartitionKey と RowKey の両方を指定します。Specify both PartitionKey and RowKey in your queries. ポイント クエリ これらは、最も効率的なテーブル サービスのクエリなどです。Point queries such as these are the most efficient table service queries.
  • エンティティの重複コピーを格納するか検討します。Consider storing duplicate copies of entities. テーブル ストレージは安価であるため、クエリの効率を上げるため、(異なるキーを持つ) 同じエンティティを複数回格納することをご検討ください。Table storage is cheap so consider storing the same entity multiple times (with different keys) to enable more efficient queries.
  • データの非正規化を検討します。Consider denormalizing your data. テーブル ストレージは安価であるため、データの非正規化を検討してください。Table storage is cheap so consider denormalizing your data. たとえば、概要エンティティを格納すると、統計データ用クエリは単一のエンティティにアクセスするだけで済みます。For example, store summary entities so that queries for aggregate data only need to access a single entity.
  • 複合キーの値を使用します。Use compound key values. 使用可能なキーは、PartitionKeyRowKey のみです。The only keys you have are PartitionKey and RowKey. たとえば、複合キーの値を使用してエンティティへの代替キー付きアクセス パスを有効にします。For example, use compound key values to enable alternate keyed access paths to entities.
  • クエリ プロジェクションを使用します。Use query projection. 必要なフィールドだけを選択するクエリを使用して、ネットワーク経由で転送するデータ量を削減できます。You can reduce the amount of data that you transfer over the network by using queries that select just the fields you need.

効果的に 書き込む Table service ソリューションを設計する。Designing your Table service solution to be write efficient:

  • ホット パーティションを作成しないでください。Do not create hot partitions. 任意の時点で、複数のパーティションで要求を分散できるキーを選択します。Choose keys that enable you to spread your requests across multiple partitions at any point of time.
  • トラフィックの急増を回避します。Avoid spikes in traffic. 適切な期間でトラフィックの流れをスムーズにし、トラフィックの急増を回避します。Smooth the traffic over a reasonable period of time and avoid spikes in traffic.
  • 必ずしもエンティティの種類ごとに個別のテーブルを作成する必要はありません。Don't necessarily create a separate table for each type of entity. 複数のエンティティ種類でアトミック トランザクションが必要なときに、同じテーブル内の同じパーティションにこれら複数のエンティティ種類を格納できます。When you require atomic transactions across entity types, you can store these multiple entity types in the same partition in the same table.
  • 実現する必要のある最大スループットを検討します。Consider the maximum throughput you must achieve. Table service のスケーラビリティ ターゲットを確認し、それを超えない設計にする必要があります。You must be aware of the scalability targets for the Table service and ensure that your design will not cause you to exceed them.

このガイドでは、これらの原則を実装した例を紹介します。As you read this guide, you will see examples that put all of these principles into practice.

クエリに対応した設計Design for querying

Table service ソリューションでは、読み取り、書き込み、またはその両方の負荷が高くなることがあります。Table service solutions may be read intensive, write intensive, or a mix of the two. このセクションでは、読み取り操作を効率的に行える Table service を設計する際に注意する必要のある事柄を中心に取り上げます。This section focuses on the things to bear in mind when you are designing your Table service to support read operations efficiently. 通常は、読み取り操作を効率的にサポートする設計は、書き込み操作についても効率が高くなります。Typically, a design that supports read operations efficiently is also efficient for write operations. ただし、書き込み操作をサポートする設計には、さらに考慮すべき事柄があります。次のセクション「データの変更に対応した設計」で説明します。However, there are additional considerations to bear in mind when designing to support write operations, discussed in the next section, Design for data modification.

データを効率的に読み取ることのできる Table service ソリューションを設計する際には、まず "必要なデータを Table service から取得するには、アプリケーションでどのようなクエリを実行する必要があるか" を考えてみてください。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?"

注意

Table service を使用する場合は、事前に正しく設計することが重要です。後で設計を変更するのは難しいだけでなく、コストも高くなるためです。With the Table service, it's important to get the design correct up front because it's difficult and expensive to change it later. たとえば、リレーショナル データベースなら、既存のデータベースにインデックスを追加するだけでパフォーマンスの問題に対処できるのが普通ですが、Table service ではそうはいきません。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.

このセクションでは、クエリに対応したテーブルを設計する際に対処する必要のある主要な問題を中心に取り上げます。This section focuses on the key issues you must address when you design your tables for querying. このセクションで取り上げるトピックは次のとおりです。The topics covered in this section include:

選択した PartitionKey と RowKey がクエリのパフォーマンスに与える影響How your choice of PartitionKey and RowKey impacts query performance

次の例は、以下の構造を持った複数の従業員エンティティの格納を想定しています (明確にするためほとんどの例で タイムスタンプ プロパティを省略)。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):

列名Column name データの種類Data type
PartitionKey (部門名)PartitionKey (Department Name) StringString
RowKey (従業員 ID)RowKey (Employee Id) StringString
FirstNameFirstName StringString
LastNameLastName StringString
AgeAge 整数Integer
EmailAddressEmailAddress StringString

最初の方のセクション「Azure Table service の概要」では、クエリの設計に直接影響を与える Azure Table service の主な機能の一部について説明します。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. ここから、Table service のクエリを設計する際には、次のような一般的なガイドラインが考えられます。These result in the following general guidelines for designing Table service queries. 以下の例で使用しているフィルター構文は、Table service REST API の構文です。詳細については、「Query Entities (エンティティの照会)」をご覧ください。Note that the filter syntax used in the examples below is from the Table service REST API, for more information see Query Entities.

  • ポイント クエリは、最も効率的な検索です。大量の参照または短い待機時間が求められる参照に使用することをお勧めします。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. このようなクエリでは、PartitionKeyRowKey 値の両方を指定することでインデックスを使用し、個別のエンティティを非常に効率よく検索することができます。Such a query can use the indexes to locate an individual entity very efficiently by specifying both the PartitionKey and RowKey values. 例: $filter (PartitionKey eq 'Sales') = および (RowKey eq '2')For example: $filter=(PartitionKey eq 'Sales') and (RowKey eq '2')
  • 2 番目に良い方法は、PartitionKey を使用する範囲クエリと、RowKey 値の範囲にフィルターをかけ、1 つ以上のエンティティを返す です。Second best is a Range Query that uses the PartitionKey and filters on a range of RowKey values to return more than one entity. PartitionKey 値は特定のパーティションを識別し、RowKey 値はそのパーティション内のエンティティのサブセットを識別します。The PartitionKey value identifies a specific partition, and the RowKey values identify a subset of the entities in that partition. 例: $filter=PartitionKey eq 'Sales' および RowKey ge 'S' および RowKey lt 'T'For example: $filter=PartitionKey eq 'Sales' and RowKey ge 'S' and RowKey lt 'T'
  • 3 番目に良い方法は、PartitionKey を使用し、他のキーを持たないプロパティにフィルターをかけ、1 つ以上のエンティティを返すことが可能なパーティション スキャンです。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. PartitionKey 値は特定のパーティションを識別し、プロパティ値はそのパーティション内のエンティティのサブセットを選択します。The PartitionKey value identifies a specific partition, and the property values select for a subset of the entities in that partition. 例: $filter = PartitionKey eq '販売'、および LastName eq 'Smith'For example: $filter=PartitionKey eq 'Sales' and LastName eq 'Smith'
  • Table ScanPartitionKey は含まれません。また、一致するエンティティのテーブルを構成するパーティションのすべてを検索するため、非常に非効率的です。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. フィルターが RowKey を使用する / しないに関わりなく、テーブルのスキャンが実行されます。It will perform a table scan regardless of whether or not your filter uses the RowKey. 例: $filter = LastName eq 'Jones'For example: $filter=LastName eq 'Jones'
  • クエリは複数のエンティティを PartitionKeyRowKey の順序で並べ替えて返します。Queries that return multiple entities return them sorted in PartitionKey and RowKey order. クライアント内でエンティティを再度並べ替えるのを防ぐため、最も一般的な並べ替え順序を定義する RowKey を選択します。To avoid resorting the entities in the client, choose a RowKey that defines the most common sort order.

"or" を使用して RowKey 値に基づいてフィルターを指定した場合はパーティション スキャンが行われます。範囲クエリとしては扱われません。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. そのため、$filter = PartitionKey eq 'Sales' and (RowKey eq '121' or 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')

ストレージ クライアント ライブラリを使って効率的なクエリを実行するクライアント側コードの例については、For examples of client-side code that use the Storage Client Library to execute efficient queries, see:

同じテーブルに格納された複数の種類のエンティティを処理できるクライアント側コードの例については、For examples of client-side code that can handle multiple entity types stored in the same table, see:

適切な PartitionKey の選択Choosing an appropriate PartitionKey

選択した PartitionKey は複数のパーティションでエンティティを配布するための要件に対し (一貫性を確保するため) EGT の使用を可能にするため、必要性のバランスを取る必要があります (スケーラブルなソリューションの確保のため)。Your choice of PartitionKey should balance the need to enable the use of EGTs (to ensure consistency) against the requirement to distribute your entities across multiple partitions (to ensure a scalable solution).

すべてのエンティティを 1 つのパーティションに格納することも可能ですが、そうするとソリューションのスケーラビリティが制限され、Table サービスで要求を負荷分散できなくなる可能性があります。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. 逆に、パーティションごとに 1 つのエンティティを格納することもできます。このようにすると、スケーラビリティが高まり、Table サービスで要求を負荷分散できるようになるものの、エンティティ グループ トランザクションは使用できなくなります。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.

理想的な PartitionKey とは、効率的なクエリを使用することができ、スケーラブルなソリューションを確保できるパーティションを持つものを指します。An ideal PartitionKey is one that enables you to use efficient queries and that has sufficient partitions to ensure your solution is scalable. 通常、エンティティには、十分な数のパーティションにエンティティを分散できるだけのプロパティがあります。Typically, you will find that your entities will have a suitable property that distributes your entities across sufficient partitions.

注意

たとえば、ユーザーまたは従業員に関する情報を格納するシステムでは、ユーザー ID を PartitionKey として使うと便利です。For example, in a system that stores information about users or employees, UserID may be a good PartitionKey. パーティション分割キーとして所定の UserID を使用する複数のエンティティを使用できます。You may have several entities that use a given UserID as the partition key. あるユーザーに関するデータを保存するそれぞれのエンティティは 1 つのパーティションにグループ化されるため、高い拡張性を確保しながら、エンティティ グループ トランザクションを介してこれらのエンティティにアクセスできます。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.

選択した PartitionKey についてエンティティの挿入、更新、削除方法に関連する追加の検討事項があります。下記のデータ変更のための設計のセクションをご覧ください。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.

クエリを Table service 向けに最適化するOptimizing queries for the Table service

Table service は 1 つのクラスター化インデックス内の PartitionKeyRowKey 値を使用して自動的にインデックスを作成します。そのため、そのためポイント クエリが使用するには最も効果的です。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. ただし、PartitionKeyRowKey のクラスター化インデックス以外にはインデックスはありません。However, there are no indexes other than that on the clustered index on the PartitionKey and RowKey.

多くの設計は、複数の条件に基づいてエンティティをルックアップできるようにするという要件を満たす必要があります。Many designs must meet requirements to enable lookup of entities based on multiple criteria. たとえば、電子メール、従業員 ID、姓に基づいて従業員エンティティを特定する場合などです。For example, locating employee entities based on email, employee id, or last name. セクションの次のパターン テーブルの設計パターン ではこれらの要件の種類について説明し、また、Table service がセカンダリ インデックスを提供しないことへの対処方法について説明します。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:

Table service でデータを並べ替えるSorting data in the Table service

Table service は、PartitionKey 次に RowKey に基づいた昇順で並べ替え、エンティティを返します。The Table service returns entities sorted in ascending order based on PartitionKey and then by RowKey. これらのキーは文字列値であり、数値を正しく並べ替えるには、固定長の値に変換し、ゼロ パディングを施す必要があります。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. たとえば、従業員 ID 値を整数値の RowKey として使用する場合、従業員 ID を 123 から 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.

さまざまな順序 (名前、入社日など) で並べ替えられたデータを使う必要のあるアプリケーションは多数あります。Many applications have requirements to use data sorted in different orders: for example, sorting employees by name, or by joining date. セクションの次のパターンでは、 テーブルの設計パターン エンティティの並べ替え順序を代替する方法について説明します。The following patterns in the section Table Design Patterns address how to alternate sort orders for your entities:

  • パーティション内のセカンダリ インデックス パターン -異なる RowKey 値(同じパーティション) を使用して各エンティティの複数のコピーを格納し、異なる RowKey 値を使用して効果的な検索と代替的な並べ替え順序を可能にします。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.
  • パーティション内のセカンダリ インデックス パターン -別個のテーブルの別個のパーティションの異なる RowKey 値を使用して各エンティティの複数のコピーを格納し、異なる 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.
  • ログ テール パターン - 逆の日付と時間順で並べ替える RowKey 値を使用して、パーティションに最も新しく追加されたエンティティ n を取得します。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.

データの変更に対応した設計Design for data modification

このセクションでは、挿入、更新、削除の操作を最適化するための設計上の考慮事項を示します。This section focuses on the design considerations for optimizing inserts, updates, and deletes. 場合によっては、リレーショナル データベースの設計と同様に、クエリ向けの最適化とデータ変更向けの最適化のトレードオフを評価する必要があります (設計のトレードオフを管理する手法はリレーショナル データベースでは異なります)。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). テーブルの設計パターン のセクションでは、Table service の詳細な設計パターンをいくつか説明し、これらのトレードオフに注目します。The section Table Design Patterns describes some detailed design patterns for the Table service and highlights some these trade-offs. 実際のところ、クエリ向けに最適化された設計の多くは、エントリの変更にも適していることがおわかりになると思います。In practice, you will find that many designs optimized for querying entities also work well for modifying entities.

挿入、更新、削除の操作のパフォーマンスを最適化するOptimizing the performance of insert, update, and delete operations

エンティティを更新または削除するには、PartitionKeyRowKey 値を使用してエンティティを識別する必要があります。To update or delete an entity, you must be able to identify it by using the PartitionKey and RowKey values. この点で、エンティティの変更のために選択した PartitionKeyRowKey は、できるだけ効率的にエンティティを識別するため、ポイント クエリをサポートするために選択したものと同様の条件に従う必要があります。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. PartitionKeyRowKey 値の検出のためにエンティティを特定する非効率的なパーティションまたはテーブル スキャンを使用したくない場合は、更新または削除する必要があります。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.

セクションの次のパターン Table 設計パターン では、パフォーマンスの最適化または操作の挿入、更新、削除について説明します。The following patterns in the section Table Design Patterns address optimizing the performance or your insert, update, and delete operations:

  • 頻度の高いパターンを削除する -独自の個別のテーブルで同時に削除のすべてのエンティティを格納することにより、大量のエンティティの削除を有効にするには、テーブルを削除して、エンティティを削除します。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.
  • データ系列のパターン -単一のエンティティで完全なデータ系列を格納し、リクエストの作成を最小限に抑えます。Data series pattern - Store complete data series in a single entity to minimize the number of requests you make.
  • ワイド エンティティ パターン -複数の物理エンティティを使用し、252 個以上のプロパティを持つ論理エンティティを格納します。Wide entities pattern - Use multiple physical entities to store logical entities with more than 252 properties.
  • 大型エンティティ パターン -大規模なプロパティの値を格納する BLOB ストレージの使用します。Large entities pattern - Use blob storage to store large property values.

格納されたエンティティの一貫性を確保するEnsuring consistency in your stored entities

データの変更を最適化するためのキーの選択を左右する要因として、アトミックなトランザクションを使って一貫性を確保する方法も挙げられます。The other key factor that influences your choice of keys for optimizing data modifications is how to ensure consistency by using atomic transactions. 同じパーティションに格納されたエンティティを操作する場合は、EGT を使用します。You can only use an EGT to operate on entities stored in the same partition.

セクションの次のパターン テーブルの設計パターン では、 一貫性の管理を説明します。The following patterns in the section Table Design Patterns address managing consistency:

エンティティ グループ トランザクションの詳細については、「 エンティティ グループ トランザクション」のセクションを参照してください。For information about entity group transactions, see the section Entity Group Transactions.

効率的な変更に対応した設計によるクエリの効率化Ensuring your design for efficient modifications facilitates efficient queries

効率的なクエリに適した設計は変更の効率も高いのが普通ですが、自分のシナリオにもそれが当てはまるかどうかは必ず評価する必要があります。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. テーブルの設計パターンセクションのパターンの中には、エンティティをクエリして変更する間に明示的にトレードオフを評価するものがあります。常に各操作数を考慮しておく必要があります。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.

テーブルの設計パターン セクションの以下のパターンでは、 効率的なクエリの設計と効率的なデータ変更の設計の間のトレードオフについて説明します。The following patterns in the section Table Design Patterns address trade-offs between designing for efficient queries and designing for efficient data modification:

  • 複合キー パターン -複合 RowKey 値を使用して、1 つのポイント クエリに関連するデータを検索するクライアントを有効にします。Compound key pattern - Use compound RowKey values to enable a client to lookup related data with a single point query.
  • ログ テール パターン - 逆の日付と時間順で並べ替える RowKey 値を使用して、パーティションに最も新しく追加されたエンティティ n を取得します。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.

テーブル データの暗号化Encrypting Table Data

.NET Azure Storage クライアント ライブラリでは、挿入および置換操作の文字列エンティティ プロパティの暗号化がサポートされます。The .NET Azure Storage Client Library supports encryption of string entity properties for insert and replace operations. 暗号化された文字列はバイナリ プロパティとしてサービスで保存され、復号化された後、文字列に変換されて戻されます。The encrypted strings are stored on the service as binary properties, and they are converted back to strings after decryption.

テーブルの場合、暗号化ポリシーに加え、ユーザーは暗号化するプロパティを指定する必要があります。For tables, in addition to the encryption policy, users must specify the properties to be encrypted. これを実行するには、[EncryptProperty] 属性を指定するか (TableEntity から派生した POCO エンティティ用)、または要求オプションで暗号化リゾルバーを指定します。This can be done by either specifying an [EncryptProperty] attribute (for POCO entities that derive from TableEntity) or an encryption resolver in request options. 暗号化リゾルバーは、パーティション キー、行キー、プロパティ名を取得するデリゲートで、プロパティを暗号化するかどうかを示すブール値を返します。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. 暗号化時、クライアント ライブラリはこの情報を使用して、ネットワークへの書き込み時にプロパティを暗号化するかどうかを決定します。During encryption, the client library will use this information to decide whether a property should be encrypted while writing to the wire. また、デリゲートは、プロパティの暗号化方法に関するロジックを使用する可能性にも備えます。The delegate also provides for the possibility of logic around how properties are encrypted. (X の場合、プロパティ A を暗号化し、それ以外の場合はプロパティ A および B を暗号化するなど。)エンティティの読み込み中、またはクエリの実行中は、この情報を指定する必要はありません。(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.

現在、マージはサポートされていません。Note that merge is not currently supported. 別のキーを使用してプロパティのサブセットが以前に暗号化されている場合、新しいプロパティをマージしたり、メタデータを更新したりするとデータ損失が発生します。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. マージでは、追加のサービス呼び出しをして既存のエンティティをサービスから読み込むか、プロパティごとに新しいキーを使用する必要があります。いずれの方法も、パフォーマンス上の理由でお勧めできません。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.

テーブル データの暗号化については、「 Microsoft Azure Storage のクライアント側の暗号化と Azure Key Vault」を参照してください。For information about encrypting table data, see Client-Side Encryption and Azure Key Vault for Microsoft Azure Storage.

リレーションシップのモデル化Modelling relationships

複雑なシステムの設計において、ドメイン モデルの作成は重要なステップです。Building domain models is a key step in the design of complex systems. 通常は、ビジネス ドメインについて理解し、システムの設計を伝えるための方法として、モデル化プロセスを使用してエンティティとエンティティどうしのリレーションシップを特定します。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. このセクションでは、ドメイン モデル内の一般的なリレーションシップの種類を Table service 向けの設計に変換する方法を中心に説明します。This section focuses on how you can translate some of the common relationship types found in domain models to designs for the Table service. 論理データ モデルから物理的な NoSQL ベースのデータ モデルへのマッピング プロセスは、リレーショナル データベースの設計時に使われるプロセスとは大きく異なります。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. リレーショナル データベースの設計は、通常、冗長性を最小限に抑えるために最適化されたデータの正規化プロセスと、データベースの動作の実装方法を抽象化する宣言によるクエリ機能があることを前提としています。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.

一対多のリレーションシップOne-to-many relationships

ビジネス ドメイン オブジェクトの間で一対多のリレーションシップが存在することはよくあります。たとえば、1 つの部署に多数の従業員が存在する場合などです。One-to-many relationships between business domain objects occur very frequently: for example, one department has many employees. 特定のシナリオにおいて、長短それぞれあるものの、Table service に一対多のリレーションシップを実装する方法はいくつかあります。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.

何万もの部署と従業員のエンティティがある大規模な多国籍企業の例を考えてみてください。各部署には多数の従業員が在籍しており、各従業員は 1 つの特定の部署に関連付けられています。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. 次のように、部署のエンティティと従業員のエンティティを分けて格納する方法もあります。One approach is to store separate department and employee entities such as these:

この例は、 PartitionKey 値に基づいて、各種類における暗黙の一対多のリレーションシップを示しています。This example shows an implicit one-to-many relationship between the types based on the PartitionKey value. 各部署に多数の従業員が存在する可能性があります。Each department can have many employees.

この例は、部署エンティティと、同じパーティションに含まれる関連の従業員エンティティも示しています。This example also shows a department entity and its related employee entities in the same partition. 別のエンティティの種類として、別のパーティション、テーブル、またはストレージ アカウントを使うこともできます。You could choose to use different partitions, tables, or even storage accounts for the different entity types.

別の方法として、次の例に示すように、データを非正規化し、非正規化された部署データと共に従業員エンティティのみを格納する方法もあります。An alternative approach is to denormalize your data and store only employee entities with denormalized department data as shown in the following example. このシナリオで部署のマネージャーの詳細を変更できるようにする必要がある場合は、この非正規化の方法は最適ではない可能性があります。部署内のすべての従業員を更新する必要が生じるためです。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.

詳細については、 このガイドで後述する 非正規化パターン を参照してください。For more information, see the Denormalization pattern later in this guide.

次の表に、上記で概要を示した一対多のリレーションシップを持つ従業員エンティティと部署エンティティを格納するアプローチについて、それぞれの長所と短所をまとめます。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. また、各種操作をどの程度の頻度で実行する見込みかも検討する必要があります。コストの高い操作であっても、実行頻度が高くなければ設計に含めてもかまいません。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.

アプローチApproach 長所Pros 短所Cons
エンティティの種類は別、パーティション、テーブルは同じSeparate entity types, same partition, same table
  • 1 回の操作で部署エンティティを更新できる。You can update a department entity with a single operation.
  • 従業員エンティティを更新、挿入、削除するたびに部署エンティティを変更する必要がある場合は、一貫性を維持するために EGT を使用できます。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. たとえば、部署ごとの従業員数を管理する場合などです。For example if you maintain a departmental employee count for each department.
  • 場合によっては、一部のクライアント アクティビティで、従業員エンティティと部署エンティティの両方を取得する必要がある。You may need to retrieve both an employee and a department entity for some client activities.
  • ストレージ操作が同じパーティションで行われる。Storage operations happen in the same partition. トランザクションの量が多いときにホットスポットが生じる可能性がある。At high transaction volumes, this may result in a hotspot.
  • EGT を使用して従業員を新しい部署に移動できない。You cannot move an employee to a new department using an EGT.
エンティティの種類は別、パーティション、テーブル、ストレージ アカウントは別Separate entity types, different partitions or tables or storage accounts
  • 1 回の操作で部署エンティティと従業員エンティティを更新できる。You can update a department entity or employee entity with a single operation.
  • トランザクションの量が多いときに、負荷をより多くのパーティションに分散させることができる。At high transaction volumes, this may help spread the load across more partitions.
  • 場合によっては、一部のクライアント アクティビティで、従業員エンティティと部署エンティティの両方を取得する必要がある。You may need to retrieve both an employee and a department entity for some client activities.
  • 従業員を更新、挿入、削除し、部署を更新するときに、一貫性を維持するために EGT を使用できる。You cannot use EGTs to maintain consistency when you update/insert/delete an employee and update a department. たとえば、部署エンティティ内の従業員数を更新する場合などです。For example, updating an employee count in a department entity.
  • EGT を使用して従業員を新しい部署に移動できない。You cannot move an employee to a new department using an EGT.
単一のエンティティの種類への非正規化Denormalize into single entity type
  • 必要なすべての情報を 1 回の要求で取得できる。You can retrieve all the information you need with a single request.
  • 部署の情報を更新する必要がある場合、一貫性の維持のコストが高くなる可能性がある (部署のすべての従業員を更新する必要があるため)。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).

これらの選択肢のうちのどれを選ぶかや、どの長所と短所の影響が最も大きいかは、アプリケーションのシナリオによって異なります。How you choose between these options, and which of the pros and cons are most significant, depends on your specific application scenarios. たとえば、部署エンティティを変更する頻度、すべての従業員クエリに追加の部署情報が必要かどうか、パーティションまたはストレージ アカウントのスケーラビリティの制限までどのくらいかなどです。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?

一対一のリレーションシップOne-to-one relationships

ドメイン モデルにはエンティティ間の一対一のリレーションシップが含まれることもあります。Domain models may include one-to-one relationships between entities. Table service で一対一のリレーションシップを実装する必要がある場合は、2 つの関連するエンティティを取得する必要があるときにそれらをリンクする方法も選択する必要があります。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. このリンクはキー値の規則に基づいて、各エンティティにおいて PartitionKeyRowKey 値形式で関連エンティティへのリンクを格納することで、明示的にも暗黙的にも成り得ます。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. 同じパーティションに関連エンティティを格納するかどうかの詳細については、 一対多のリレーションシップセクションを参照してください。For a discussion of whether you should store the related entities in the same partition, see the section One-to-many relationships.

実装上の検討内容に応じて、Table service で一対一のリレーションシップを実装する必要が生じることもあります。Note that there are also implementation considerations that might lead you to implement one-to-one relationships in the Table service:

クライアントでの結合Join in the client

Table service でのリレーションシップのモデル化には何とおりかの方法があるものの、Table service を使う主な理由はスケーラビリティとパフォーマンスの 2 つであることを忘れないでください。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. ソリューションのパフォーマンスとスケーラビリティを損なう多数のリレーションシップをモデル化しようとしていることに気が付いた場合は、そのすべてのデータ リレーションシップをテーブル設計に組み込む必要があるかどうかを確認する必要があります。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. クライアント アプリケーションで必要な結合が実行されるようにすると、設計を簡素化し、ソリューションのスケーラビリティとパフォーマンスを向上させることができます。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.

たとえば、変更頻度の高くないデータが格納された小さなテーブルがある場合は、そのデータを取得した後でクライアント上にキャッシュできます。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. そうすると、何度も同じデータを取得する必要がなくなります。This can avoid repeated roundtrips to retrieve the same data. このガイドで見てきた例では、小規模な組織の部署のセットは小さく、変更頻度も低いことが多いので、データをクライアント アプリケーションでダウンロードしてからルックアップ データとしてキャッシュするのに適しています。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.

継承リレーションシップInheritance relationships

クライアント アプリケーションでビジネス エンティティを表す継承リレーションシップの一部を構成するクラスのセットを使用する場合は、それらのエンティティを Table service で簡単に保持できます。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. たとえば、 が抽象クラスとなっているクライアント アプリケーションにはクラスセットが定義されている可能性があります。For example, you might have the following set of classes defined in your client application where Person is an abstract class.

エンティティを次のように扱う 1 つの Person テーブルを使えば、2 つの具象クラスのインスタンスを Table service で維持できます。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:

クライアント コードの同じテーブル内の複数のエンティティ種類の詳細については、このガイドの後述のセクション 異種のエンティティ種類の使用 を参照してください。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. クライアント コードでエンティティの種類を認識する方法の例が示されています。This provides examples of how to recognize the entity type in client code.

テーブルの設計パターンTable Design Patterns

前のセクションでは、クエリを使用してエンティティ データを取得する場合と、エンティティ データを挿入、更新、削除する場合の両方のテーブル設計を最適化する方法について詳しく説明しました。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. このセクションでは、Table service ソリューションで使用するのに適したパターンをいくつか紹介します。This section describes some patterns appropriate for use with Table service solutions. また、このガイドで前に提起された問題とトレードオフの一部に実際に対処する方法を説明しています。In addition, you will see how you can practically address some of the issues and trade-offs raised previously in this guide. 次の図は、さまざまなパターンの関係をまとめたものです。The following diagram summarizes the relationships between the different patterns:

上記のパターン マップには、このガイドに記載されているパターン (青) とアンチパターン (オレンジ) の関係の一部が示されています。The pattern map above highlights some relationships between patterns (blue) and anti-patterns (orange) that are documented in this guide. もちろん、検討する価値があるパターンは他にもたくさんあります。There are of course many other patterns that are worth considering. たとえば、Table サービス向けの主なシナリオの 1 つに、コマンド クエリ責務分離 (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.

パーティション内のセカンダリ インデックス パターンIntra-partition secondary index pattern

異なる RowKey 値 (同じパーティション内) を使用して各エンティティの複数のコピーを格納し、異なる RowKey 値を使用した高速で効率的な検証と代替の並べ替え順序を可能にします。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. コピー間の更新の一貫性は、EGT を使用して保つことができます。Updates between copies can be kept consistent using EGT's.

コンテキストと問題Context and problem

Table service は PartitionKeyRowKey 値を使用して自動的にインデックスを作成します。The Table service automatically indexes entities using the PartitionKey and RowKey values. そのため、クライアント アプリケーションでは、これらの値を使用してエンティティを効率的に取得できます。This enables a client application to retrieve an entity efficiently using these values. たとえば、次のようなテーブル構造を使用することにより、クライアント アプリケーションでは、ポイント クエリを使用して部署名と従業員 ID (PartitionKeyRowKey 値) から、個々の従業員エンティティを取得できます。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). また、各部署内の従業員 ID で並べ替えたエンティティを取得することも可能です。A client can also retrieve entities sorted by employee id within each department.

また、電子メール アドレスなど、他のプロパティの値に基づいて従業員エンティティを検索できるようにする場合は、効率の劣るパーティション スキャンを使用して、一致するエンティティを検索する必要があります。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. これは、Table サービスではセカンダリ インデックスが提供されないためです。This is because the table service does not provide secondary indexes. さらに、 RowKey 順以外の順序で並べ替えられた従業員の一覧を要求するオプションはありません。In addition, there is no option to request a list of employees sorted in a different order than RowKey order.

解決策Solution

セカンダリ インデックスの不足を回避するには、異なる RowKey 値を使用して各コピーの複数コピーを格納します 。To work around the lack of secondary indexes, you can store multiple copies of each entity with each copy using a different RowKey value. 次のような構造体を持つエンティティを格納する場合は、電子メール アドレスや従業員 ID に基づく複数の 従業員エンティティを効率的に取得できます。RowKey のプレフィックス値、"empid"、"email" で、1 人の従業員をクエリするか電子メール アドレスまたは従業員 ID の範囲を使用して、ある特定の範囲の従業員をクエリできます。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.

次の 2 つのフィルター条件 (従業員 ID で検索するフィルター条件と電子メール アドレスで検索するフィルター条件) ではどちらもポイント クエリを指定しています。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') と (RowKey eq 'empid_000223')$filter=(PartitionKey eq 'Sales') and (RowKey eq 'empid_000223')
  • $filter=(PartitionKey eq 'Sales') と (RowKey eq 'email_jonesj@contoso.com')$filter=(PartitionKey eq 'Sales') and (RowKey eq 'email_jonesj@contoso.com')

一連の複数の従業員エンティティの範囲をクエリする場合は、従業員 ID の順に並べ替えられた範囲を指定するか、適切なプレフィックスを持つエンティティのクエリを実行して、 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.

  • Sales 部署において、従業員 ID、000100 から 000199 を指定して、すべての従業員を検索するには: $filter=(PartitionKey eq 'Sales') and (RowKey ge 'empid_000100') and (RowKey le 'empid_000199') を使用します。To find all the employees in the Sales department with an employee id in the range 000100 to 000199 use: $filter=(PartitionKey eq 'Sales') and (RowKey ge 'empid_000100') and (RowKey le 'empid_000199')
  • Sales 部署において、'a' で始まる電子メール アドレスを持つすべての従業員を検索するには:$filter=(PartitionKey eq 'Sales') and (RowKey ge 'email_a') and (RowKey lt 'email_b') を使用します。To find all the employees in the Sales department with an email address starting with the letter 'a' use: $filter=(PartitionKey eq 'Sales') and (RowKey ge 'email_a') and (RowKey lt 'email_b')

    上記の例で使用しているフィルター構文は、Table service REST API の構文です。詳細については、「Query Entities (エンティティの照会)」をご覧ください。Note that the filter syntax used in the examples above is from the Table service REST API, for more information see Query Entities.

問題と注意事項Issues and considerations

このパターンの実装方法を決めるときには、以下の点に注意してください。Consider the following points when deciding how to implement this pattern:

  • テーブル ストレージは比較的低コストで利用できるため、重複するデータを格納してもコストは大きな問題になりません。Table storage is relatively cheap to use so the cost overhead of storing duplicate data should not be a major concern. ただし、必ず、予想されるストレージ要件に基づいて設計のコストを見積もり、クライアント アプリケーションが実行するクエリで使用するエンティティのみを複製する必要があります。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.
  • セカンダリ インデックス エンティティは元のエンティティと同じパーティションに格納されるため、個々のパーティションのスケーラビリティ ターゲットを超えないようにする必要があります。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.
  • EGT を使用してエンティティの 2 つのコピーをアトミックに更新することで、重複するエンティティどうしの一貫性を保つことができます。You can keep your duplicate entities consistent with each other by using EGTs to update the two copies of the entity atomically. そのためには、エンティティのすべてのコピーを同じパーティションに格納する必要があります。This implies that you should store all copies of an entity in the same partition. 詳細については、 エンティティ グループ トランザクションを使用するセクションを参照してください。For more information, see the section Using Entity Group Transactions.
  • RowKey に使用される値は 各エンティティに対して一意である必要があります。The value used for the RowKey must be unique for each entity. 複合キー値の使用を検討してください。Consider using compound key values.
  • 数値を RowKey (たとえば、従業員 ID 000223)にパディングすると、上限と下限に基づき正確な並べ替えとフィルタリングが可能になります。Padding numeric values in the RowKey (for example, the employee id 000223), enables correct sorting and filtering based on upper and lower bounds.
  • 必ずしもエンティティのすべてのプロパティを複製する必要はありません。You do not necessarily need to duplicate all the properties of your entity. たとえば、電子メールアドレスを使用してエンティティを RowKey で検索するクエリの場合、従業員の年齢は不要です。このようなエンティティは、次のような構造になっている可能性があります。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:

  • 通常は、エンティティの検索と必要なデータの検索にそれぞれ異なるクエリを使用するよりも、重複するデータを格納し、必要なすべてのデータを単一のクエリで取得できるようにすることをお勧めします。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.

このパターンを使用する状況When to use this pattern

クライアント アプリケーションで異なるさまざまなキーを使用してエンティティを取得する必要がある場合、クライアントで異なる順序で並べ替えたエンティティを取得する必要がある場合、さまざまな一意の値を使用して各エンティティを識別できる場合に、このパターンを使用します。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. ただし、異なる RowKey 値を使用してエンティティ参照を実行している場合は、パーティションのスケーラビリティの制限を超えていないことを確認してください。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.

このパターンを実装する場合は、次のパターンとガイダンスも関連している可能性があります。The following patterns and guidance may also be relevant when implementing this pattern:

パーティション内のセカンダリ インデックス パターンInter-partition secondary index pattern

別個のテーブルの別個のパーティションの異なるRowKey 値 (同じパーティション内) を使用して各エンティティの複数のコピーを格納し、異なる RowKey 値を使用した高速で効率的な検証と代替の並べ替え順序を可能にします。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.

コンテキストと問題Context and problem

Table service は PartitionKeyRowKey 値を使用して自動的にインデックスを作成します。The Table service automatically indexes entities using the PartitionKey and RowKey values. そのため、クライアント アプリケーションでは、これらの値を使用してエンティティを効率的に取得できます。This enables a client application to retrieve an entity efficiently using these values. たとえば、次のようなテーブル構造を使用することにより、クライアント アプリケーションでは、ポイント クエリを使用して部署名と従業員 ID (PartitionKeyRowKey 値) から、個々の従業員エンティティを取得できます。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). また、各部署内の従業員 ID で並べ替えたエンティティを取得することも可能です。A client can also retrieve entities sorted by employee id within each department.

また、電子メール アドレスなど、他のプロパティの値に基づいて従業員エンティティを検索できるようにする場合は、効率の劣るパーティション スキャンを使用して、一致するエンティティを検索する必要があります。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. これは、Table サービスではセカンダリ インデックスが提供されないためです。This is because the table service does not provide secondary indexes. さらに、 RowKey 順以外の順序で並べ替えられた従業員の一覧を要求するオプションはありません。In addition, there is no option to request a list of employees sorted in a different order than RowKey order.

これらのエンティティに対するトランザクションの量が膨大になることが予想される場合は、Table service によってクライアントが調整されるリスクを最小限に抑える必要があります。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.

解決策Solution

セカンダリ インデックスの不足を回避するには、異なるPartitionKeyRowKey 値を使用して各コピーの複数コピーを格納します。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. 次のような構造体を持つエンティティを格納する場合は、電子メール アドレスや従業員 ID に基づく複数の 従業員エンティティを効率的に取得できます。PartitionKey のプレフィックスの値、"empid_" と "email_" で、クエリに使用するインデックスを特定することができます。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.

次の 2 つのフィルター条件 (従業員 ID で検索するフィルター条件と電子メール アドレスで検索するフィルター条件) ではどちらもポイント クエリを指定しています。The following two filter criteria (one looking up by employee id and one looking up by email address) both specify point queries:

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

一連の複数の従業員エンティティの範囲をクエリする場合は、従業員 ID の順に並べ替えられた範囲を指定するか、適切なプレフィックスを持つエンティティのクエリを実行して、 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.

  • 従業員 ID 順で格納された、従業員 ID が000100 から 000199 の範囲の Sales 部署のすべての従業員を検索するには、$filter=(PartitionKey eq 'empid_Sales') と (RowKey ge '000100') および (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')
  • Sales 部署において、電子メール アドレス順で格納された電子メール アドレスで、'a' で始まる電子メール アドレスを持つすべての従業員を検索するには: $filter=(PartitionKey eq 'email_Sales') and (RowKey ge 'a') and (RowKey lt 'b') を使用します。To find all the employees in the Sales department with an email address that starts with 'a' sorted in email address order use: $filter=(PartitionKey eq 'email_Sales') and (RowKey ge 'a') and (RowKey lt 'b')

上記の例で使用しているフィルター構文は、Table service REST API の構文です。詳細については、「Query Entities (エンティティの照会)」をご覧ください。Note that the filter syntax used in the examples above is from the Table service REST API, for more information see Query Entities.

問題と注意事項Issues and considerations

このパターンの実装方法を決めるときには、以下の点に注意してください。Consider the following points when deciding how to implement this pattern:

  • プライマリとセカンダリ インデックスのエンティティを維持するため、重複するエンティティを保持して、 最終的に一貫性のあるトランザクション パターン を使用し、互いに最終的に一貫性を持たせます。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.
  • テーブル ストレージは比較的低コストで利用できるため、重複するデータを格納してもコストは大きな問題になりません。Table storage is relatively cheap to use so the cost overhead of storing duplicate data should not be a major concern. ただし、必ず、予想されるストレージ要件に基づいて設計のコストを見積もり、クライアント アプリケーションが実行するクエリで使用するエンティティのみを複製する必要があります。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.
  • RowKey に使用される値は 各エンティティに対して一意である必要があります。The value used for the RowKey must be unique for each entity. 複合キー値の使用を検討してください。Consider using compound key values.
  • 数値を RowKey (たとえば、従業員 ID 000223)にパディングすると、上限と下限に基づき正確な並べ替えとフィルタリングが可能になります。Padding numeric values in the RowKey (for example, the employee id 000223), enables correct sorting and filtering based on upper and lower bounds.
  • 必ずしもエンティティのすべてのプロパティを複製する必要はありません。You do not necessarily need to duplicate all the properties of your entity. たとえば、電子メールアドレスを使用してエンティティを RowKey で検索するクエリの場合、従業員の年齢は不要です。このようなエンティティは、次のような構造になっている可能性があります。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:

  • 通常は、セカンダリ インデックスを使用したエンティティの検索とプライマリ インデックス内の必要なデータの検索にそれぞれ異なるクエリを使用するよりも、重複するデータを格納し、必要なすべてのデータを単一のクエリで取得できるようにすることをお勧めします。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.

このパターンを使用する状況When to use this pattern

クライアント アプリケーションで異なるさまざまなキーを使用してエンティティを取得する必要がある場合、クライアントで異なる順序で並べ替えたエンティティを取得する必要がある場合、さまざまな一意の値を使用して各エンティティを識別できる場合に、このパターンを使用します。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. 異なる 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.

このパターンを実装する場合は、次のパターンとガイダンスも関連している可能性があります。The following patterns and guidance may also be relevant when implementing this pattern:

最終的に一貫性のあるトランザクション パターンEventually consistent transactions pattern

Azure キューを使用して、パーティションやストレージ システムの境界を越えて、最終的に一貫した動作を実現します。Enable eventually consistent behavior across partition boundaries or storage system boundaries by using Azure queues.

コンテキストと問題Context and problem

EGT を使用すると、同じパーティション キーを共有する複数のエンティティに対してアトミックなトランザクションを実行できます。EGTs enable atomic transactions across multiple entities that share the same partition key. パフォーマンスやスケーラビリティの関係で、一貫性が必要なエンティティを別々のパーティションや別のストレージ システムに格納する場合があります。そのような場合は、EGT を使用して一貫性を保つことはできません。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. たとえば、次の一貫性を最終的に確保する必要があるとします。For example, you might have a requirement to maintain eventual consistency between:

  • 同じテーブル内の 2 つの異なるパーティション、異なるテーブル、異なるストレージ アカウントに格納されているエンティティ。Entities stored in two different partitions in the same table, in different tables, in in different storage accounts.
  • Table service に格納されているエンティティと Blob service に格納されている BLOB。An entity stored in the Table service and a blob stored in the Blob service.
  • Table service に格納されているエンティティとファイル システム内のファイル。An entity stored in the Table service and a file in a file system.
  • Table service に格納されているにもかかわらず、Azure Search サービスを使用してインデックスが作成されているエンティティ。An entity store in the Table service yet indexed using the Azure Search service.

解決策Solution

Azure キューを使用すると、2 つ以上のパーティションまたはストレージ システム間で最終的に一貫性を確保するソリューションを実装できます。By using Azure queues, you can implement a solution that delivers eventual consistency across two or more partitions or storage systems. この方法を説明するために、退職した従業員エンティティをアーカイブできるようにする必要があるとします。To illustrate this approach, assume you have a requirement to be able to archive old employee entities. 退職した従業員エンティティはめったに照会されず、現在の従業員を対象にしたすべてのアクティビティから除外する必要があります。Old employee entities are rarely queried and should be excluded from any activities that deal with current employees. この要件を実装するには、現在テーブルにいる現在の従業員と、アーカイブ テーブルにいる退職した従業員を格納します。To implement this requirement you store active employees in the Current table and old employees in the Archive table. 従業員をアーカイブするには、現在テーブルからのエンティティを削除し、アーカイブ テーブルにエンティティを追加する必要がありますが、これら 2 つの操作を実行する EGT は使用できません。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. エンティティが両方のテーブルに表示されることや、どちらのテーブルにも表示されないことがないように、アーカイブ操作は最終的に一貫性が確保される必要があります。To avoid the risk that a failure causes an entity to appear in both or neither tables, the archive operation must be eventually consistent. 次のシーケンス図は、この操作の大まかな手順を示しています。The following sequence diagram outlines the steps in this operation. その下のテキストには、例外パスの詳細が示されています。More detail is provided for exception paths in the text following.

クライアントは、Azure キューにメッセージを配置することによって、アーカイブ操作を開始します。この例では、ID が 456 の従業員をアーカイブします。A client initiates the archive operation by placing a message on an Azure queue, in this example to archive employee #456. worker ロールは、キューをポーリングして新しいメッセージの有無を確認します。メッセージを見つけると、そのメッセージを読み取り、隠しコピーをキューに残します。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. worker ロールは、次に、現在テーブルからコピーをフェッチし、アーカイブ テーブルにコピーを挿入し、その後、元のデータを現在テーブルから削除します。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. 最後に、前の手順でエラーが発生しなければ、worker ロールはキューから隠しメッセージを削除します。Finally, if there were no errors from the previous steps, the worker role deletes the hidden message from the queue.

この例では、ステップ 4 で従業員を アーカイブ テーブルに挿入しています。In this example, step 4 inserts the employee into the Archive table. Blob service の BLOB またはファイル システム内のファイルに従業員を加えることもできます。It could add the employee to a blob in the Blob service or a file in a file system.

エラーからの回復Recovering from failures

worker ロールがアーカイブ操作を再開する必要がある場合、手順 45 の操作がべき等になっていることが重要です。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. Table service を使用している場合、手順 4 で「挿入または置換」操作を使用する必要があります。手順 5 では、使用しているクライアント ライブラリ で "存在する場合は削除" 操作を使用する必要があります。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. 他のストレージ システムを使用する場合は、適切なべき等操作を使用する必要があります。If you are using another storage system, you must use an appropriate idempotent operation.

worker ロールが手順 6を完了しない場合は、タイムアウトの後、メッセージが worker ロール準備完了のキューに表示され再処理を試みます。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. worker ロールは、キュー上のメッセージを読み取った回数を確認し、必要に応じて、別のキューに送信することで、調査のために "有害" メッセージとしてフラグを設定できます。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. キュー メッセージの読み取りとデキューカウントのチェックに関する詳細については、 メッセージを取得を参照してください。For more information about reading queue messages and checking the dequeue count, see Get Messages.

Table サービスと Queue サービスのエラーには一時的なエラーもあります。クライアント アプリケーションには、そうしたエラーに対処する適切な再試行ロジックを組み込む必要があります。Some errors from the Table and Queue services are transient errors, and your client application should include suitable retry logic to handle them.

問題と注意事項Issues and considerations

このパターンの実装方法を決めるときには、以下の点に注意してください。Consider the following points when deciding how to implement this pattern:

  • このソリューションは、トランザクションを分離するためのソリューションではありません。This solution does not provide for transaction isolation. たとえば、worker ロールがステップ 45 の間で、クライアントは現在アーカイブ テーブルを読み込むことができます。また、データの非一貫性表示を参照できます。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. データは最終的に一貫性が確保されます。Note that the data will be consistent eventually.
  • 最終的に一貫性を確保するために、手順 4. と 5. がべき等になっていることを確認する必要があります。You must be sure that steps 4 and 5 are idempotent in order to ensure eventual consistency.
  • 複数のキューと worker ロール インスタンスを使用して、ソリューションを拡張できます。You can scale the solution by using multiple queues and worker role instances.

このパターンを使用する状況When to use this pattern

別のパーティションまたはテーブルに存在するエンティティ間の一貫性を最終的に確保する必要がある場合に、このパターンを使用します。Use this pattern when you want to guarantee eventual consistency between entities that exist in different partitions or tables. このパターンを拡張して、Table service と Blob service のほかにも、データベースやファイル システムなどの Azure 以外のストレージ データ ソース間の操作で最終的な一貫性を確保できます。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.

このパターンを実装する場合は、次のパターンとガイダンスも関連している可能性があります。The following patterns and guidance may also be relevant when implementing this pattern:

注意

ソリューションにとってトランザクションの分離が重要な場合は、EGT を使用できるようにテーブルを再設計することを検討する必要があります。If transaction isolation is important to your solution, you should consider redesigning your tables to enable you to use EGTs.

インデックス エンティティのパターンIndex Entities Pattern

インデックス エンティティを保持して、エンティティの一覧を返す効率の良い検索を実現します。Maintain index entities to enable efficient searches that return lists of entities.

コンテキストと問題Context and problem

Table service は PartitionKeyRowKey 値を使用して自動的にインデックスを作成します。The Table service automatically indexes entities using the PartitionKey and RowKey values. そうすると、クライアント アプリケーションでポイント クエリを使用してエンティティを効率的に取得できます。This enables a client application to retrieve an entity efficiently using a point query. たとえば、次のようなテーブル構造を使用することにより、クライアント アプリケーションでは、部署名と従業員 ID (PartitionKeyRowKey 値) から、個々の従業員エンティティを効率的に取得できます。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).

また、姓など、一意ではない他のプロパティの値に基づいて従業員エンティティの一覧を取得できるようにする場合は、インデックスを使用して直接一致するエンティティを検索せずに、効率の劣るパーティション スキャンを使用して検索する必要があります。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. これは、Table サービスではセカンダリ インデックスが提供されないためです。This is because the table service does not provide secondary indexes.

解決策Solution

上のエンティティ構造の場合、姓で検索できるようにするには、従業員 ID の一覧を保持する必要があります。To enable lookup by last name with the entity structure shown above, you must maintain lists of employee ids. Jones など、特定の姓を持つ従業員エンティティを取得するには、まず姓が Jones である従業員の従業員 ID の一覧を検索してから、それらの従業員エンティティを取得する必要があります。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. 従業員 ID の一覧を格納する方法は主に次の 3 つがあります。There are three main options for storing the lists of employee ids:

  • BLOB ストレージを使用する。Use blob storage.
  • 従業員エンティティと同じパーティションにインデックス エンティティを作成する。Create index entities in the same partition as the employee entities.
  • 別のパーティションまたはテーブルにインデックス エンティティを作成する。Create index entities in a separate partition or table.

オプション 1: BLOB ストレージの使用Option #1: Use blob storage

最初のオプションでは、すべての一意の姓について Blob を作成し、その姓の従業員用の各 Blob には PartitionKey (部署) と RowKey (従業員 ID) 値が格納されます。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. 従業員を追加または削除した場合は、関連する BLOB の内容と従業員エンティティの一貫性が最終的に確保されていることを確認する必要があります。When you add or delete an employee you should ensure that the content of the relevant blob is eventually consistent with the employee entities.

オプション 2: 同じパーティション内のインデックス エンティティの作成Option #2: Create index entities in the same partition

2 番目の方法では、以下のデータを格納するインデックス エンティティを使用します。For the second option, use index entities that store the following data:

従業員 ID プロパティには、RowKey に格納されている姓を持つ従業員の従業員 ID リストが含まれています。The EmployeeIDs property contains a list of employee ids for employees with the last name stored in the RowKey.

次の手順は、2 番目の方法を使用した場合に、新しい従業員を追加するときに従う必要がある手順の概要を示しています。The following steps outline the process you should follow when you are adding a new employee if you are using the second option. この例では、Sales 部署で ID が 000152、姓が Jones の従業員を追加します。In this example, we are adding an employee with Id 000152 and a last name Jones in the Sales department:

  1. PartitionKey 値 "Sales" と RowKey 値 "Jones" を持つインデックスのエンティティを取得します。Retrieve the index entity with a PartitionKey value "Sales" and the RowKey value "Jones." このエンティティの ETag を、手順 2. で使用するために保存します。Save the ETag of this entity to use in step 2.
  2. 新しい従業員エンティティを挿入するエンティティ グループ トランザクション、つまり、バッチ操作(PartitionKey 値 "Sales" と RowKey 値 "000152") を作成し、新しい従業員 ID を従業員 ID フィールドに追加することでインデックス エンティティ (PartitionKey 値 "Sales" と RowKey 値 "Jones") を更新します。Create an entity group transaction (that is, a batch operation) that inserts the new employee entity (PartitionKey value "Sales" and RowKey value "000152"), and updates the index entity (PartitionKey value "Sales" and RowKey value "Jones") by adding the new employee id to the list in the EmployeeIDs field. エンティティ グループ トランザクションの詳細については、「 エンティティ グループ トランザクション」をご覧ください。For more information about entity group transactions, see Entity Group Transactions.
  3. オプティミスティック同時実行エラー (他のユーザーがインデックス エンティティを変更したこと) が原因でエンティティ グループ トランザクションが失敗した場合は、手順 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.

2 番目の方法を使用する場合は、同じような方法で従業員を削除できます。You can use a similar approach to deleting an employee if you are using the second option. 従業員の姓を変更するのは、3 つのエンティティ (従業員エンティティ、元の姓のインデックス エンティティ、新しい姓のインデックス エンティティ) を更新するエンティティ グループ トランザクションを実行する必要があるため、少し複雑です。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. 変更を加える前に、各エンティティを取得して、ETag 値を取得する必要があります。その ETag 値を使用して、オプティミスティック同時実行で更新を実行できます。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.

次の手順は、2 番目の方法を使用した場合に、ある部署で特定の姓を持つすべての従業員を検索する必要があるときに従う必要がある手順の概要を示しています。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. この例では、Sales 部署で姓が Jones のすべての従業員を検索します。In this example, we are looking up all the employees with last name Jones in the Sales department:

  1. PartitionKey 値 "Sales" と RowKey 値 "Jones" を持つインデックスのエンティティを取得します。Retrieve the index entity with a PartitionKey value "Sales" and the RowKey value "Jones."
  2. EmployeeIDs フィールドで従業員 ID の一覧を解析します。Parse the list of employee Ids in the EmployeeIDs field.
  3. 各従業員に関する追加情報(電子メール アドレスなど) が必要な場合は、手順 2 で取得した従業員リストから PartitionKey 値 "Sales" と RowKey 値を使用して各従業員のエンティティを取得します。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.

オプション 3: 別のパーティションまたはテーブルにインデックス エンティティを作成するOption #3: Create index entities in a separate partition or table

3 番目の方法では、以下のデータを格納するインデックス エンティティを使用します。For the third option, use index entities that store the following data:

従業員 ID プロパティには、RowKey に格納されている姓を持つ従業員の従業員 ID リストが含まれています。The EmployeeIDs property contains a list of employee ids for employees with the last name stored in the RowKey.

3 番目の方法では、インデックス エンティティが従業員エンティティとは別のパーティションにあるため、EGT を使用して一貫性を保つことはできません。With the third option, you cannot use EGTs to maintain consistency because the index entities are in a separate partition from the employee entities. インデックス エンティティが従業員エンティティと最終的に一貫していることを確認する必要があります。You should ensure that the index entities are eventually consistent with the employee entities.

問題と注意事項Issues and considerations

このパターンの実装方法を決めるときには、以下の点に注意してください。Consider the following points when deciding how to implement this pattern:

  • このソリューションでは、一致するエンティティを取得するために、少なくとも 2 つのクエリが必要です。1 つはインデックス エンティティを照会して RowKey 値の一覧を取得するクエリです。もう 1 つはその一覧内の各エンティティを取得するクエリです。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.
  • 個々のエンティティの最大サイズは 1 MB であるため、ソリューションの方法 2 と方法 3 では、特定の姓の従業員 ID の一覧が 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. 従業員 ID の一覧のサイズが 1 MB を超える可能性がある場合は、方法 1 を使用して、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.
  • 方法 2 を使用する (EGT を使用して、従業員の追加と削除、従業員の姓の変更を処理する) 場合は、トランザクションの量が特定のパーティションのスケーラビリティの限界に近づくかどうかを確認する必要があります。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. 限界に近づく場合は、キューを使用して更新要求を処理し、従業員エンティティとは別のパーティションにインデックス エンティティを格納でき、最終的に一貫性が確保されるソリューション (方法 1 または方法 3) を検討する必要があります。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.
  • このソリューションの方法 2 では、部署内を姓で検索する (たとえば、Sales 部署で姓が 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. 組織全体で姓が Jones のすべての従業員を検索できる必要がある場合は、方法 1 と方法 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.
  • 最終的に一貫性が確保されるキューベースのソリューションを実装できます (詳細については、「 最終的に一貫性のあるトランザクション パターン 」を参照してください)。You can implement a queue-based solution that delivers eventual consistency (see the Eventually consistent transactions pattern for more details).

このパターンを使用する状況When to use this pattern

姓が 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.

このパターンを実装する場合は、次のパターンとガイダンスも関連している可能性があります。The following patterns and guidance may also be relevant when implementing this pattern:

非正規化パターンDenormalization pattern

関連するデータを 1 つのエンティティに結合し、1 回のポイント クエリで必要なデータをすべて取得できるようにします。Combine related data together in a single entity to enable you to retrieve all the data you need with a single point query.

コンテキストと問題Context and problem

リレーショナル データベースでは、通常、重複を排除するためにデータを正規化します。その結果、クエリで複数のテーブルからデータを取得することになります。In a relational database, you typically normalize data to remove duplication resulting in queries that retrieve data from multiple tables. Azure テーブルのデータを正規化した場合、関連するデータを取得するには、クライアント アプリケーションとサーバー間のラウンド トリップを複数回行う必要があります。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. たとえば、以下のテーブル構造を使用した場合、部署の詳細を取得するためには、2 回ラウンド トリップを行う必要があります。1 回目のラウンド トリップでマネージャーの ID を含む部署エンティティをフェッチし、2 回目に従業員エンティティからマネージャーの詳細をフェッチします。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.

解決策Solution

データを 2 つのエンティティに格納する代わりに、データを非正規化し、部署エンティティにマネージャーの詳細のコピーを保持します。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. 例: For example:

格納されている部署エンティティにはこれらのプロパティがあるため、ポイント クエリを使用して、部署に関する必要なすべての詳細を取得できます。With department entities stored with these properties, you can now retrieve all the details you need about a department using a point query.

問題と注意事項Issues and considerations

このパターンの実装方法を決めるときには、以下の点に注意してください。Consider the following points when deciding how to implement this pattern:

  • 一部のデータを重複して格納するため、多少コストがかかります。There is some cost overhead associated with storing some data twice. 通常、ストレージ コストの増加はわずかなため、(ストレージ サービスへの要求が減少することによる) パフォーマンス上のメリットが勝ります (このコストの一部は、部署の詳細をフェッチするために必要なトランザクションの数が減少することで相殺されます)。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).
  • マネージャーに関する情報を格納する 2 つのエンティティの一貫性を維持する必要があります。You must maintain the consistency of the two entities that store information about managers. 一貫性の問題は、EGT を使用して単一のアトミックなトランザクションで複数のエンティティを更新することで対処できます。この例では、部署エンティティと、部署マネージャーの従業員エンティティが同じパーティションに格納されています。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.

このパターンを使用する状況When to use this pattern

関連情報を頻繁に検索する必要がある場合に、このパターンを使用します。Use this pattern when you frequently need to look up related information. このパターンを使用すると、クライアントが必要なデータを取得するために実行する必要があるクエリの数が減少します。This pattern reduces the number of queries your client must make to retrieve the data it requires.

このパターンを実装する場合は、次のパターンとガイダンスも関連している可能性があります。The following patterns and guidance may also be relevant when implementing this pattern:

複合キー パターンCompound key pattern

複合 RowKey 値を使用して 1 つのポイント クエリに関連するデータを検索するクライアントを有効にします。Use compound RowKey values to enable a client to lookup related data with a single point query.

コンテキストと問題Context and problem

リレーショナル データベースでは、単一のクエリで関連するデータをクライアントに返すために、クエリでよく結合を使用します。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. たとえば、従業員 ID を使用して、その従業員の業績と評価データが含まれている関連エンティティの一覧を検索する場合があります。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.

次の構造を使用し、Table service に従業員エンティティを格納しているとします。Assume you are storing employee entities in the Table service using the following structure:

また、各年度の従業員の評価と業績に関する履歴データを格納し、この情報に年度別でアクセスできる必要もあります。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. それには、次の構造でエンティティを格納する別のテーブルを作成するという方法があります。One option is to create another table that stores entities with the following structure:

この方法では、単一の要求でデータを取得できるようにするには、一部の情報 (姓や名など) を新しいエンティティに複製する必要があります。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. ただし、EGT を使用しても 2 つのエンティティをアトミックには更新できないため、強力な整合性を保つことはできません。However, you cannot maintain strong consistency because you cannot use an EGT to update the two entities atomically.

解決策Solution

次の構造のエンティティを使用して、元のテーブルに新しい種類のエンティティを格納します。Store a new entity type in your original table using entities with the following structure:

RowKey が従業員 ID と評価データの年度から構成された複合キーとなり、1 つのエンティティに対する 1 つのリクエストで、従業員の業績と評価データを取得できるようになっていることにご注意ください。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.

次の例では、Sales 部署の従業員 000123 など、特定の従業員のすべての評価データを取得する方法を示しています。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')、(RowKey ge 'empid_000123')、(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

問題と注意事項Issues and considerations

このパターンの実装方法を決めるときには、以下の点に注意してください。Consider the following points when deciding how to implement this pattern:

  • 000123_2012 のような、RowKey 値の解析を容易にする適切な区切り文字を使用する必要があります。You should use a suitable separator character that makes it easy to parse the RowKey value: for example, 000123_2012.
  • また、このエンティティは、同じ従業員の関連データを含む他のエンティティと同じパーティションに格納します。そうすると、EGT を使用して、強い整合性を維持できます。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.
  • このパターンが適切であるかどうかを判断には、データを照会する頻度を考慮する必要があります。You should consider how frequently you will query the data to determine whether this pattern is appropriate. たとえば、評価データにはあまり頻度にアクセスせず、メインの従業員データには頻度にアクセスする場合は、それらのデータを別々のエンティティとして保持する必要があります。For example, if you will access the review data infrequently and the main employee data often you should keep them as separate entities.

このパターンを使用する状況When to use this pattern

頻繁に照会する関連エンティティを 1 つ以上格納する必要がある場合に、このパターンを使用します。Use this pattern when you need to store one or more related entities that you query frequently.

このパターンを実装する場合は、次のパターンとガイダンスも関連している可能性があります。The following patterns and guidance may also be relevant when implementing this pattern:

ログ テール パターンLog tail pattern

逆の日付と時間順でソートする RowKey 値を 使用して最も最近追加された n を取得します。Retrieve the n entities most recently added to a partition by using a RowKey value that sorts in reverse date and time order.

コンテキストと問題Context and problem

よく、最近作成されたエンティティ (従業員が提出した経費請求を日時の新しいものから 10 件など) を取得できることが必要な場合があります。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. Table クエリは $top クエリ操作をサポートして、最初の n 件のエンティティをセットから返します。セットの最終 n 件のエンティティを返す同等のクエリの操作はありません。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.

解決策Solution

自然に最新のエントリを逆の日付と時刻順で並べ替える RowKey を使用してエンティティの保存、するため、表の一番上に直近のエントリが表示されます。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.

たとえば、従業員が提出した経費請求を日時の新しいものから 10 件取得できるようにする場合は、現在の日時から派生した逆順のティック値を使用できます。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. 次の c# のコード サンプルは、最新から最古の順で並べ替える RowKey 用の適切な「逆タイマー刻み」値を作成する方法の 1 つを示しています。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);

次のコードを使用すると、日時値に戻すことができます。You can get back to the date time value using the following code:

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

テーブル クエリは次のようになります。The table query looks like this:

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

問題と注意事項Issues and considerations

このパターンの実装方法を決めるときには、以下の点に注意してください。Consider the following points when deciding how to implement this pattern:

  • 文字列値が正しく並び替わるように、逆順のティック値の先頭にゼロをパディングする必要があります。You must pad the reverse tick value with leading zeroes to ensure the string value sorts as expected.
  • パーティション レベルのスケーラビリティ ターゲットに注意する必要があります。You must be aware of the scalability targets at the level of a partition. ホット スポット パーティションが発生しないように注意してください。Be careful not create hot spot partitions.

このパターンを使用する状況When to use this pattern

日時の逆順でエンティティにアクセスする必要がある場合、または追加日時の新しい順にエンティティにアクセスする必要がある場合に、このパターンを使用します。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.

このパターンを実装する場合は、次のパターンとガイダンスも関連している可能性があります。The following patterns and guidance may also be relevant when implementing this pattern:

頻度の高いパターンを削除する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.

コンテキストと問題Context and problem

多くのアプリケーションでは、クライアント アプリケーションで使用する必要がなくなった古いデータや、他の記憶域メディアにアーカイブした古いデータを削除します。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. 通常は、日付でそうしたデータを特定します。たとえば、60 日以上前のすべてのログイン要求のレコードを削除する必要があるとします。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.

利用可能な設計の 1 つは、 RowKeyでのログイン リクエストの日付と時刻の使用です:One possible design is to use the date and time of the login request in the RowKey:

この方法では、アプリケーションが別のパーティションで各ユーザーのログイン エンティティを挿入したり削除したりできるため、パーティションのホット スポットを回避できます。This approach avoids partition hotspots because the application can insert and delete login entities for each user in a separate partition. ただし、まず削除するすべてのエンティティを特定するためにテーブル スキャンを実行し、その後、古い各エンティティを削除する必要があるため、エンティティの数が多い場合、この方法ではコストと時間がかかる可能性があります。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. 複数の削除要求をバッチ処理として 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.

解決策Solution

ログイン試行の日付ごとに異なるテーブルを使用します。Use a separate table for each day of login attempts. 上のエンティティのデザインを使用すると、エンティティを挿入する際にホットスポットを回避できます。毎日数百や数千もの個々のログイン エンティティを検索して削除する代わりに、毎日テーブルを 1 つ削除する (単一のストレージ操作) だけで古いエンティティを削除できます。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.

問題と注意事項Issues and considerations

このパターンの実装方法を決めるときには、以下の点に注意してください。Consider the following points when deciding how to implement this pattern:

  • 特定のエンティティの検索、他のデータとのリンク、集計情報の生成など、データの他の用途もサポートするように設計していますか。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?
  • 新しいエンティティを挿入する際にホットスポットを回避するように設計していますか。Does your design avoid hot spots when you are inserting new entities?
  • テーブル名を削除した後に同じテーブル名を再利用する場合に遅延が必要であります。Expect a delay if you want to reuse the same table name after deleting it. 常に一意のテーブル名を使用することをお勧めします。It's better to always use unique table names.
  • Table service ではアクセス パターンを学習して、ノード全体にパーティションを分散しますが、最初に新しいテーブルを使用するときは何らかの調整が行われます。Expect some throttling when you first use a new table while the Table service learns the access patterns and distributes the partitions across nodes. 新しいテーブルを作成する必要がある頻度を検討する必要があります。You should consider how frequently you need to create new tables.

このパターンを使用する状況When to use this pattern

同時に削除する必要があるエンティティが大量にある場合に、このパターンを使用します。Use this pattern when you have a high volume of entities that you must delete at the same time.

このパターンを実装する場合は、次のパターンとガイダンスも関連している可能性があります。The following patterns and guidance may also be relevant when implementing this pattern:

データ系列のパターンData series pattern

データ系列全体を単一のエンティティに格納し、要求の数を最小限に抑えます。Store complete data series in a single entity to minimize the number of requests you make.

コンテキストと問題Context and problem

一般的なシナリオとして、通常、アプリケーションで一度にすべて取得する必要があるデータ系列を格納するというものがあります。A common scenario is for an application to store a series of data that it typically needs to retrieve all at once. たとえば、アプリケーションで 1 時間ごとに各従業員が送信した IM メッセージの数を記録し、後でその情報を使用して、各ユーザーが過去 24 時間以内に送信したメッセージの数をプロットするとします。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. 設計の 1 つとして、従業員ごとに 24 個のエンティティを格納します。One design might be to store 24 entities for each employee:

この設計では、アプリケーションでメッセージのカウント値を更新する必要があるときに、各従業員の更新するエンティティを簡単に検索して更新できます。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. ただし、情報を取得して、過去 24 時間の活動のグラフをプロットするためには、24 個のエンティティを取得する必要があります。However, to retrieve the information to plot a chart of the activity for the preceding 24 hours, you must retrieve 24 entities.

解決策Solution

次のデザインを使用し、各時間のメッセージ数をそれぞれ別のプロパティに格納します。Use the following design with a separate property to store the message count for each hour:

この設計では、マージ操作を使用して、特定の時間の従業員のメッセージ数を更新できます。With this design, you can use a merge operation to update the message count for an employee for a specific hour. これで、単一のエンティティに対する単一の要求を使用して、チャートをプロットするために必要なすべての情報を取得できます。Now, you can retrieve all the information you need to plot the chart using a request for a single entity.

問題と注意事項Issues and considerations

このパターンの実装方法を決めるときには、以下の点に注意してください。Consider the following points when deciding how to implement this pattern:

  • データ系列全体が単一のエンティティに収まらない場合 (エンティティは最大 252 個のプロパティを持つことができます)、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.
  • 複数のクライアントが同時にエンティティを更新する場合は、 ETag を使用して、オプティミスティック同時実行を実装する必要があります。If you have multiple clients updating an entity simultaneously, you will need to use the ETag to implement optimistic concurrency. クライアントがたくさんある場合は、競合が大量に発生する可能性があります。If you have many clients, you may experience high contention.

このパターンを使用する状況When to use this pattern

個々のエンティティに関連付けられているデータ系列を更新したり取得したりする必要がある場合に、このパターンを使用します。Use this pattern when you need to update and retrieve a data series associated with an individual entity.

このパターンを実装する場合は、次のパターンとガイダンスも関連している可能性があります。The following patterns and guidance may also be relevant when implementing this pattern:

ワイド エンティティ パターンWide entities pattern

複数の物理エンティティを使用して、252 を超えるプロパティを持つ論理エンティティを格納します。Use multiple physical entities to store logical entities with more than 252 properties.

コンテキストと問題Context and problem

個々のエンティティが持つことができるプロパティは、(必須のシステム プロパティを除き) 252 個までです。また、格納できるデータは合計で 1 MB までです。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. リレーショナル データベースでは、通常、新しいテーブルを追加し、その新しいテーブルと 1 対 1 のリレーションシップを作成することによって、行のサイズに関するさまざまな制限を回避します。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.

解決策Solution

Table service を使用すると、複数のエンティティを格納して、252 を超えるプロパティを持つ単一の大きなビジネス オブジェクトを作成できます。Using the Table service, you can store multiple entities to represent a single large business object with more than 252 properties. たとえば、過去 365 日の間に各従業員が送信した IM メッセージの数を格納する場合は、スキーマの異なる 2 つのエンティティを使用する次のデザインを使用できます。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:

両方のエンティティを更新しないとエンティティどうしの同期が維持されない変更を加える必要がある場合は、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. それ以外の場合は、単一のマージ操作を使用して、特定の日のメッセージ数を更新できます。Otherwise, you can use a single merge operation to update the message count for a specific day. 個々 の従業員のすべてのデータを取得するには、PartitionKeyRowKey 値の両方を使用する 2 つの効率的なリクエストを取得する必要があります。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.

問題と注意事項Issues and considerations

このパターンの実装方法を決めるときには、以下の点に注意してください。Consider the following points when deciding how to implement this pattern:

  • 論理エンティティ全体を取得するには、少なくとも 2 つのストレージ トランザクション (各物理エンティティを取得するトランザクション) が必要です。Retrieving a complete logical entity involves at least two storage transactions: one to retrieve each physical entity.

このパターンを使用する状況When to use this pattern

サイズやプロパティの数が Table service の個々のエンティティの制限を超えるエンティティを格納する必要がある場合に、このパターンを使用します。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.

このパターンを実装する場合は、次のパターンとガイダンスも関連している可能性があります。The following patterns and guidance may also be relevant when implementing this pattern:

大型エンティティ パターンLarge entities pattern

BLOB ストレージを使用して、大きなプロパティ値を格納します。Use blob storage to store large property values.

コンテキストと問題Context and problem

個々のエンティティに格納できるデータは合計で 1 MB までです。An individual entity cannot store more than 1 MB of data in total. 1 つまたは複数のプロパティに格納される値でエンティティの合計サイズが 1 MB を超える場合は、Table service にエンティティ全体は格納できません。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.

解決策Solution

1 つ以上のプロパティに大量のデータが含まれているためにエンティティのサイズが 1 MB を超える場合は、Blob service にデータを格納し、エンティティのプロパティに BLOB のアドレスを格納できます。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. たとえば、従業員の写真を Blob ストレージに格納し、写真へのリンクを従業員エンティティの フォト プロパティに格納できます。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:

問題と注意事項Issues and considerations

このパターンの実装方法を決めるときには、以下の点に注意してください。Consider the following points when deciding how to implement this pattern:

  • Table service 内のエンティティと、Blob service 内のデータの間の最終的な一貫性を保つには、最終的に一貫性のあるトランザクション パターン を使用してエンティティを維持します。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.
  • エンティティ全体を取得するには、少なくとも 2 つのストレージ トランザクション (エンティティを取得するトランザクションと BLOB データを取得するトランザクション) が必要です。Retrieving a complete entity involves at least two storage transactions: one to retrieve the entity and one to retrieve the blob data.

このパターンを使用する状況When to use this pattern

サイズが Table service の個々のエンティティの制限を超えるエンティティを格納する必要がある場合に、このパターンを使用します。Use this pattern when you need to store entities whose size exceeds the limits for an individual entity in the Table service.

このパターンを実装する場合は、次のパターンとガイダンスも関連している可能性があります。The following patterns and guidance may also be relevant when implementing this pattern:

先頭または末尾に追加するアンチパターンPrepend/append anti-pattern

大量に挿入する場合に、挿入を複数のパーティションに分散させることで、スケーラビリティを向上させます。Increase scalability when you have a high volume of inserts by spreading the inserts across multiple partitions.

コンテキストと問題Context and problem

格納されているエンティティの先頭または末尾にエンティティを追加すると、通常は、連続するパーティションの最初または最後のパーティションに新しいエンティティが追加されます。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. この場合、常に挿入はすべて同じパーティション内で行われるため、ホットスポットが発生し、Table サービスが複数のノードに挿入の負荷を分散できず、場合によっては、パーティションのスケーラビリティ ターゲットに達する可能性があります。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. たとえば、従業員によるネットワークやリソースへのアクセスをログに記録するアプリケーションで、以下に示すエンティティ構造を使用した場合、トランザクションの量が個々のパーティションのスケーラビリティ ターゲットに達すると、現在処理が行われているパーティションがホットスポットになる可能性があります。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:

解決策Solution

代わりに次のエンティティ構造を使用すると、アプリケーションでイベントをログに記録する際に特定のパーティションのホットスポットを回避できます。The following alternative entity structure avoids a hotspot on any particular partition as the application logs events:

次の例では 2 つのキー PartitionKeyRowKey がどのように複合キーになっているか注意してください。Notice with this example how both the PartitionKey and RowKey are compound keys. PartitionKey は部署と従業員の両方の ID を使用して複数のパーティションにログを配布します。The PartitionKey uses both the department and employee id to distribute the logging across multiple partitions.

問題と注意事項Issues and considerations

このパターンの実装方法を決めるときには、以下の点に注意してください。Consider the following points when deciding how to implement this pattern:

  • 挿入時のホット パーティションの発生を回避する代わりのキー構造でクライアント アプリケーションが実行するクエリを効率的にサポートしていますか。Does the alternative key structure that avoids creating hot partitions on inserts efficiently support the queries your client application makes?
  • 予想されるトランザクションの量から判断して、個々のパーティションのスケーラビリティ ターゲットに達し、ストレージ サービスによって調整される可能性がありますか。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?

このパターンを使用する状況When to use this pattern

トランザクションの量により、ホット パーティションにアクセスするとストレージ サービスによって調整される可能性がある場合は、先頭または末尾に追加するアンチパターンを使用しないでください。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.

このパターンを実装する場合は、次のパターンとガイダンスも関連している可能性があります。The following patterns and guidance may also be relevant when implementing this pattern:

ログ データのアンチパターンLog data anti-pattern

ログ データの格納には通常、Table service ではなく Blob service を使用します。Typically, you should use the Blob service instead of the Table service to store log data.

コンテキストと問題Context and problem

ログ データを使用する局面として最も一般的なのが、特定の日付範囲または時間範囲のログ エントリを選択して取得するというものです。たとえば、特定の日の 15:04 から 15:06 までの間にアプリケーションが記録したエラー メッセージや重要なメッセージをすべて取得するなどの局面が挙げられます。A 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. ログ メッセージの日時を使用して、ログのエンティティを保存するパーティションを特定したくない場合は、ホット パーティションになります。任意の時点で、すべてのログ エンティティが同じ PartitionKey 値を共有します (先頭または末尾に追加するアンチ パターンのセクションをご覧ください)。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). たとえば、ログ メッセージに関する以下のエンティティ スキーマでは、アプリケーションが現在の日付や時刻についてパーティションにあらゆるログ メッセージを書き込むことになるため、ホット パーティションの問題が発生します。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:

この例では、 RowKey にはログ メッセージが日時順で格納されていることを確認するため、ログメッセージの日時が含まれており、複数のメッセージが同じ日時を共有する複数のログ メッセージの場合にはメッセージ ID も含まれています。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.

別の方法は、アプリケーションに確実に パーティション範囲にわたってメッセージを書き込ませる PartitionKey の使用です。Another approach is to use a PartitionKey that ensures that the application writes messages across a range of partitions. たとえば、ログ メッセージのソースで多数のパーティションにメッセージを配信できるようになっている場合には、以下のエンティティ スキーマを使用できます。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:

ただし、このスキーマには問題があります。特定のタイム スパンに記録されたログ メッセージをすべて取得するときには、テーブル内のパーティションを逐一検索する必要があるからです。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.

解決策Solution

前のセクションでは、ログ エントリの保存先として Table service を使用した場合に生じる問題について説明し、その解決策として、完璧とは言いがたいものの 2 つの設計を紹介しました。The previous section highlighted the problem of trying to use the Table service to store log entries and suggested two, unsatisfactory, designs. 1 つ目に紹介した方法には、ホット パーティションが発生し、ログ メッセージの書き込みのパフォーマンスが低下するリスクがあります。これに対して 2 つ目の方法は、特定のタイム スパンについてログ メッセージを取得しようとした場合に、テーブル内のパーティションを逐一スキャンしなければならないため、クエリのパフォーマンスが低下するという問題がありました。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. BLOB ストレージなら、ここで取り上げたシナリオについて前の 2 つよりも優れたソリューションとなることができます。このため、Azure Storage Analytics が収集したログ データを保存するときにも、この BLOB ストレージが使用されています。Blob storage offers a better solution for this type of scenario and this is how Azure Storage Analytics stores the log data it collects.

このセクションでは、Storage Analytics が BLOB ストレージにログ データを格納する流れの概要を説明し、範囲を指定してクエリを実行することが多いデータを保存する際にこのアプローチがどのように役立つかを見ていきます。This section outlines how Storage Analytics stores log data in blob storage as an illustration of this approach to storing data that you typically query by range.

Storage Analytics では、ログ メッセージを一定の形式で区切ったものを、複数の BLOB に格納します。Storage Analytics stores log messages in a delimited format in multiple blobs. 区切りに使用する形式は、クライアント アプリケーション側でログ メッセージのデータ解析を円滑に完了できるものになっています。The delimited format makes it easy for a client application to parse the data in the log message.

Storage Analytics が BLOB に対して使用している名前付け規則は、検索対象のログ メッセージが含まれる BLOB の場所を特定できるようなものになっています。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. たとえば、"queue/2014/07/31/1800/000001.log" という名前の BLOB であれば、2014 年 7 月 31 日の 18:00 から始まる時間の Queue サービスと関係があるログ メッセージが格納されています。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" という部分は、この期間の最初のログ ファイルであることを示しています。The "000001" indicates that this is the first log file for this period. このほか、Storage Analytics では 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. BLOB ストレージの API では、一定の名前プレフィックスに基づいてコンテナー内の BLOB の場所を特定できるようになっています。18:00 から始まる時間についてキューのログ データを格納している BLOB をすべて検索する場合には、"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."

Storage Analytics は内部のバッファーにログ メッセージを保管したうえで、ログ エントリのバッチの最新版を使って定期的に BLOB を更新したり、新しい BLOB を作成したりします。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. これによって、BLOB サービスに書き込みを実行する回数が少なくなります。This reduces the number of writes it must perform to the blob service.

アプリケーションにこれと似たソリューションを実装するときには、信頼性 (ログ エントリが発生するたびに BLOB ストレージに書き込む) と、コストとスケーラビリティ (アプリケーションに更新内容を一時的に保管し、バッチとして BLOB ストレージに書き込む) との間のトレードオフをどのようにするかについて、検討が必要になります。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).

問題と注意事項Issues and considerations

ログ データの保存方法を決めるときには、以下の点に注意する必要があります。Consider the following points when deciding how to store log data:

  • ホット パーティションが発生しないような設計のテーブルを作成すると、ログ データに対するアクセス効率が低下することがあります。If you create a table design that avoids potential hot partitions, you may find that you cannot access your log data efficiently.
  • ログ データを処理するときには多くの場合、クライアント側で多くのレコードを読み込む必要があります。To process log data, a client often needs to load many records.
  • ログ データは構造化されていないことが多いものの、BLOB ストレージの方が優れたソリューションになることがあります。Although log data is often structured, blob storage may be a better solution.

実装時の注意事項Implementation considerations

このセクションでは、ここまでのセクションで説明したパターンを実装する際に念頭に置く必要がある点をいくつか説明します。This section discusses some of the considerations to bear in mind when you implement the patterns described in the previous sections. このセクションで示したコード例は、ほとんどが C# で書かれ、ストレージ クライアント ライブラリ (本稿執筆時点のバージョンは 4.3.0) を使用しています。Most of this section uses examples written in C# that use the Storage Client Library (version 4.3.0 at the time of writing).

エンティティの取得Retrieving entities

クエリに対応した設計」で説明したように、最も効率的なクエリはポイント クエリです。As discussed in the section Design for querying, the most efficient query is a point query. ただ、時として多数のエンティティを同時に取得することも必要になります。However, in some scenarios you may need to retrieve multiple entities. このセクションでは、ストレージ クライアント ライブラリを使ってエンティティを取得するときによく使用される方法をいくつか紹介します。This section describes some common approaches to retrieving entities using the Storage Client Library.

ストレージ クライアント ライブラリを使ってポイント クエリを実行するExecuting a point query using the Storage Client Library

ポイント クエリを実行する最も簡単な方法は、次の c# コード スニペットに表示された、PartitionKey 値 "Sales" と RowKey 値 "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;
    ...
}  

この例では、 従業員エンティティ型のエンティティを取得することをどのように予想しているか注意してください。Notice how this example expects the entity it retrieves to be of type EmployeeEntity.

LINQ を使用して複数のエンティティを取得します。Retrieving multiple entities using LINQ

複数のエンティティを取得するには、て、ストレージ クライアント ライブラリとともにLINQ を使用し、 where 句のあるクエリを指定します。You can retrieve multiple entities by using LINQ with Storage Client Library and specifying a query with a where clause. テーブル スキャンを回避するのには、where 句の PartitionKey 値と、可能であれば RowKey 値をインクルードし、テーブルとパーティションのスキャンを避けます。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. Table サービスは、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. 次の c# のコード スニペットは、Sales 部署 (PartitionKey が部署名を格納していると仮定) の中で、姓が "B" (RowKey が姓を格納していると仮定) で始まるすべての従業員を検索 します。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();  

パフォーマンスを確保するため、クエリで RowKeyPartitionKey の両方をどのように指定するか注意してください。Notice how the query specifies both a RowKey and a PartitionKey to ensure better performance.

次のコード サンプルは、Fluent API を使用したのと同等の機能を示しています (一般的な Fluent API の詳細について、 Fluent API を設計するためのベスト プラクティスを参照してください)。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);  

注意

このサンプルでは、 3 つのフィルター条件を含んだ複数の コンバイン フィルター メソッドをネストしています。The sample nests multiple CombineFilters methods to include the three filter conditions.

1 件のクエリで大量のエンティティを取得するRetrieving large numbers of entities from a query

最適なクエリは PartitionKey 値と RowKey 値に基づいて個別のエンティティを返します。An optimal query returns an individual entity based on a PartitionKey value and a RowKey value. ところが、場合によっては同じパーティション、ときには多数のパーティションから、多数のエンティティを返すことが必要になります。However, in some scenarios you may have a requirement to return many entities from the same partition or even from many partitions.

そのようなときには必ず、アプリケーションのパフォーマンスを綿密にテストする必要があります。You should always fully test the performance of your application in such scenarios.

Table サービスに対してクエリを実行した場合、一度に返されるエンティティの数は最大 1,000 件、クエリの実行時間は最大 5 秒間です。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. 結果として返されるエンティティが 1,000 件を超える場合、クエリが 5 秒以内に完了しなかった場合、またはクエリがパーティションの境界をまたいで実行される場合には、Table service によって継続トークンが返されます。クライアント アプリケーションはこのトークンを使って、続きとなるエンティティを要求します。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. 継続トークンの詳細については、「クエリのタイムアウトと改ページ」をご覧ください。For more information about how continuation tokens work, see Query Timeout and Pagination.

ストレージ クライアント ライブラリを使用している場合には、Table service からエンティティが返されるたびに継続トークンが自動で処理されます。If you are using the Storage Client Library, it can automatically handle continuation tokens for you as it returns entities from the Table service. 以下の C# コード サンプルではストレージ クライアント ライブラリを使用しているため、Table サービスが応答で返した継続トークンが自動的に処理されます。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)
{
        ...
}  

以下の C# コード サンプルでは、継続トークンの処理を明示的に記述しています。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);  

継続トークンを明示的に使用すると、アプリケーションが次のセグメントに相当するデータを取得するタイミングを制御ができます。By using continuation tokens explicitly, you can control when your application retrieves the next segment of data. たとえば、テーブルに格納されたエンティティをクライアント アプリケーションでページとして表示できるようにしている場合に、クエリで取得したエンティティをユーザーが最後まで見ないことがあります。そのようなとき、継続トークンを明示的に使用していれば、ユーザーが現在のセグメントのエンティティの最後のページに達した時点で、アプリケーションが継続トークンだけを使って次のセグメントを取得できます。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. この方法には、いくつかの利点があります。This approach has several benefits:

  • Table service から取得するデータの量を制限したり、ユーザーがネットワークを移動したりできるようになります。It enables you to limit the amount of data to retrieve from the Table service and that you move over the network.
  • .NET の非同期 IO を実行できるようになります。It enables you to perform asynchronous IO in .NET.
  • 継続トークンをシリアル化して永続記憶装置に保存できるため、アプリケーションがクラッシュした場合でも処理を継続できるようになります。It enables you to serialize the continuation token to persistent storage so you can continue in the event of an application crash.

注意

継続トークンは通常、エンティティ 1,000 件を 1 つのセグメントにして返しますが、この数が少なくなることもあります。A continuation token typically returns a segment containing 1,000 entities, although it may be fewer. これも、取得を使用してクエリが返すをエントリの数を制限する場合は、検索条件に一致する最初の n 件のエンティティを返します。テーブル サービスは、残りのエンティティを取得するため、継続トークンと合わせて n 件より少ないエンティティを含むセグメントを返す可能性があります。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.

以下の C# コードは、1 つのセグメントで返されるエンティティの数を変更するためのものです。The following C# code shows how to modify the number of entities returned inside a segment:

employeeQuery.TakeCount = 50;  

サーバー側のプロジェクションServer-side projection

1 つのエンティティには最大で 255 個のプロパティを格納でき、エンティティの最大サイズは 1 MB です。A single entity can have up to 255 properties and be up to 1 MB in size. テーブルに対してクエリを実行してエンティティを取得する際、すべてのプロパティが必要ない場合は、データの不要な転送を避けることができます (遅延とコストの削減につながります)。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). サーバー側のプロジェクションを使えば、必要なプロパティのみを転送できます。You can use server-side projection to transfer just the properties you need. 次の例は、クエリによって選択されたエンティティから電子メール プロパティ (PartitionKeyRowKeyタイムスタンプETag と連動) を取得しています。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);
}  

RowKey 値は取得するプロパティのリストに含まれていなくてもどのように有効であることか注意してください。Notice how the RowKey value is available even though it was not included in the list of properties to retrieve.

エンティティの変更Modifying entities

ストレージ クライアント ライブラリを使えば、Table サービスに格納されたエンティティを、挿入、削除、更新の各操作によって変更できます。The Storage Client Library enables you to modify your entities stored in the table service by inserting, deleting, and updating entities. また、EGT を使えば複数の挿入、更新、削除の操作を一括で行えるため、必要なラウンドトリップの回数が減り、ソリューションのパフォーマンスが高まります。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.

ストレージ クライアント ライブラリが EGT を実行したときにスローされる例外には、通常、一括処理の失敗を招いたエンティティのインデックスが含まれます。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. これは EGT を使うコードをデバッグする際に役立ちます。This is helpful when you are debugging code that uses EGTs.

クライアント アプリケーションでの同時実行と更新操作の処理方法に設計が及ぼす影響についても考慮が必要です。You should also consider how your design affects how your client application handles concurrency and update operations.

同時実行を管理するManaging concurrency

既定では、テーブル サービスは個々 のエンティティのレベルで挿入マージ削除操作に対しオプティミスティック同時実行チェックを実行しますが、クライアントは、テーブル サービスがこれらのチェックをバイパスするよう強制することもできます。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. Table service での同時実行の管理方法については、「Microsoft Azure Storage での同時実行制御の管理」をご覧ください。For more information about how the table service manages concurrency, see Managing Concurrency in Microsoft Azure Storage.

マージまたは置換Merge or replace

TableOperation クラスの置換のメソッドは、常に、Table service の完全なエンティティを置換します。The Replace method of the TableOperation class always replaces the complete entity in the Table service. 格納されたエンティティに存在するプロパティを要求に含めない場合、要求により、格納されたエンティティからそのプロパティが削除されます。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. 格納されたエンティティからプロパティを明示的に削除しない場合は、すべてのプロパティを要求に含める必要があります。Unless you want to remove a property explicitly from a stored entity, you must include every property in the request.

TableOperation クラスのマージ メソッドを使用して エンティティを更新するときの Table service に送信するデータの量を削減します。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. マージ メソッドはプロパティ値を持った格納エンティティのプロパティをリクエストに含まれるエンティティと置換しますが、リクエストに含まれない格納エンティティ内の無傷のプロパティはそのまま残します。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. ラージ エンティティがあり、要求で少数のプロパティのみを更新する必要があるときに便利な処理です。This is useful if you have large entities and only need to update a small number of properties in a request.

注意

エンティティが存在しない場合、置換マージ メソッドが失敗します。The Replace and Merge methods fail if the entity does not exist. 存在しない場合は、代わりに、InsertOrReplaceInsertOrMerge メソッドを使用して新しいエンティティを作成します。As an alternative, you can use the InsertOrReplace and InsertOrMerge methods that create a new entity if it doesn't exist.

異種のエンティティ種類の使用Working with heterogeneous entity types

Table service とは、スキーマのない テーブル ストアを 1 つのテーブルが非常に柔軟にデザインを提供する複数の種類のエンティティを格納できることを意味します。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. 次の例は、従業員エンティティと部署エンティティの両方を格納したテーブルを示しています。The following example illustrates a table storing both employee and department entities:

パーティション キーPartitionKey 行キーRowKey TimestampTimestamp
FirstNameFirstName LastNameLastName AgeAge 電子メールEmail
FirstNameFirstName LastNameLastName AgeAge 電子メールEmail
DepartmentNameDepartmentName EmployeeCountEmployeeCount
FirstNameFirstName LastNameLastName AgeAge 電子メールEmail

各エンティティはなお、PartitionKeyRowKeyタイムスタンプ値を持つ必要がありますが、プロパティセットを持つ場合もあります。Note that each entity must still have PartitionKey, RowKey, and Timestamp values, but may have any set of properties. さらに、エンティティの種類を示すものがありません (エンティティの種類に関する情報を格納していない場合)。Furthermore, there is nothing to indicate the type of an entity unless you choose to store that information somewhere. エンティティの種類を識別する方法は 2 とおりあります。There are two options for identifying the entity type:

  • RowKey (または PartitionKey) にエンティティ型を追加。Prepend the entity type to the RowKey (or possibly the PartitionKey). 例えば、RowKey 値としてのEMPLOYEE_000123 または DEPARTMENT_SALESFor example, EMPLOYEE_000123 or DEPARTMENT_SALES as RowKey values.
  • 以下の表に示すように、個別のプロパティを使用してエンティティの種類を記録します。Use a separate property to record the entity type as shown in the table below.
パーティション キーPartitionKey 行キーRowKey TimestampTimestamp
EntityTypeEntityType FirstNameFirstName LastNameLastName AgeAge 電子メールEmail
EmployeeEmployee
EntityTypeEntityType FirstNameFirstName LastNameLastName AgeAge 電子メールEmail
EmployeeEmployee
EntityTypeEntityType DepartmentNameDepartmentName EmployeeCountEmployeeCount
部署Department
EntityTypeEntityType FirstNameFirstName LastNameLastName AgeAge 電子メールEmail
EmployeeEmployee

最初のオプションでは、エンティティ型を RowKeyの先頭に着けると、異なる種類の 2 つのエンティティが同じキー値にある可能性がある場合に便利です。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. この方法なら、パーティションに同じ種類のエンティティのグループ化もできます。It also groups entities of the same type together in the partition.

このセクションで説明した手法は特に、本ガイドに前述のリレーションシップのモデリング セクション内の継承リレーションシップで説明した内容と関連がありま す。The techniques discussed in this section are especially relevant to the discussion Inheritance relationships earlier in this guide in the section Modelling relationships.

注意

エンティティの種類の値にバージョン番号を追加して、クライアント アプリケーションで POCO オブジェクトを発展させ、さまざまなバージョンを操作できるようにすることを検討してください。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.

このセクションの残りの部分では、同じテーブル内の異なる種類のエンティティを操作しやすくするストレージ クライアント ライブラリの機能について説明します。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.

異なる種類のエンティティを取得するRetrieving heterogeneous entity types

ストレージ クライアント ライブラリを使えば、3 とおりの方法で複数の種類のエンティティを操作できます。If you are using the Storage Client Library, you have three options for working with multiple entity types.

特定の RowKey および PartitionKey 値とともに格納されているエンティティの型がわかっている場合は、EmployeeEntity 型のエンティティを取得する前述の 2 つの例 (「ストレージ クライアント ライブラリを使ってポイント クエリを実行する」および「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.

2 番目のオプションは、具体的な POCO エンティティ型の代わりに DynamicTableEntity 型 (プロパティ バッグ) の使用です(エンティティを .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). 次の c# コードは、テーブルから潜在的にさまざまな種類の複数のエンティティを取得しますが、すべてのエンティティを DynamicTableEntity インスタンスとして返します。The following C# code potentially retrieves multiple entities of different types from the table, but returns all entities as DynamicTableEntity instances. EntityType プロパティを使用して各エンティティの種類を決定します。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
        }
    }
}  

その他のプロパティを取得するには、DynamicTableEntity クラスのプロパティのプロパティにある TryGetValue メソッドを使用する必要があるので注意してください。Note that to retrieve other properties you must use the TryGetValue method on the Properties property of the DynamicTableEntity class.

3 番目のオプションは、DynamicTableEntity 型と EntityResolver インスタンスの組み合わせの使用です。A third option is to combine using the DynamicTableEntity type and an EntityResolver instance. この方法なら、同じクエリで複数の POCO 型を解決できます。This enables you to resolve to multiple POCO types in the same query. この例では、EntityResolver デリゲートは EntityType プロパティを使用して、クエリによって返されるエンティティの 2 つの種類を区別します。In this example, the EntityResolver delegate is using the EntityType property to distinguish between the two types of entity that the query returns. Resolve メソッドは、resolver デリゲートを使用して DynamicTableEntity インスタンスを 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)
        {
    ...
        }
}  

異なる種類のエンティティを変更するModifying heterogeneous entity types

エンティティの種類がわからなくても削除はできますが、挿入はできません。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. ですが、種類がわからなくても、POCO エンティティ クラスを使用せず、 DynamicTableEntity 型を使用して エンティティを更新します。However, you can use DynamicTableEntity type to update an entity without knowing its type and without using a POCO entity class. 次のコード サンプルでは、1 つのエンティティを取得し、 EmployeeCount プロパティが存在するか、更新前に確認しています。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));  

共有アクセス署名でのアクセスを制御するControlling access with Shared Access Signatures

Shared Access Signature (SAS) トークンを使うと、クライアント アプリケーションで、Table サービスに対して直接認証しなくてもテーブル エンティティを直接変更 (と照会) できるようになります。You can use Shared Access Signature (SAS) tokens to enable client applications to modify (and query) table entities directly without the need to authenticate directly with the table service. 通常、アプリケーションで SAS を使うと、次の 3 つのメリットが得られます。Typically, there are three main benefits to using SAS in your application:

  • デバイスで Table service のエンティティにアクセスして変更できるようにするために、安全ではないプラットフォーム (モバイル デバイスなど) にストレージ アカウント キーを配布する必要がない。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.
  • Web ロールまたは worker ロールがエンティティを管理する際に実行する処理の一部を、エンド ユーザー コンピューターやモバイル デバイスなどのクライアント デバイスにオフロードできる。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.
  • 制約と時間制限のあるアクセス許可のセットをクライアントに割り当てることができる (読み取り専用アクセスを特定のリソースに許可するなど)。You can assign a constrained and time limited set of permissions to a client (such as allowing read-only access to specific resources).

Table service での SAS トークンの使用について詳しくは、「 Shared Access Signatures (SAS) の使用」をご覧ください。For more information about using SAS tokens with the Table service, see Using Shared Access Signatures (SAS).

ただし、Table サービスのエンティティへのアクセスをクライアント アプリケーションに付与する SAS トークンを生成する必要はあります。これは、ストレージ アカウント キーに安全にアクセスできる環境で行うようにしてください。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. 通常は、Web ロールまたは worker ロールを使って SAS トークンを生成し、エンティティへのアクセスを必要とするクライアント アプリケーションに配布します。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. SAS トークンの生成とクライアントへの配布にもやはりオーバーヘッドが伴うため、特に大量に扱うシナリオでは、このオーバーヘッドを減らす最適な方法を検討する必要があります。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.

テーブル内のエンティティのサブセットへのアクセスを付与する SAS トークンを生成できます。It is possible to generate a SAS token that grants access to a subset of the entities in a table. 既定では、テーブル全体に対し SAS トークンを作成しますが、SAS トークンへのアクセス許可を PartitionKey 値の範囲か、PartitionKeyRowKey 値の範囲のいずれかに指定することも可能です。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. システムの個々のユーザーに SAS トークンが生成されるようにすれば、各ユーザーの SAS トークンによってアクセスが許可されるのは、Table サービス内にあるユーザー独自のエンティティだけになります。You might choose to generate SAS tokens for individual users of your system such that each user's SAS token only allows them access to their own entities in the table service.

非同期と並列操作Asynchronous and parallel operations

要求を複数のパーティションに分散させている場合は、非同期または並列クエリを使ってスループットとクライアントの応答性を向上させることができます。Provided you are spreading your requests across multiple partitions, you can improve throughput and client responsiveness by using asynchronous or parallel queries. たとえば、テーブルに並列的にアクセスする複数の worker ロール インスタンスを使用する場合などです。For example, you might have two or more worker role instances accessing your tables in parallel. 個別の worker ロールで特定のパーティション セットのみを処理することも可能であるほか、テーブル内のすべてのパーティションにアクセスできる worker ロール インスタンスを複数実装することも可能です。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.

クライアント インスタンスでは、ストレージ操作を非同期的に実行することでスループットを高めることができます。Within a client instance, you can improve throughput by executing storage operations asynchronously. ストレージ クライアント ライブラリを使えば、非同期クエリと変更を簡単に記述できます。The Storage Client Library makes it easy to write asynchronous queries and modifications. たとえば、次の C# コードに示すように、パーティション内のすべてのエントリを取得する同期メソッドをベースとして利用できます。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);
}  

このコードを次のように少し変更して、クエリが非同期的に実行されるようにします。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 this asynchronous example, you can see the following changes from the synchronous version:

  • メソッドのシグネチャは async 修飾子を含み、Task インスタンスを返します。The method signature now includes the async modifier and returns a Task instance.
  • ExecuteSegmented メソッドを呼び出して結果を取得する代わりに、ExecuteSegmentedAsync メソッドを呼び出し、await 修飾子を使用して非同期的に結果を取得します。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.

クライアント アプリケーションが複数回このメソッドを呼び出し ( 部署 パラメーターの異なる値のため)、各クエリは個別のスレッドで実行されます。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.

IEnumerable インターフェイスは非同期列挙型をサポートしていないため、TableQuery クラスのExecute メソッドには非同期バージョンがないのでご注意ください。Note that there is no asynchronous version of the Execute method in the TableQuery class because the IEnumerable interface does not support asynchronous enumeration.

エンティティを非同期的に挿入、更新、削除できます。You can also insert, update, and delete entities asynchronously. 次の C# の例は、従業員エンティティを挿入または置換する単純な同期メソッドです。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);
}  

このコードを次のように少し変更して、更新が非同期的に実行されるようにすることができます。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 this asynchronous example, you can see the following changes from the synchronous version:

  • メソッドのシグネチャは async 修飾子を含み、Task インスタンスを返します。The method signature now includes the async modifier and returns a Task instance.
  • Execute メソッドを呼び出してエンティティを更新する代わりに、ExecuteAsync メソッドを呼び出し、await 修飾子を使用して非同期的に結果を取得します。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.

クライアント アプリケーションは、これと同じように非同期メソッドを複数回呼び出すことができます。各メソッドの呼び出しは別々のスレッドで実行されます。The client application can call multiple asynchronous methods like this one, and each method invocation will run on a separate thread.

謝辞Credits

Azure チームの功績の次のメンバーに感謝いたします。Dominic Betts、Jason Hogg、Jean Ghanem、Jai Haridas、Jeff Irwin、Vamshidhar Kommineni、Vinay Shah、Serdar Ozler、Microsoft DX の Tom Hollander。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.

以下の Microsoft MVP にもレビュー時に彼らの貴重なフィードバックを頂きました。感謝いたします: Igor Papirov と Edward BakkerWe would also like to thank the following Microsoft MVP's for their valuable feedback during review cycles: Igor Papirov and Edward Bakker.