Storage Table を利用する場合、

PartitionKeyとRowKeyをどのように決めるのか重要なポイントとなります。

あまり気にせずに作ってしまうと、テーブル内のデータ量が多くなって来た時に、

抽出時のパフォーマンスが落ち、致命的な欠陥につながります。

特にRowKeyの考え方が重要で(PartitionKeyもそうですが)

まず、Storage Tableでは、RowKeyに対して昇順のインデックス付けがされます。

Table Storage の トランザクション – EGT

それを念頭に、実際にRowKeyをどのように組み立てれば良いかという事になるのですが、

例えば、PartitionKey、RowKey 以外の項目に where をかけるとすると、

対象テーブルの全てに走査・抽出が行われ、

データ量(レコード量)が多い場合には結果的に遅くなり、

さらにタイムアウトにより後方に存在するデータは抽出されないという事になります。

 

そのような事にならないように、

抽出するキーとなるものは、RowKeyに含め、RowKeyに対して where をかける

というのが原則となります。

RowKeyは、文字列型ですが、64KBの長さではなく、260文字しか有効ではありません。
(これは、PartitionKeyでも同じです)

 

データを表すキー項目が一つであれば、そのままRowKeyを使用するだけですが、

そんな単純なデータは多くはなく、複数のキーが有るのが普通でしょう。

そのような場合は、各キーを固定長の文字にして、連結してRowKeyとします。

例えば、店舗名、従業員名のキーが在るとしましょう。その場合、

RowKey = 店舗名20文字_従業員名20文字

のようにします。

数値が必要なら、string.Format(“0:10D”, 設定値);

日付なら、Ticks をうまく使うなどして、各項目を固定長に整形して連結します。

文字列が長い場合には、MD5ハッシュなどすれば、32文字になります。
(その場合、大文字小文字でハッシュ値が違うので注意してください。常に小文字にするなど)

 

このようにRowKeyを決める事で、

上の例で言えば、ある店舗名の従業員一覧が欲しい場合、

var query = from t in {TableServiceContextの従業員データ}
            where
            t.PartitionKey == partitionKey &&
            t.RowKey.CompareTo({調べたい店舗名20char}) >= 0 &&
            t.RowKey.CompareTo({調べたい店舗名20char} + "\uffff") < 0
            select t;

とすることで、その店舗名で始まるRowKeyを抽出できます。

t.RowKey.CompareTo({other}) >= 0 &&
t.RowKey.CompareTo({other} + "\uffff") < 0

上の、この構文は、StartsWith 相当です。

t.RowKey.StartsWith({other}) と同等になりますが、

Storage Table (TableServiceContext) の場合、Queryプロバイダが

StartsWithに対応していませんが、上記の書き方によって同等となります。

さらに言えば、部分条件抽出は、上記 StartsWith 相当しか無いと思ったほうがよさそうです。

SubString、EndWith、(他、部分的比較命令)は使用できません。

また、それらに相当する書き方も実際うまくいかないのが現状です。

この辺は、開発ストレージで動いたとしても、実際に動かなかったりしますので

十分注意してください。

(個人的には、開発ストレージで開発しないほうが良いとも思っています)

 

上記のことから、RowKeyは先頭一致の抽出が可能な事と、

それを利用して、キー項目を固定長で連結することが大事です。

固定長にするのは、where の文字列を作るときに任意な長さでは曖昧になるため。

また、RowKeyの値は変更できません。

 

以前、論理削除の意で、

0_DATA
削除すると
1_DATA

という、先頭1charを削除フラグとして試したことがあります。

UpdateChangesは失敗し、更新できません。

これは、仕様ですので当然なのですが、

思いついた時の歓喜と、その後の落胆が大きかったです・・