SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

EnterpriseZine(エンタープライズジン)編集部では、情報システム担当、セキュリティ担当の方々向けに、EnterpriseZine Day、Security Online Day、DataTechという、3つのイベントを開催しております。それぞれ編集部独自の切り口で、業界トレンドや最新事例を網羅。最新の動向を知ることができる場として、好評を得ています。

最新イベントはこちら!

Security Online Day 2025 春の陣(開催予定)

2025年3月18日(火)オンライン開催

EnterpriseZine(エンタープライズジン)編集部では、情報システム担当、セキュリティ担当の方々向けの講座「EnterpriseZine Academy」や、すべてのITパーソンに向けた「新エバンジェリスト養成講座」などの講座を企画しています。EnterpriseZine編集部ならではの切り口・企画・講師セレクトで、明日を担うIT人材の育成をミッションに展開しております。

お申し込み受付中!

EnterpriseZine(エンタープライズジン)

EnterpriseZine編集部が最旬ITトピックの深層に迫る。ここでしか読めない、エンタープライズITの最新トピックをお届けします。

『EnterpriseZine Press』

2024年秋号(EnterpriseZine Press 2024 Autumn)特集「生成AI時代に考える“真のDX人材育成”──『スキル策定』『実践』2つの観点で紐解く」

脱初心者!MongoDB中級編

MongoDBの単体性能(後編)


 第1回ではMongoDBの単体性能の重要性、そして「何が遅いのか」の調べ方について説明してきました。第二回では「なぜ遅いのか」について考えてきましょう。

 文中の中で「MMAP」と記載した場合、これはMongoDB 2.xもしくはMongoDB 3.0のMMAPv1ストレージエンジンのことを指します。また「WiredTiger」と記載した場合は、MongoDB 3.0のWiredTigerストレージエンジンのことを指します。

コンピュータが遅いとはどういうことなのか

 MongoDBに限らずコンピュータシステムが遅いというのはどういうことなのでしょうか?

 1つ目は、コンピュータのリソースが限界に達して何かを待っている状態です。コンピュータにはCPU、メモリ、ディスク、ネットワークといったリソースがあります。例えば、多くのプロセスで大量の計算をした時には、CPUの使用が限界に達して、結果としてCPUを使えずに待たされる処理が出てきます。メモリであれば、メモリ量が限界に達してディスクからデータを読むことになり、ディスクのIOを待つという事になります。

 MongoDBの場合はディスクIOを待つ場合が多く、CPUネックになることは複雑な集計の時を除いてほとんどありません。それはJOINや副問い合わせなどの複雑な参照クエリが提供されていないためです。また、単体構成であればネットワークがネックになることもほとんどありません。

 2つ目は、非効率な処理をしているです。MongoDBの場合は、「本来応答を待たなくてよいのに応答を待っている」や「必要以上にロックを取って他の計算が待たされる」といった非効率な処理により期待どおりの性能が出ない事が多いです。

 では具体的にMongoDBが遅くなる原因を参照と更新で分けて説明していきましょう。

[参照の場合] データがメモリに載っていない

 一般的にデータをメモリから読む場合とディスクから読む場合では100~1万倍速度が違うと言われています。参照クエリではメモリにデータあればメモリを読み込むだけでよいですが、メモリになければディスクIOを待つことになります。

 どれだけメモリにデータが載っているかは、mongostatを見ればわかります。resの項目が実際に利用している物理メモリ量です。この値とデータのワーキングセット(インデックスとクエリで必要となるデータ)のサイズを比較して、ワーキングセットのほうが大きければメモリに載りきっていないことになります。特にインデックスがメモリに載らない場合は読み込み性能は著しく低下しますので、最低でもインデックスはメモリに載るようにしましょう。インデックスのサイズは db.コレクション.stats()の出力結果を見ればわかります。

 この問題が発生しているかどうかは、MMAPあればmongostatのfaultsの項目を見ればわかります。この項目には、秒間のページフォルト、つまりメモリに無くディスクを読みにいった回数が表示されます。

 十分にメモリがあってもMongoDBの起動直後は注意が必要です。MongoDBは起動した状態ではメモリには一切データは載っておらず、クエリでデータが読み込まれていくと次第にメモリに載っていきます。これを回避したければtouchコマンドを用いてコレクションをメモリに載せることができます。

 上記の問題はデータファイルにフラグメンテーションが発生している時により顕著になります。MongoDBではドキュメントを消したり肥大化により移動が発生すると、データファイルに穴ができます。これがフラグメンテーションです。これが発生すると「穴ごと」メモリに乗せてしまうため、実際のデータサイズよりも大きなメモリを使うことになり、よりメモリからあふれる可能性がでてきます。これはdb.コレクション.stats()db.stats()のdataSizeとstorageSizeデータサイズを比較するとわかります。またこの問題はMMAPでのみ発生します。

[参照の場合] インデックスがない

 これは多くの他のDBMSと同じですが、インデックスを使わない検索は、すべてのドキュメントの中を開けて調べることになりディスクIOが多発します。これを「フルスキャン」といいます。

 クエリがフルスキャンしているかどうかは、explain()でわかります。

 explain()の実行例は以下の通りです。

db.mycol.find({mykey:98}).explain() 

 explain()はそのクエリの実行計画を示します。MongoDBの実行計画はどのインデックスを選ぶかを決めることです。以下がexplain()の実行結果例です。今回はMongoDB 3.0の結果を抜粋して記載します。

{
    "queryPlanner" : {
     ...
        "winningPlan" : {         # ←選択された実行計画
            "stage" : "COLLSCAN", # ←フルスキャンしている
            "filter" : {
                "mykey" : {
                       "$eq" : 98
                }

 上記の例では、winningPlanという箇所に、最終的に選ばれた実行計画が表示され、その中身に"stage" : "COLLSCAN" とあることからフルスキャンしていることがわかります。

 このクエリを速くしたければ、mykeyというキーにインデックを貼ることでディスクIOを最小にすることができます。

 MongoDB 3.0からexplain()の結果が大きく変わりました。MongoDB 3.0から実行計画の計画フェーズと実行状況を明確に区別して表示できるようになり、表示項目も非常に増えています。詳しくは公式マニュアルのcursor.explainを確認して下さい。

次のページ
[更新の場合] 更新ロックが多い

この記事は参考になりましたか?

  • Facebook
  • X
  • Pocket
  • note
脱初心者!MongoDB中級編連載記事一覧

もっと読む

この記事の著者

渡部徹太郎(ワタナベテツタロウ)

 日本MongoDBユーザ会所属 2012年からMongoDB勉強会開催、記事執筆、セミナ講演を精力的に実施。仕事でもMongoDBのトレーニングやコンサルティングを実施。日本で一番MongoDBを情報発信していると自負している。現在はWeb企業でビッグデータ基盤のエンジニアをしている。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

EnterpriseZine(エンタープライズジン)
https://enterprisezine.jp/article/detail/7098 2015/09/01 20:00

Job Board

AD

おすすめ

アクセスランキング

アクセスランキング

イベント

EnterpriseZine(エンタープライズジン)編集部では、情報システム担当、セキュリティ担当の方々向けに、EnterpriseZine Day、Security Online Day、DataTechという、3つのイベントを開催しております。それぞれ編集部独自の切り口で、業界トレンドや最新事例を網羅。最新の動向を知ることができる場として、好評を得ています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング