cosmic

Cosmos DB の論理パーティションは、コンテナーのパーティションキーに基づいてデータをグルーピングします。

Cosmos DBは、水平スケールさせるために、物理サーバー/パーティション間で、論理パーティションをシームレスに組み合わせます。
ユーザーが制御できるのは論理パーティションまでで、論理パーティションと物理パーティションのマッピングはシステム側で自動的に行います。

image

パーティショニングの設計により性能に大きく影響がでます。
良いパーティションキーとは、容量とスループットの観点からバランスが取れて分散するものです。

容量が偏ったり、スループットが偏ったりする場合には、パーティションキーを見直ししたほうがいいです。

image

cosmic

Cosmos DB の性能は、RSuで定義されています。
指定したRUsに従って、性能が提供されます。

RUsは、メモリやCPU、IOPSが抽象化して表現されたものです。
1KBのItemを1Readすると1RUs。
1KBのItemを1Write1すると5RUs。

RUsが課金に関係してくるので、各クエリのRUsをいかに低くするのかが重要な性能チューニングポイントになります。
RUsを抑えるデータモデリングについては、こちらの「Cosmos DBのデータモデリングの勘所」を参照してください。

image

SDK

PR #561: GetItemLinqQueryable now works with null query
Azure Cosmos DB .NET SDK Version 3.0 のバグ情報。

GetItemLinqQueryableを使っているときに、結果がNULLになると例外が発生するバグ修正がマージされました。
次ようなコードがあったときに、ItemがNullになると例外が発生します。

var allObjects = this.container.GetItemLinqQueryable<ExampleObject>(true).ToList();

SDK

元ネタ:ISSUE:#550 serializerSettings with v3 client

Version 2までは、Clientにシリアライザの設定をすることができました。

var serializerSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };

this.client = new DocumentClient(new Uri(this.options.CosmosDbEndPoint), this.options.CosmosDbKey, serializerSettings: serializerSettings);

しかし、2019/07/16段階では、Version 3ではカスタム設定が削除され、カスタムのシリアライザを設定できるようになりました。

参考:シリアライザの設定

参考:既定のシリアライザの実装

既定のシリアライザの設定を変更する方法を提供しない理由はないので、ISSUEとしてあがりました。

ISSUE:#551 Add support for JsonSerializerSettings on default serializer

カスタムシリアライザの使用方法

サンプル:https://github.com/Azure/azure-cosmos-dotnet-v3/pull/560/files

  1. CosmosSerializerを継承してカスタムシリアライザクラスを作成する。
  2. CosmosClientOptionsで、Serializerに作成したカスタムシリアライザクラスのインスタンスを渡す
  3. CosmosClientのインスタンス作成時にOptionを渡す

class JsonSerializerIgnoreNull : CosmosSerializer
{
    ……..
}

CosmosClientOptions options = new CosmosClientOptions()
{
     Serializer = new JsonSerializerIgnoreNull(),
};

CosmosClient client = new CosmosClient(endpoint, key, options)

SQL

Azure Cosmos DBのSQLサブクエリの書き方を見てみましょう。
例えば、次のようなクエリを表現したい場合はどうすればいいでしょうか。

SELECT Count(1) AS Count
FROM c
JOIN t IN c.tags
JOIN n IN c.nutrients
JOIN s IN c.servings
WHERE
t.name = ‘infant formula’
AND (n.nutritionValue > 0 AND n.nutritionValue < 10)
AND s.amount > 1

このクエリでは、インデックスは、タグの名前に「infant formula」を持つDocumentと一致します。
nutritionValue が0から10で、amaoutが1より大きいものです。

ここでのJOIN式は、フィルターを適用する前に、マッチしたtag、nutrients、servings配列を外積します。
Where句は、「c,t,n,s」タプルにフィルターを適用します。

マッチするDocumentが、tag、nutrients、servingsにそれぞれ10個あるとすると、10×10×10の1000個に拡張し、それに対してフィルターを書けます。

結合する前にフィルターをかけて効率化するにはサブクエリを利用します。

SELECT Count(1) AS Count
FROM c
JOIN (SELECT VALUE t FROM t IN c.tags WHERE t.name = ‘infant formula’)
JOIN (SELECT VALUE n FROM n IN c.nutrients WHERE n.nutritionValue > 0 AND n.nutritionValue < 10)
JOIN (SELECT VALUE s FROM s IN c.servings WHERE s.amount > 1)

タグが1つ、nutritionValue とservings が5つフィルターされたとすると、JSON式は25項目を展開します。