システム可用性を拡張するイン 
デクス戦略 
鈴木いっぺい 
MongoDB, Inc.
アジェンダ 
• インデクスとは何か? 
• インデクスの基本 
• 評価/チューニング 
• 地理空間情報機能(Geospacial) 
• テキスト検索 
• スケーリング
インデクスとは何か?
インデクスとは何か? 
料理の本から特定の料理を、そのレシピの名前 
から探そうとした時、索引からレシピを探すの 
が最も早い。
索引(インデクス)を利用
連結リスト 
1 2 3 4 5 6 7
連結リストを使ってアイテム7を探す 
1 2 3 4 5 6 7
ツリー構造からアイテム7を探す 
1 
2 
3 
4 
7 
6 
5
MongoDB内のインデクスはB-Treesによっ 
て構造化
Query, Insert, Delete処理
インデクスはMongoDBの性 
能チューニングにとって最も 
重要な要素
インデクスの基本
インデクスの基本 
• データベース性能を決める最大要素 
13 
– インデクスの効果はシステムデザインの初期からレビュー 
が必要 
– 冗長なインデクス設定を避ける事 
// authorのインデクス(abc順) 
>db.articles.ensureIndex( { author : 1 } ) 
– . 
// authorのインデクス(abcとは逆順) 
>db.articles.ensureIndex( { author : -1 } ) 
// 複数要素の配列のインデクス– マルチキーインデクス 
>db.articles.ensureIndex( { tags : 1 } )
サブドキュメント(Sub-document) 
インデクス 
• サブドキュメントでのインデクス 
14 
– ドット表記を使用 
{ 
‘_id’ : ObjectId(..), 
‘article_id’ : ObjectId(..), 
‘section’ : ‘schema’, 
‘date’ : ISODate(..), 
‘daily’: { ‘views’ : 45, 
‘comments’ : 150 } 
‘hours’ : { 
0 : { ‘views’ : 10 }, 
1 : { ‘views’ : 2 }, 
… 
23 : { ‘views’ : 14, 
‘comments’ : 10 } 
} 
} 
>db.interactions.ensureIndex( 
{ “daily.comments” : 1} 
} 
>db.interactions.find( 
{“daily.comments” : { $gte : 150} } , 
{ _id:0, “daily.comments” : 1 } 
)
複合(Compound)インデクス 
• 複数の要素をもつインデクス 
15 
//コンソールで表示 
> db.articles.ensureIndex( { author : 1, tags : 1 } ) 
> db.articles.find( { author : ‘Joe D’, tags : ‘MongoDB’} ) 
//さらに次も可能 
> db.articles.find( { author : ‘Joe D’ } ) 
// Author単一のインデックス指定は必要なし 
> db.articles.ensureIndex( { author : 1 } )
ソート処理の順序 
• 単一インデクスの場合はソートは単純 
16 
– B-Treeのいずれからも検索可能 
• { attribute: 1 } もしくは{ attribute: -1 } 
• 複合インデクスの場合はソート順序が重要 
– 作者(author)で検索し、日付でソートをしたい場合 
// 作者(author)は名前順、日付は新しい日付を先にソートしてインデックする 
>db.articles.ensureIndex( { ‘author’ : 1, ‘date’ -1 } )
カバード(Covered)もしくはインデクスのみ 
のクエリー 
• 参照データはインデクスから戻ってくる 
17 
– データベースファイルはアクセスしない 
– 性能の大幅な向上 
– Compoundインデクスでも使用可能 
• プロジェクション(projection)で指定 
> db.users.ensureIndex( { user : 1, password :1 } ) 
> db.user.find({ user:”joe” }, 
{ _id:0, password:1 } 
) 
参考: プロジェクションを使ってクライアントに戻すデータを減らす事も考慮せよ 
(_id=0  Object_id を参照しない)
オプション 
18 
• ユニーク度の制限(unique, dropDups) 
// authorのインデクスはユニークである必要(一つしか存在しない) 
>db.articles.ensureIndex( { ‘author’ : 1}, { unique : true } ) 
• スパース(Sparce) インデクス 
// likesのフィールドを持たないドキュメントが複数あっても良い 
>db.articles.ensureIndex( { ‘author’ : 1, ‘likes’ : 1}, { sparse: true } ) 
* 抜けているフィールドはインデクス内でnull として記録
バックグラウンドでのインデクス生成 
• インデクス生成は長時間かかる事も多い 
• この生成をバックグラウンドに指定する事により他の 
オプレーションに対する影響を最小限に 
• バックグラウンドで複数のインデクスの生成も可能 
• レプリカセットから一旦外したセカンダリーでインデク 
スを生成 
19 
// バックグラウンドでのインデクス生成 
> db.articles.ensureIndex( 
{ ‘author’ : 1, ‘date’ -1 }, 
{background : true} 
)
Explain planコマンド 
• インデクスとオペレーションの分析を行う際に使用 
20 
– どのインデクスが使用されたかを確認 
– どれくらいのドキュメント/オブジェクトがスキャンされたかを 
確認 
– コンソール経由、もしくはコードで表示 
//コンソールで結果を表示する 
> db.articles.find({author:’Joe D'}).explain()
Explain planコマンドの出力(インデクス 
無し) 
21 
{ 
"cursor" : ”BasicCursor", 
"isMultiKey" : false, 
"n" : 12, 
"nscannedObjects" : 25820, 
"nscanned" : 25820, 
… 
"indexOnly" : false, 
… 
"millis" : 27, 
… 
} 
他のタイプ: 
• BasicCursor 
• コレクション全体スキャン 
(インデクス使用せず) 
• BtreeCursor 
• GeoSearchCursor 
• Complex Plan 
• TextCursor
Explain planコマンドの出力 
22 
{ 
"cursor" : "BtreeCursor author_1_date_- 
1", 
"isMultiKey" : false, 
"n" : 12, 
"nscannedObjects" : 12, 
"nscanned" : 12, 
… 
"indexOnly" : false, 
… 
"millis" : 0, 
… 
} 
他のタイプ: 
• BasicCursor 
• コレクション全体スキャン 
• BtreeCursor 
• GeoSearchCursor 
• Complex Plan 
• TextCursor
データベースプロファイラー 
• 遅いクエリー処理の発見 
23 
– すべてを表示する事もオプション指定可能 
– デフォルトは100ms以上の処理の表示 
//プロファイラの結果をコンソールに表示, 0=オフ1=遅い処理のみ2=すべて 
> db.setProfilingLevel(1, 100) 
{ "was" : 0, "slowms" : 100, "ok" : 1 } 
//プロファイル結果の表示 
> show profile 
//もしくは次の方法でも可能 
>db.system.profile.find().pretty()
クエリーの最適化 
• 各クエリーに対して、MongoDBは定期的に有効なイ 
ンデクスをすべて使う。 
• 最適なプランを発見次第、他のインデクスの使用を 
中止 
• 選択されたプランは、一時的にキャッシュされ、他の 
タイプのクエリーにも適用される(1000回分使用され 
る) 
• MongoDB 2.6はクエリー処理に複数のインデクスの 
組み合わせ(intersection)をサポート 
24
他のインデクスタイプ 
25 
• 地理空間(Geospatial)インデクス(2次元球体) 
• テキストインデクス 
• TTLコレクション(期限付き条件) 
• シャーディング向けのハッシュインデクス
地理空間(Geo Spatial)インデクス
2次元球体 
• 地理空間上の位置情報をインデクス化 
27 
– GeoJSON オブジェクトを使用 
– 球体の上での2次元位置情報 
//GeoJSON インデクスのためのオブジェクト構造 
{ 
name: ’MongoDB Palo Alto’, 
location: { type : “Point”, 
coordinates: [ 37.449157 , -122.158574 ] } 
} 
// GeoJSONオブジェクトのインデクス化 
>db.articles.ensureIndex( { location: “2dsphere” } ) 
サポートされるGeoJSON オ 
ブジェクト: 
Point(点) 
LineString(線) 
Polygon(ポリゴン) 
MultiPoint(複数点) 
MultiLineString(複数線) 
MultiPolygon(複数ポリゴン) 
GeometryCollection (位置情 
報コレクション)
記事情報の拡張機能 
• 記事(article)が投稿さ 
28 
れた位置情報を記録す 
る 
• 位置情報はブラウザー 
から 
Articles コレクション 
>db.articles.insert({ 
'text': 'Article 
content…’, 
'date' : ISODate(...), 
'title' : ’Intro to 
MongoDB’, 
'author' : ’Joe D’, 
'tags' : ['mongodb', 
'database', 
'nosql’], 
‘location’ : { 
‘type’ : ‘Point’, 
‘coordinates’ : 
[37.449, -122.158] 
} 
}); 
//位置情報を取得するJavascript機能. 
navigator.geolocation.getCurrentPosition(); 
//GeoJSONデータ構造に変換する必要あり
例 
29 
– 指定した座標値に”近い”場所を検索する 
>db.articles.find( { 
location: { $near : 
{ $geometry : 
{ type : "Point”, coordinates : [37.449, -122.158] } }, 
$maxDistance : 5000 
} 
} )
テキスト検索
テキストインデクス 
• テキストインデクスを使用してコレクション内のド 
31 
キュメントの中にある文字列検索を行う 
• テキストインデクスは任意の文字情報、もしくは 
文字情報の配列でも可 
• テキストインデクスを利用した検索の際には、 
$text オペレータを使用
テキスト検索 
• コレクション一つに対し 
32 
て一つのテキストイン 
デクス 
• $** オペレータを使い、 
コレクション内の文字列 
をインデクス化 
• “weights”を使って文 
字列の重要度を指定 
>db.articles.ensureIndex( 
{title: ”text”, content: ”text”} 
) 
>db.articles.ensureIndex( 
{ "$**" : “text”, 
name : “MyTextIndex”} ) 
>db.articles.ensureIndex( 
{ "$**" : "text”}, 
{ weights : 
{ ”title" : 10, ”content" : 5}, 
name : ”MyTextIndex” } 
) 
オペレータ 
$text, $search, $language, 
$meta
検索 
• $text と$search オペレータを使ってクエリー処理 
• Cursorが戻ってくる 
• $meta を使って結果のスコアを求める 
33 
// Articlesコレクション内を検索 
> db.articles.find ({$text: { $search: ”MongoDB" }}) 
– . 
> db.articles.find( 
{ $text: { $search: "MongoDB" }}, 
{ score: { $meta: "textScore" }, _id:0, title:1 } ) 
{ "title" : "Intro to MongoDB", "score" : 0.75 }
スケーリング
ワーキングセットが物理メモリを超える
いつスケールすべきか? 
• 特定のリソースがマシン、もしくはレプリカ 
セット上でのボトルネックになった場合 
• RAM 
• ディスクI/O 
• ストレージ 
• コンカレンシー(Concurrency)
垂直スケール(スケールアップ)
水平スケール(スケールアウト)
シャーディング 
• ユーザがシャードキーを選択 
• シャードキーはデータレンジを定義 
• シャードキーに従ってデータはシャード毎にパ 
ティションされる
スケーラビリティ 
40 
自動シャーディング 
シャード1 シャード2 シャード3 シャードN 
水平スケール 
• キャパシティを自由に拡張 
• コモディティサーバやクラウドアーキテクチャに最適 
• 容易な運用とコストの明確化がメリット

MongoDB: システム可用性を拡張するインデクス戦略

Editor's Notes

  • #8 Look at 7 documents
  • #9 Queries, inserts and deletes: O(log(n)) time
  • #10 MongoDB's indexes are B-Trees. Lookups (queries), inserts and deletes happen in O(log(n)) time. TODO: Add a page describing what a B-Tree is???
  • #11 So this is helpful, and can speed up queries by a tremendous amount
  • #19 unique applies a uniqueness constant on duplicate values. dropDups will force the server to create a unique index by only keeping the first document found in natural order with a value and dropping all other documents with that value. dropDups will likely result in data loss!!! Make sure you know what it does before you use it. MongoDB doesn't enforce a schema – documents are not required to have the same fields. Sparse indexes only contain entries for documents that have the indexed field. Without sparse, documents without field 'a' have a null entry in the index for that field. With sparse a unique constraint can be applied to a field not shared by all documents. Otherwise multiple 'null' values violate the unique constraint.
  • #22 cursor – the type of cursor used. BasicCursor means no index was used. TODO: Use a real example here instead of made up numbers… n – the number of documents that match the query nscannedObjects – the number of documents that had to be scanned nscanned – the number of items (index entries or documents) examined millis – how long the query took Ratio of n to nscanned should be as close to 1 as possible.
  • #23 cursor – the type of cursor used. BasicCursor means no index was used. TODO: Use a real example here instead of made up numbers… n – the number of documents that match the query nscannedObjects – the number of documents that had to be scanned nscanned – the number of items (index entries or documents) examined millis – how long the query took Ratio of n to nscanned should be as close to 1 as possible.
  • #36 Indexes should be contained in working set.
  • #38 From mainframes, to RAC Oracle servers... People solved problems by adding more resources to a single machine.
  • #39 Large scale operation can be combined with high performance on commodity hardware through horizontal scaling Build - Document oriented database maps perfectly to object oriented languages Scale - MongoDB presents clear path to scalability that isn't ops intensive - Provides same interface for sharded cluster as single instance