Azure Table における orderby
Azrue のTable Storage を対象としたLinqでOrderby が使えないのは有名な話ですが、
まあ、コードがカッコ悪くなることに目をつぶって、
var account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
var client = account.CreateCloudTableClient();
var context = client.GetDataServiceContext();
var query = (from t in context.CreateQuery<Table>("Table")
//orderby t.propety //これはエラーになります。
select t).ToList();
var sorted = from t in query
orderby t.propety //これはエラーになりません。
select t;
GridView1.DataSource = sorted;
GridView1.DataBind();
などとすれば、普通に動くは動きます。
が、このコードには、カッコ悪いということをさておいても、利用するにはいろいろと問題があります。
どういう場合に問題になるかというと、データが大きく?なると問題になります。
例えば、数GBのデータに対して上記コードを実行するとどうなるでしょうか。
ToList() の時点でクエリが実行され、数TBのデータを読み込もうとして・・・固まっちゃう?
かというと、実際はそうはなりません。
実装にもよりますが、いくらデータ(エンティティ)数があっても、1000件しか表示されません。
というのは、Table に対するクエリ(で返されるエンティティ数)は
- 1000件まで
- 60秒以内(30秒、5秒になったんでしたっけ?)
- 4Mまで
のいずれかの制限を受けます。
となると、Orderbyが(何も考えずに)使えるのは、基本的に上記の条件以下のデータに対してのみということになります。
継続トークンを設定する(AsTableServiceQuery 使う方がいいかな)ことで、閾値の変更は可能ですが、不用意に巨大なデータを読み込みアプリが固まるなどの懸念が発生します。
追記:ちなみにAsTableServiceQueryを使う場合は、1個目のクエリを、
var query = (from t in context.CreateQuery<SampleTable>("SampleTable")
select t).AsTableServiceQuery().ToList();
とします。
上記制限は、そうならないための仕様上のリミッターだとも考えられます。
が、いずれにせよ、開発者視点としては、
- Orderbyが使えるのはデータが小さいとき
- 小さいデータでTableを使う意味は少ない
- 大きいデータでもOrderbyを使えなくはない
- が、いろいろと問題が発生する
などというジレンマが発生することになります。
「いくらうちのサイトのアクセスが少ないからって1000件以上はデータたまるよ!」
という状況が普通かと思いますので、ゆえに、冒頭のコードをそのまま使うのは厳しいというわけです。
では、Tableってどう使えばいいのでしょうか?
このような制限(仕様)は、Table の位置づけや、どう利用すべきか?ということを暗に示唆しているものと思われます。
私見ですが、いわゆるアプリ開発におけるデータの利用は、
- データを溜める
- データを間引く(SELECT, WHERE)
- データを成形する(ORDER BYなどの集合関数系機能)
という3つの行為に分割できるかと思うのですが、Table は2までの機能のものと考える必要があるのでは?と感じております。
RDBは1~3をサポートするので、どうしてもTableは見劣りしがちですが、それは本質的に仕方のないことだと思います。
そのことは、Linq to SQLにおいて、
Orderby(ソート)っていったいどこでやるの?
を考えてみるとTableの本質というか位置づけがわかります。
Linq to SQLでは、裏で生成されているSQL文を確認するとORDER BYはSQL文としてRDBに渡され、ソート処理はRDBエンジンにて行われています。
では、同じことをTable にやらそうとすると、どうなるでしょうか?Table側に何らかの検索エンジンを搭載する必要があり、それを高速化するためには、データの正規化やら、インデックスやらという話になり、
それってRDBみたいなのと同じじゃん?
という話になり、Tableの位置づけはあいまいになりますし、Storageにそこまでを求めるのも酷な話です。
もちろん、Linq to Object やXMLのようにクライアントで処理する方法もありますが、いずれにせよTableにロジックが乗っかってるわけではありません。一方、クライアントに一気にデータが流れ込まないくらいの仕組みだけは最低限Tableにあるべきです。
というわけで、Tableはデータの保存、大まかな検索(1000件以下への絞り込み)に利用し、データの成形等の細かな処理はクライアント側で行うというのが自然と導かれる活用法なのかと感じます。
1000件以内に絞り込めない場合は、クエリをさらに細かくし、それらの結果を一度SQLに蓄積した後、クライアントから利用するという感じでしょうか。
そういう意味では、Table利用においては、
Table とSQL等のその他のデータストアは排他的に考えるものではない
ということを認識しておくことは意外と重要なのかもしれません。
将来的には、DryadとかHadoopみたいなのがTableに最適化されたエンジンとして登場してくるのではないかと思いますが、そのような状態になったとしても、SQLの必要性が低下するとも思えません。
既にHadoop(やKVS)等を運用されている方はわかると思うのですが、それだけで、データハンドリングが完結するケースはむしろ少なく、ほとんどのシステムがSQL等の複数のデータストア技術を組み合わせて利用されていますよね。
いろいろ書きましたが、まとめると・・・
- データがSQL Azureで扱える量ならSQL Azure +クライアントアプリで実装が無難
- データが大きい場合、溜める、間引くは、Tableで行い、細かな処理はSQLを含むクライアントアプリで対応
ということでしょうか。
Orderby からそれましたが、今回はそんな感じで。