
January 14, 2012 19:05 by
Sekine
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は失敗し、更新できません。
これは、仕様ですので当然なのですが、
思いついた時の歓喜と、その後の落胆が大きかったです・・
7200bf14-079f-47ca-ac6e-0c7eaa02c93d|1|3.0