MongoDB 2.4 の新クエリーcapped arrayを試した
capped arrayの機能と性能を検証をした。
結論
capped arrayでは配列数が多い場合、明らかにsortが性能劣化する。
(使い難いが)sortを使わない場合は殆ど気にしなくて良いレベルになる。
LRUキャッシュに使うにはちょっと厳しいかもしれない。。
capped arrayの機能
ドキュメント内配列を容量固定にする。
>use testdb >db.cappedArray.ensureIndex({key:1},{unique:1}); >db.cappedArray.save({ key:10, value:[ {s:10}, {s:20}, {s:30}, {s:40}, {s:50} ]}); >db.cappedArray.find({key:10}); { "_id" : ObjectId("514fb518f63edd201d14595f"), "key":10, "value":[{"s":10},{"s":20 },{"s":30 },{"s":40},{"s":50} ] } // ここまでは同じ。 // capped array クエリー // $each => {s:9999} , {s:0} レコードを追加する // $sort => sフィールドで正順ソート // $slice=> 最後5レコードだけ抽出して保存。 db.cappedArray.update({key:10},{ $push: { value: { $each : [{s:9999},{s:0}], $sort : {s:1}, $slice:-5 } } }); // 確認:valueフィールドに注目。今指定した{s:0}すら入らない。 { "_id" : ObjectId("514fb518f63edd201d14595f"), "key":10, "value":[{"s":20 },{"s":30 },{"s":40},{"s":50},{"s":9999} ] }
やはり上記リンクのパフォーマンス用途でもある。
でもあまり配列が大きくなるようだと計算量的にどうなんだろう??
性能検証
- プロファイルの取り方
- 目的のDBに移ってdb.setProfilingLevel(level)
0 : 無効
1 : slowsオペレーション(遅い奴)だけ
2 : 全部オペレーション
use testdb db.setProfilingLevel(2)
プロファイルはdb.system.profile(capped)コレクションに溜まる。
capped array
capped array更新性能と配列数の関係を調べる。
- capped arrayクエリー
db.cappedArray.update({key:99},{ $push: { value: { $each : [{s:9999},{s:0}], $sort : {s:1}, $slice:-5 } } });
- 更新対象ドキュメント
- 配列数=20
{ key:99, value:[ {s:10, v:'11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'} :<中略> ,{s:200,v:'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'} ] }
- 配列数=20のcapped arrayクエリーのプロファイル
- ロック時間は0.56ms程度。
{ "op" : "update", "ns" : "testdb.cappedArray", "query" : { "key" : 99 }, "updateobj" : { "$push" : { "value" : { "$each" : [ { "s" : 9999 }, { "s" : 0 } ], "$sort" : { "s" : 1 }, "$slice" : -5 } } }, "nscanned" : 1, "nupdated" : 1, "keyUpdates" : 0, "numYield" : 0, "lockStats" : { "timeLockedMicros" : { "r" : NumberLong(0), "w" : NumberLong(560) }, "timeAcquiringMicros" : { "r" : NumberLong(0), "w" : NumberLong(7) } }, "millis" : 0, "ts" : ISODate("2013-03-26T05:30:07.891Z"), "client" : "127.0.0.1", "allUsers" : [ { "user" : "crumb", "userSource" : "admin" } ], "user" : "crumb@admin" }
- 更新対象ドキュメント
- 配列数=100。配列を5倍にしてみる。ちなみにこのsaveのlock期間は596 = 0.596msだった。小さいドキュメントとあまり変わらない。
(ドキュメントサイズが3.5kb程度で1ページに収まるので差が出ないのだろう。)
{ key:99, value:[ {s:10, v:'11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'} :<中略> ,{s:1000,v:'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'} ] }
- 配列数=100のcapped arrayクエリーのプロファイル
- ロック時間は1.439ms。明らかに増えた。
上記の通りデータサイズがI/Oに与える影響は軽微のはずなので、ソート処理時間が影響したと思われる。
{ "op" : "update", "ns" : "testdb.cappedArray", "query" : { "key" : 99 }, "updateobj" : { "$push" : { "value" : { "$each" : [ { "s" : 9999 }, { "s" : 0 } ],"$sort" : { "s" : 1 },"$slice" : -5 } } }, "nscanned" : 1, "nupdated" : 1, "keyUpdates" : 0, "numYield" : 0, "lockStats" : { "timeLockedMicros" : { "r" : NumberLong(0), "w" : NumberLong(1439) }, "timeAcquiringMicros" : { "r" : NumberLong(0), "w" : NumberLong(8) } }, "millis" : 1, "ts" : ISODate("2013-03-26T05:39:01.145Z"), "client" : "127.0.0.1", "allUsers" : [ { "user" : "crumb", "userSource" : "admin" } ], "user" : "crumb@admin" }
- 配列数=100のcapped arrayクエリーでsortをしなかった場合のプロファイル
- 予想通り高速になった。
{ "op" : "update", "ns" : "testdb.cappedArray", "query" : { "key" : 99 }, "updateobj" : { "$push" : { "value" : { "$each" : [ { "s" : 9999 }, { "s" : 0 } ], "$slice" : -5 } } }, "nscanned" : 1, "nupdated" : 1, "keyUpdates" : 0, "numYield" : 0, "lockStats" : { "timeLockedMicros" : { "r" : NumberLong(0), "w" : NumberLong(369) }, "timeAcquiringMicros" : { "r" : NumberLong(0), "w" : NumberLong(9) } }, "millis" : 0, "ts" : ISODate("2013-03-26T06:02:56.837Z"), "client" : "127.0.0.1", "allUsers" : [ { "user" : "crumb", "userSource" : "admin" } ], "user" : "crumb@admin" }