Table Storage のパフォーマンスとスケーラビリティのチェックリスト

Microsoft は、Table Storage を使用して高パフォーマンス アプリケーションを開発するための多数の実証済みプラクティスを開発してきました。 このチェックリストでは、パフォーマンスを最適化するために開発者が従うことのできる主要なプラクティスを示します。 アプリケーションを設計している間、およびプロセス全体を通して、これらのプラクティスに留意してください。

Azure Storage には、容量、トランザクション レート、および帯域幅についてスケーラビリティとパフォーマンスのターゲットがあります。 Azure Storage のスケーラビリティ ターゲットの詳細については、「Standard Storage アカウントのスケーラビリティとパフォーマンスのターゲット」および「Table Storage のスケーラビリティおよびパフォーマンスのターゲット」を参照してください。

チェック リスト

この記事では、パフォーマンスに関する実証済みプラクティスを、Table Storage アプリケーションの開発中に従うことのできるチェックリストにまとめています。

完了 カテゴリ 設計上の考慮事項
  スケーラビリティ ターゲット 使用するストレージ アカウントの数が最大数以下になるようにアプリケーションを設計できますか?
  スケーラビリティ ターゲット 容量とトランザクションの制限に近づかないようにしていますか?
  スケーラビリティ ターゲット 1 秒あたりのエンティティに対するスケーラビリティ ターゲットに近づいていませんか?
  ネットワーク クライアント側のデバイスは、必要なパフォーマンスを達成するのに十分な高帯域幅と低遅延を備えていますか?
  ネットワーク クライアント側のデバイスには、高品質のネットワーク リンクがありますか?
  ネットワーク クライアント アプリケーションは、ストレージ アカウントと同じリージョンにありますか?
  クライアントへの直接アクセス Shared Access Signature (SAS) とクロスオリジン リソース共有 (CORS) を使用して、Azure Storage への直接アクセスを有効にしていますか?
  バッチ処理 エンティティ グループ トランザクションを使用してアプリケーションの更新をバッチ処理していますか?
  .NET 構成 .NET Framework アプリケーションの場合、十分な数のコンカレント接続を使用するようにクライアントを構成していますか?
  .NET 構成 .NET Framework アプリケーションの場合、十分な数のスレッドを使用するように .NET を構成しましたか?
  Parallelism クライアントの機能に過剰な負荷を掛けたり、スケーラビリティ ターゲットに近づいたりしないように、並列処理が適切に制限されていることを確認しましたか?
  ツール Microsoft が提供する最新バージョンのクライアント ライブラリとツールを使用していますか?
  [再試行の回数] エクスポネンシャル バックオフを使ってエラーとタイムアウトを調整する再試行ポリシーを使用していますか?
  [再試行の回数] 再試行できないエラーに対するアプリケーションの再試行を回避していますか?
  構成 テーブル要求に JSON を使用していますか?
  構成 小さな要求のパフォーマンスを上げるために、Nagle アルゴリズムをオフにしていますか?
  テーブルとパーティション 適切にデータのパーティション分割を実行していますか?
  ホット パーティション 末尾または先頭にのみ追加されるパターンを回避していますか?
  ホット パーティション 多くのパーティションにまたがる挿入や更新を実行しますか?
  クエリ スコープ ほとんどの場合にポイント クエリの使用を許可し、テーブル クエリは控え目に使用するようスキーマを設計していますか?
  クエリ密度 通常のクエリでは、アプリケーションが今後使用する行のみをスキャンして結果を取得していますか?
  返されるデータの限定 不要なエンティティが返されないように、フィルターを使用していますか?
  返されるデータの限定 不要なプロパティが返されないように、プロジェクションを使用していますか?
  非正規化 データを取得するときに非効率なクエリや複数の読み取り要求が回避されるように、データを非正規化していますか?
  挿入、更新、削除 トランザクションとする必要がある要求やラウンド トリップを削減するために同時に実行できる要求は、バッチ操作で実行していますか?
  挿入、更新、削除 挿入または更新のどちらを実行するかを判断するためだけにエンティティを取得しないようにしていますか?
  挿入、更新、削除 まとめて取得されることが多い一連のデータは、複数のエンティティではなく、1 つのエンティティにプロパティとして格納することを検討しましたか?
  挿入、更新、削除 まとめて取得され、バッチ操作で書き込むことができるエンティティ (時系列データなど) には、テーブルではなく BLOB を使用することを検討しましたか?

スケーラビリティ ターゲット

アプリケーションがいずれかのスケーラビリティ ターゲットに近づいたり超過したりすると、トランザクション待機時間や調整が増加することがあります。 Azure Storage によってアプリケーションが調整されると、サービスが 503 (サーバー ビジー) または 500 (操作タイムアウト) のエラー コードを返し始めます。 スケーラビリティ ターゲットの制限内にとどまることでこれらのエラーを回避することは、アプリケーションのパフォーマンスを強化するうえで重要な部分です。

Table service のスケーラビリティ ターゲットの詳細については、「Table Storage のスケーラビリティとパフォーマンスのターゲット」を参照してください。

ストレージ アカウントの最大数

特定のサブスクリプションとリージョンの組み合わせについて許容されるストレージ アカウントの最大数に近づいてきた場合に、複数のストレージ アカウントを使用したシャード化により、イングレス、エグレス、1 秒あたりの I/O 操作 (IOPS)、または容量を増やすことがあります。 このシナリオでは、ワークロードに必要なストレージ アカウントの数を減らすために、可能であればストレージ アカウントの制限を引き上げることをお勧めします。 Azure サポートに連絡して、ストレージ アカウントの制限の引き上げをご依頼ください。

容量とトランザクションのターゲット

アプリケーションが 1 つのストレージ アカウントに対するスケーラビリティ ターゲットに接近している場合は、次の方法のいずれかを検討し、適用します。

  • 対象のアプリケーションでスケーラビリティ ターゲットに対する接近や超過を引き起こしたワークロードを見直します。 設計を変更して、必要な帯域幅や処理能力を抑えたり、トランザクションを減らしたりすることができないでしょうか?
  • アプリケーションがいずれかのスケーラビリティ ターゲットを超過することがほぼ確実な場合には、複数のストレージ アカウントを作成し、それらのアカウントにアプリケーション データを分けて配置します。 このパターンを使用する場合は、後で負荷分散用のストレージ アカウントを追加できるようにアプリケーションを設計してください。 ストレージ アカウント自体では、データ保存、トランザクション実行、データ転送以外の使用に料金が発生することはありません。
  • アプリケーションが帯域幅ターゲットに近づいてきた場合は、クライアント側でデータを圧縮し、Azure Storage へのデータ送信に必要な帯域幅を削減する方法を検討します。 データを圧縮することにより帯域幅の節約とネットワーク パフォーマンスの改善が期待できますが、パフォーマンスにマイナスの影響が及ぶ可能性もあります。 クライアント側でデータの圧縮と展開の処理要件が増加することにより生じるパフォーマンスへの影響を評価してください。 圧縮データを格納すると、標準ツールではデータが見づらくなるため、トラブルシューティングが困難になる場合があることに留意してください。
  • アプリケーションがスケーラビリティ ターゲットに近づいている場合は、再試行にエクスポネンシャル バックオフを使用していることを確認してください。 この記事に書かれている推奨事項を実践して、スケーラビリティ ターゲットへの到達を回避することを強くお勧めします。 ただし、再試行にエクスポネンシャル バックオフを使用するとアプリケーションの迅速な再試行が妨げられ、調整が悪化する可能性もあります。 詳細については、「タイムアウト エラーとサーバー ビジー エラー」セクションを参照してください。

データ操作のターゲット

ストレージ アカウントへのトラフィックが増大すると Azure Storage が負荷分散を実行しますが、トラフィックのバーストが発生した場合、すぐには、そのトラフィック量のスループットが得られない場合もあります。 バーストが発生している間は、Azure Storage が自動でテーブルの負荷分散を実行するため、調整やタイムアウトが発生することを想定しておいてください。 負荷が緩やかに増加した場合の方が、システムが適切に負荷分散を実行する時間が確保できるため、一般的によい結果が得られます。

1 秒あたりのエンティティ (ストレージ アカウント)

テーブルに対するアクセスのスケーラビリティ限界は、1 アカウントにつき 1 秒あたり最大 20,000 エンティティ (各 1 KB) です。 一般に、挿入、更新、削除、スキャンされたエンティティがそれぞれ、このターゲットに対してカウントされます。 したがって、100 エンティティを含むバッチ挿入は 100 エンティティとカウントされます。 1 回のクエリで 1,000 エンティティをスキャンし、5 つが返された場合のカウントは、1,000 エンティティです。

1 秒あたりのエンティティ (パーティション)

単一パーティション内のテーブルに対するアクセスのスケーラビリティ ターゲットは、1 秒あたり 2,000 エンティティ (各 1 KB) です。カウント方法は前のセクションと同じです。

ネットワーク

アプリケーションの物理ネットワークの制約がパフォーマンスに大きな影響を及ぼすことがあります。 以降のセクションでは、ユーザーが遭遇する可能性のあるいくつかの制限について説明します。

クライアントのネットワーク機能

ネットワーク リンクの帯域幅と接続品質は、アプリケーションのパフォーマンスに重要な役割を果たします。以降のセクションでは、この点について説明しています。

スループット

帯域幅については、多くの場合にクライアントの処理能力が問題になります。 大きい Azure インスタンスは、処理能力の高い NIC を使用します。そのため、1 台のコンピューターのネットワーク制限を引き上げる必要がある場合は、大きなインスタンスを使用するか VM の数を増やすことを検討してください。 オンプレミスのアプリケーションから Azure Storage にアクセスする場合にも、同じ規則が当てはまります。クライアント デバイスのネットワーク性能と、Azure Storage の場所へのネットワーク接続を把握し、それらを必要に応じて増強するか、それぞれの性能の範囲内でアプリケーションが稼働するように設計してください。

他のネットワーク運用と同様に、エラーやパケット損失が生じるネットワーク状態では、遅延が生じて有効なスループットが損なわれることに留意してください。 WireShark または NetMon は、この問題の診断に有用です。

場所

分散型環境では、サーバーの近くにクライアントを配置すると、パフォーマンスが最大になります。 最小限の遅延で Azure Storage にアクセスするには、同じ Azure リージョン内にクライアントを配置するのが最適です。 たとえば、Azure Storage を使用する Azure Web アプリを 1 つ保有している場合は、その両方を単一のリージョン内に配置します (たとえば、米国西部や東南アジア)。 リソースを併置することにより待ち時間が短縮され、コストが低下します。1 つのリージョン内での帯域幅使用は無料であるためです。

Azure 内にホストされていないクライアント アプリケーション (モバイル デバイス アプリやオンプレミスのエンタープライズ サービスなど) が Azure Storage にアクセスする場合、それらのクライアントに近いリージョンにストレージ アカウントを配置することで待ち時間が短くなる可能性があります。 クライアントが広範囲に分散されている場合 (一部が北米に、一部がヨーロッパに存在する場合など) は、ストレージ アカウントをリージョンごとに 1 つ使用することを検討します。 アプリケーションが保存するデータが個々のユーザーに固有であり、ストレージ アカウント間でデータをレプリケートする必要がなければ、これは導入しやすい方法です。

SAS と CORS

ユーザーの Web ブラウザーや携帯電話アプリで実行されている JavaScript などのコードが Azure Storage 内のデータにアクセスするのを承認する必要があるとします。 1 つの方法として、プロキシとして動作するサービス アプリケーションを作成することが考えられます。 このサービスに対してユーザーのデバイスが認証を行うと、Azure Storage リソースへのアクセスがそのサービスによって承認されるというものです。 この方法では、安全でないデバイスにストレージ アカウント キーを知らせずに済みます。 しかし、この方法では、サービス アプリケーションに大きなオーバーヘッドが生じます。ユーザーのデバイスと Azure Storage との間で転送されるデータがすべてそのサービス アプリケーションを通過することになるためです。

Shared Access Signature (SAS) を使用すると、サービス アプリケーションを Azure Storage のプロキシとして用いることを回避できます。 SAS を使用すれば、ユーザーのデバイスから制限付きアクセス トークンを使って、Azure Storage に直接要求を実行できるようになります。 たとえば、ユーザーがアプリケーションに写真をアップロードしたい場合に、サービス アプリケーションで SAS を生成してユーザーのデバイスに送信することが考えられます。 Azure Storage リソースへの書き込みアクセス許可を SAS トークンで与えることが可能です。アクセス許可には期間が指定され、その期間を過ぎると SAS トークンの有効期限が切れます。 SAS の詳細については、「Shared Access Signatures (SAS) を使用して Azure Storage リソースへの制限付きアクセスを許可する」を参照してください。

通常、あるドメイン上の Web サイトでホストされているページの JavaScript が、別のドメインに対して特定の操作 (書き込みなど) を実行することは、Web ブラウザーによって許可されません。 このポリシーは "同一オリジン ポリシー" と呼ばれ、ページ上の悪意のあるスクリプトが別の Web ページ上のデータにアクセスすることを阻止するものです。 ただし、クラウドのソリューションを構築するときには、同一オリジン ポリシーが制限になることがあります。 クロスオリジン リソース共有 (CORS) はブラウザーの機能です。ソース ドメインで生成された要求が信頼済みであることをターゲット ドメインがブラウザーに伝達できます。

たとえば、Azure で実行されている Web アプリケーションが Azure Storage アカウントにリソースを要求するとします。 Web アプリケーションがソース ドメインで、ストレージ アカウントがターゲット ドメインです。 任意の Azure Storage サービスに対して CORS を構成して、ソース ドメインからの要求が Azure Storage によって信頼されていることを Web ブラウザーに伝えることができます。 CORS の詳細については、「Azure Storage でのクロスオリジン リソース共有 (CORS) のサポート」を参照してください。

SAS と CORS はどちらも、Web アプリケーションに対する不要な負荷をなくす効果があります。

バッチ トランザクション

同じテーブルに存在し、かつ同じパーティション グループに属しているエンティティについて、Table service はバッチ トランザクションをサポートします。 詳細については、「エンティティ グループ トランザクションの実行」を参照してください。

.NET 構成

このセクションでは、.NET Framework を使用するプロジェクトの場合に、パフォーマンスの大幅な向上を図るために利用できるいくつかの簡単な構成設定を示します。 .NET 以外の言語を使用している場合は、その言語に類似の概念がないか確認してください。

既定の接続数の上限を引き上げる

Note

接続プールは ServicePointManager クラスによって制御されるため、このセクションは .NET Framework を使用するプロジェクトに適用されます。 .NET Core では、接続プールの管理に関して大幅な変更が導入されました。接続プールは HttpClient レベルで行われ、既定ではプールのサイズが制限されません。 つまり、HTTP 接続はワークロードを満たすように自動的にスケーリングされます。 パフォーマンスの向上を活用するには、可能な場合は最新バージョンの .NET を使用することをお勧めします。

.NET Framework を使用するプロジェクトでは、次のコードを使用して、既定の接続数の上限 (通常、クライアント環境では 2、サーバー環境では 10) を 100 に引き上げることができます。 一般的に、この値はアプリケーションが使用するおおよそのスレッド数に設定します。 接続数の上限は、接続を開始する前に設定してください。

ServicePointManager.DefaultConnectionLimit = 100; //(Or More)  

.NET Framework での接続プールの制限について詳しくは、「.NET Framework での接続プールの制限と .NET 用の新しい Azure SDK」をご覧ください。

他のプログラミング言語については、ドキュメントを参照して接続数の上限の設定方法を確認してください。

スレッドの最小数を増やす

同期呼び出しを非同期タスクと共に使用している場合、スレッド プールのスレッド数を増やしたい場合があります。

ThreadPool.SetMinThreads(100,100); //(Determine the right number for your application)  

詳細については、ThreadPool.SetMinThreads メソッドを参照してください。

無制限の並列処理

並列処理はパフォーマンスの観点では非常に有用ですが、無制限の並列処理を使用すると、スレッド数や並列要求数に対して適用される制限がなくなることになるので、注意が必要です。 同じストレージ アカウント内の複数のパーティションにアクセスする状況や、同じパーティション内の複数の項目にアクセスする状況では、データをアップロードまたはダウンロードするための並列要求の数を制限するようにしてください。 並列処理が無制限の場合、アプリケーションはクライアント デバイスの処理能力やストレージ アカウントのスケーラビリティ ターゲットを超過することがあり、その結果、待ち時間や調整時間が長くなります。

クライアント ライブラリとツール

パフォーマンスを最大限に引き出すためには必ず、Microsoft から提供される最新のクライアント ライブラリとツールを使用してください。 Azure Storage のクライアント ライブラリは、さまざまな言語に対応しています。 また、Azure Storage は PowerShell と Azure CLI をサポートします。 Microsoft はパフォーマンスに留意してこれらのクライアント ライブラリとツールを積極的に開発し、最新のサービス バージョンに遅れることなく対応して、数多くのパフォーマンスの実証済みプラクティスを内部で確実に処理できるように取り組んでいます。

サービス エラーの処理

サービスが要求を処理できない場合、Azure Storage からエラーが返されます。 特定のシナリオで Azure Storage から返されるエラーについての知識は、パフォーマンスを最適化するうえで役立ちます。

タイムアウト エラーとサーバー ビジー エラー

アプリケーションがスケーラビリティの限界に近づくと、アプリケーションに対して Azure Storage による調整が発生することがあります。 場合によっては、なんらかの一時的な状態によって、Azure Storage が要求を処理できなくなることもあります。 どちらのケースでも、サービスからは 503 (サーバー ビジー) または 500 (タイムアウト) エラーが返される可能性があります。 スループットを高めるためにデータ パーティションがサービスによって再調整されている場合にも、これらのエラーが発生することがあります。 通常、クライアント アプリケーションは、そうしたエラーを引き起こしている操作を再試行する必要があります。 ただし、スケーラビリティ ターゲットを超過しているためにアプリケーションに Azure Storage による調整が発生している場合や、他のなんらかの理由でサービスが要求を処理できない場合、積極的に再試行を実行すると問題が悪化することがあります。 再試行ポリシーにはエクスポネンシャル バックオフを使用することをお勧めします。エクスポネンシャル バックオフは、クライアント ライブラリの既定の動作にもなっています。 たとえば、アプリケーションが 2 秒後、次に 4 秒後、次に 10 秒後、次に 30 秒後に再試行し、その後再試行を断念することがあります。 そうすれば、調整が起こって動作が悪化することなく、サービスに対するアプリケーションの負荷を大幅に軽減できます。

接続エラーは、調整の結果ではなく、一時的な問題と予想されるので、直後に再試行を実行してかまいません。

再試行できないエラー

クライアント ライブラリは、再試行できるエラーとできないエラーを認識して再試行を処理します。 ただし、Azure Storage REST API を直接呼び出している場合は、再試行すべきではないエラーも一部存在します。 たとえば、400 (正しくない要求) エラーは、クライアント アプリケーションから送信された要求が想定外の形式であったために処理できなかったことを示しています。 この要求を再送信しても、毎回同じ応答が返されることになるので、再試行は無意味です。 Azure Storage REST API を直接呼び出している場合は、どのようなエラーが生じる可能性があるか、また、それらを再試行すべきかどうかを意識するようにしてください。

Azure Storage のエラー コードの詳細については、「状態コードとエラー コード」を参照してください。

構成

このセクションでは、Table service のパフォーマンスを大幅に向上させるための簡単な構成を示します。

JSON を使用する

ストレージ サービス Version 2013-08-15 より、Table service では、テーブル データの転送用に、XML ベースの AtomPub 形式に代えて JSON を使用できるようになりました。 JSON を使用することにより、ペイロード サイズが 75% 程度に抑えられ、アプリケーションのパフォーマンスを大幅に引き上げることができます。

詳しくは、投稿「Microsoft Azure Tables: Introducing JSON (Microsoft Azure テーブル: JSON の紹介)」と、「テーブル サービス操作のペイロード形式」をご覧ください。

Nagle の無効化

Nagle のアルゴリズムは、ネットワーク パフォーマンスを向上させる方法として、TCP/IP ネットワークで広く使用されています。 ただし、すべての環境 (高度な対話形式の環境など) で最適であるとは言えません。 Nagle のアルゴリズムは Azure Table service に対する要求のパフォーマンスにマイナスの影響を及ぼすため、可能な場合は無効にしてください。

スキーマ

データの表現とクエリの方法は、Table service のパフォーマンスに影響を及ぼす単一要因として最大のものです。 アプリケーションごとに違いはありますが、このセクションでは、以下に関連する一般的な実証済みプラクティスの概略を示します。

  • テーブル設計
  • 効率的なクエリ
  • 効率的なデータ更新

テーブルとパーティション

テーブルはパーティションに分割されます。 同じパーティションに格納されるエンティティは、いずれも同じパーティション キーを共有し、一意の行キーによってパーティション内で識別されます。 パーティションには利点もありますが、スケーラビリティ限界ももたらします。

  • メリット:最大 100 個のストレージ操作 (総サイズの上限は 4 MB) を含む単一のアトミック バッチ トランザクションで、同じパーティション内のエンティティを更新できます。 また、取得するエンティティが同数であれば、複数のパーティションにまたがるデータのクエリよりも、単一パーティションに含まれるデータのクエリの方が効率的に実行できます (ただし、テーブル データのクエリに関する推奨事項を参照してください)。
  • スケーラビリティ限界: パーティションはアトミック バッチ トランザクションをサポートしているため、単一パーティションに格納されているエンティティへのアクセスは、負荷分散の対象になりません。 したがって、個々のテーブル パーティションのスケーラビリティ ターゲットは、Table service 全体のターゲットよりも低くなります。

テーブルとパーティションにはこうした特徴があるため、以下の設計原理を適用します。

  • クライアント アプリケーションが同一論理ユニットの処理内で頻繁に更新やクエリを実行するデータは、同じパーティションに配置します。 たとえば、書き込みがアプリケーションによって集約される場合や、アトミック バッチ操作を実行する場合は、同じパーティションにデータを配置します。 さらに、単一パーティションに含まれるデータは、複数のパーティションにまたがるデータよりも 1 回で効率的にクエリを実行できます。
  • クライアント アプリケーションが同一論理ユニットの処理 (単一クエリまたはバッチ更新) 内で挿入や更新、クエリを実行しないデータは、別のパーティションに配置します。 単一テーブル内のパーティション キーの数には上限がないことに注意してください。パーティション キーが数百万個あっても問題にはならず、パフォーマンスは影響を受けません。 たとえばアプリケーションが、ユーザー サインインが必要でアクセス数の多い Web サイトである場合、パーティション キーとして User ID を使用することは適切です。

ホット パーティション

ホット パーティションとは、あるアカウントへのトラフィックのうち、過度な割合を占めていながら、それが単一のパーティションであるために負荷分散できないパーティションです。 一般的にホット パーティションは、次の 2 つのうち、いずれかの状況で発生します。

末尾または先頭にのみ追加されるパターン

"追加のみ" パターンでは、特定のパーティション キーに対するすべての (または、ほとんどすべての) トラフィックが現在時刻によって増減します。 たとえば、アプリケーションがログ データのパーティション キーとして現在日時を使用するとします。 この設計では、すべての挿入がテーブルの最後のパーティションに対して実行されるため、システムで適切に負荷分散できません。 対象のパーティションに対するトラフィックの量がパーティション レベルのスケーラビリティ ターゲットを超えると、調整が行われます。 トラフィックを複数のパーティションに送り、要求の負荷をテーブル全体に分散することが必要です。

大量のトラフィック データ

採用したパーティショニング スキームにより、ある単一パーティションのデータが他のパーティションよりもはるかに多く使用される事態が生じると、そのパーティションのトラフィックが単一パーティションのスケーラビリティ ターゲットに接近し、調整が発生することがあります。 いずれのパーティションもスケーラビリティ ターゲットに達しないように、パーティション スキームを確認してください。

クエリ実行

このセクションでは、Table service のクエリに関する実証済みプラクティスについて説明します。

クエリ スコープ

複数の方法で、クエリで照会するエンティティの範囲を指定できます。 次に、クエリ スコープの各オプションについて説明します。

  • ポイント クエリ: ポイント クエリは、取得するエンティティのパーティション キーと行キーの両方を指定することによって厳密に 1 つのエンティティを取得します。 このクエリは効率的であるため、可能であれば常にこれを使用してください。
  • パーティション クエリ: パーティション クエリは、共通のパーティション キーを持つデータのセットを取得するクエリです。 通常このクエリでは、パーティション キーに加えて、行キー値の範囲かいくつかのエンティティ プロパティ値の範囲を指定します。 これらのクエリは、ポイント クエリより非効率であるため、多用しないでください。
  • テーブル クエリ: テーブル クエリは、共通のパーティション キーを共有しないエンティティのセットを取得するクエリです。 このクエリは効率的でないため、可能であれば使用を控えてください。

通常はスキャン (単一のエンティティを超える大きさのクエリ) を実行しないようにしますが、避けられない場合は、必要のない大量のエンティティをスキャンしたり返したりせずに目的のデータを取得できるようデータを編成してみてください。

クエリ密度

クエリ効率に関する他の主要な要因は、結果のセットを特定するためのスキャンが行われたエンティティの数に対する、返されたエンティティの数です。 アプリケーションで、1% のデータだけに共通するプロパティ値に対応するフィルターを使用したテーブル クエリを実行すると、このクエリでは 1 つのエンティティを返すごとに 100 エンティティがスキャンされます。 前に説明したテーブルのスケーラビリティ ターゲットはいずれも、返されるエンティティ数ではなく、スキャンを実行するエンティティ数に関係しています。つまり、クエリ密度が低いと、目的のエンティティを取得するために非常に多くのエンティティをスキャンしなければならないため、Table service によるアプリケーションの調整が発生しやすくなります。 調整を回避する方法の詳細については、「非正規化」のセクションを参照してください。

必要なデータ量の制限

クエリによって、クライアント アプリケーションで不要なエンティティが返されることがわかっている場合は、フィルターを使用して返されるセットのサイズを減らすことを検討してください。 クライアントに返されないエンティティもスケーラビリティ限界に対してカウントされますが、ネットワーク ペイロードのサイズが小さくなり、クライアント アプリケーションが処理しなければならないエンティティの数も少なくなるため、アプリケーションのパフォーマンスは向上します。 スケーラビリティ ターゲットはスキャンされるエンティティ数に関連するため、多くのエンティティを除外するクエリは、ほとんどエンティティを返さない場合でも、調整の原因となることがあります。 クエリの効率を高める方法について詳しくは、「クエリ密度」のセクションを参照してください。

クライアント アプリケーションが、テーブルに含まれるエンティティのプロパティのごく一部しか必要としない場合は、プロジェクションを使用して、返されるデータ セットのサイズを制限できます。 フィルター処理と同じく、プロジェクションはネットワークの負荷とクライアントによる処理の削減に役立ちます。

非正規化

リレーショナル データベースを運用する場合とは異なり、テーブル データに対する効率的なクエリの実証済みプラクティスは、データを非正規化することにつながります。 つまり、多数のエンティティをスキャンしてアプリケーションに必要なデータを見つけるのではなく、複数のエンティティで同じデータを (データの検索に使用するキーごとに 1 つ) 複製し、クライアントに必要なデータを探すためにクエリでスキャンしなければならないエンティティ数を最小にします。 たとえば電子商取引 Web サイトでは、ある注文を見つけるために、カスタマー ID (特定の顧客の注文を探す) と日付 (特定の日の注文を探す) の両方での検索が必要になることがあります。 Table Storage での最適な方法は、エンティティ (またはそれへの参照) を 2 回格納することです。1 回はカスタマー ID で検索しやすくするためにテーブル名、PK、RK と共に格納し、もう 1 回は日付で検索しやすくします。

挿入、更新、削除

このセクションでは、Table service に格納されているエンティティの変更に関する実証済みプラクティスについて説明します。

バッチ処理

Azure Storage では、バッチ トランザクションがエンティティ グループ トランザクションと呼ばれています。 エンティティ グループ トランザクションに含まれるすべての操作は、単一テーブル内の 1 つのパーティションを対象としている必要があります。 可能な場合は、エンティティ グループ トランザクションを使用して一括での挿入、更新、削除を実行してください。 エンティティ グループ トランザクションを使用することにより、クライアント アプリケーションとサーバーの間のラウンド トリップ数が減少し、課金対象のトランザクション数も少なくなります (1 つのエンティティ グループ トランザクションは課金対象の 1 回のトランザクションとしてカウントされ、最大 100 回のストレージ操作が含まれます)。さらに、アトミックな更新 (1 回のエンティティ グループ トランザクションですべての操作が成功するか、すべて失敗するかのいずれかになるような更新) も可能になります。 モバイル デバイスなどの待ち時間が長い環境では、エンティティ グループ トランザクションを使用することで大きなメリットが得られます。

Upsert

可能な場合は、常にテーブルの アップサート 操作を使用します。 アップサートには 2 種類あり、いずれも従来の挿入操作と更新操作に比べて効率的です。

  • InsertOrMerge: エンティティ プロパティのサブセットをアップロードする必要があるものの、エンティティが既に存在するかどうかが明らかでない場合には、この操作を使用します。 エンティティが存在する場合、この呼び出しはアップサート操作に含まれるプロパティを更新し、既存のプロパティはすべてそのまま残します。エンティティが存在しない場合は、新しいエンティティを挿入します。 変更するプロパティのアップロードだけが必要とされる点が、クエリにおけるプロジェクションの使用に類似しています。
  • InsertOrReplace: まったく新しいエンティティをアップロードする必要があるものの、エンティティが既に存在するかどうかが明らかでない場合には、この操作を使用します。 この操作は、以前のエンティティを全面的に上書きするため、新たにアップロードするエンティティに誤りのないことが確実な場合に使用してください。 たとえば、アプリケーションが以前にユーザーの場所データを保存しているかどうかにかかわらず、ユーザーの現在の場所を格納しているエンティティを更新する必要があり、その新しい場所エンティティに問題がなく、かつ以前のどのエンティティのどの情報も必要としない場合などです。

単一エンティティでのデータ シリーズの格納

アプリケーションが、頻繁にすべてを一括で取得しなければならない一連のデータを保存する場合があります。たとえば、アプリケーションが直近 24 時間のデータを反映するチャートをプロットするために、時間の経過に伴う CPU 使用率を追跡している場合です。 このとき、正時ごとに対応するテーブル エンティティを 1 つずつ作成し、各エンティティに特定の時刻の CPU 使用率を格納する方法をとることができます。 このデータをプロットするには、アプリケーションが直近 24 時間のデータを保持しているエンティティを取得する必要があります。

また、別の方法として、アプリケーションが各時刻の CPU 使用率を単一エンティティの個々のプロパティとして格納することもできます。アプリケーションは InsertOrMerge Upsert の呼び出しを実行するたびに直近の時刻の値を更新でき、その値を毎時間の更新に使うことができます。 データをプロットするためにアプリケーションが取得するエンティティは、24 個ではなく 1 つだけであるため、効率的なクエリを実行できます。 クエリの効率について詳しくは、「クエリ スコープ」のセクションを参照してください。

BLOB での構造化データの格納

バッチ挿入を実行した後で一定範囲のエンティティをまとめて取得する場合は、テーブルではなく BLOB の使用を検討してください。 典型的な例はログ ファイルです。 数分間のログを一括で処理して挿入を実行した後、数分間のログを一度に取得することができます。 この場合は、テーブルではなく BLOB を使用した方が、書き込まれるオブジェクトと読み取られるオブジェクトの数を大幅に削減でき、また、必要な要求数も減る可能性があるため、パフォーマンスの面で優れています。

次の手順