[pymongo]ドキュメント数を取得(カウント)する最速の方法を検証。cursor.count()とcount_documents()ってどっちが早い?

2020年3月5日木曜日

t f B! P L

[pymongo]ドキュメント数を取得(カウント)する最速の方法を検証。cursor.count()とcount_documents()ってどっちが早い?

はじめに

pymongoで検索結果のドキュメント数を知る方法に次の2通りのやり方がある。

  1. cursor型のcount()で件数を取得する方法
ret = collection.find(filter={検索条件}).count()
  1. コレクションのcount_documents()関数で取得する方法
ret = collection.count_documents(filter={検索条件})

どっちを使っても、条件に一致するドキュメント数が取得できます。
この記事では、上の2つの方法の内、どちらの方が高速に動くのかを検証してみます。

テストデータ

今回、実行時間の比較で使用するデータ(コレクション)は、次のような「ユーザID」「ユーザ名」と「点数」を持つ一般的な成績表データを使用します。なお、「点数」には1〜1000までのランダムな値を設定しておく。

id name score (ランダム値)
1 ユーザ1 100
2 ユーザ2 950
3 ユーザ3 550

Round1. 1000ドキュメント、filterなし(全件)

1回戦目は、簡単な条件で実行時間を測定してみたいと思います。以下の条件で実行時間を3回計測し、その平均値を比較しています。

  • ドキュメント数: 1000
  • 検索条件: なし

実行結果

この程度の件数であれは、どちらの関数を使用しても同じ時間で結果が返ってきます。

使用関数 実行時間
corsor.count 2.28ms
collection.count_documents 2.85ms

Round2. 10万ドキュメント、filterなし(全件)

2回戦目は、ドキュメント数を一気に増やして10万件で実行時間を比較してみます。

  • ドキュメント数: 10万
  • 検索条件: なし

実行結果

corsor.countの方が50倍近い速さで結果が返ってきています。この結果を見る限りだと、ドキュメント数の取得は、corsor.countを使った方がよさそうですね。

使用関数 実行時間
corsor.count 2.00ms
collection.count_documents 55.34ms

Round3. 10万ドキュメント、filterあり

次のは、検索条件を指定した時の実行時間を比較してみます。

  • ドキュメント数: 10万
  • 検索条件: 全体の「1%」のデータを抽出する検索条件を指定

※ この時の、検索条件を指定する列(score)のカーディナリティは**1%**です。

実行結果

今度は打って変わって、検索条件を指定した場合は、ほんの少しだけcount_documents()が早くなりました。ただ、誤差の範囲なので実行時間は同じと見てよいでしょう。

使用関数 実行時間
corsor.count 71.48ms
collection.count_documents 64.50ms

Round4. 100万ドキュメント、filter・skip・limitあり

ここまでの結論

ここまでの結果から、collection.find(filter={検索条件}).count()でカウントを取得する方が、総合的に早いと言う見解が得られました。

ここでの結果は、あくまで私の環境での実行結果から推測される私的な見解であり、実際は違うかもしれません。そのときはごめんなさい。

単純にコレクションのドキュメント数を知りたい場合

検索条件なしで、 単純にコレクション内の、ドキュメント数を知りたい場合 は、estimated_document_countを使うのが最速です。

pymongoのドキュメントにも、次のように書かれていす

 .. note:: For a fast count of the total documents in a collection see
    :meth:`estimated_document_count`.

実際に測定してみました。

  • 10万ドキュメント
使用関数 実行時間
corsor.count 2.09ms
collection.count_documents 61.10ms
collection.estimated_document_count 2.09ms
  • 1000万ドキュメント
使用関数 実行時間
corsor.count 8.97ms
collection.count_documents 5174.81ms
collection.estimated_document_count 2.05ms

上の結果の通り、estimated_document_count()関数を使った、カウントが最も早いです。

制限事項として、estimated_document_count()はセッションをサポートしていないので、セッションを指定したい時は使用できません。

スポンサーリンク

QooQ