1. ホーム
  2. sql

[解決済み] なぜ大きな Django QuerySet を繰り返し処理すると、大量のメモリを消費するのですか?

2022-08-04 02:10:16

質問

問題のテーブルはおよそ1,000万行を含んでいます。

for event in Event.objects.all():
    print event

この結果、メモリ使用量は4GB程度まで順調に増加し、その時点で行が急速に印刷されるようになりました。最初の行が印刷されるまでの長い遅延には驚きました。ほとんど瞬時に印刷されると思っていたからです。

また、私は Event.objects.iterator() も試してみましたが、同じような挙動でした。

Django が何をメモリにロードしているのか、なぜこのようなことをするのか、理解できません。私は Django がデータベースレベルで結果を繰り返し処理することを期待していました。

私は何を誤解しているのでしょうか?

(関係あるかわかりませんが、PostgreSQLを使用しています)

どのように解決するのですか?

ネイトCは惜しかった。

から ドキュメント :

QuerySetは以下の方法で評価することができます。

  • 反復。QuerySetは反復可能であり、最初に反復するときにそのデータベースクエリを実行します。例えば、これはデータベース内の全エントリーの見出しを表示します。

    for e in Entry.objects.all():
        print e.headline
    
    

つまり、1000 万行は、最初にループに入り、クエリセットの反復形式を取得するときに、一度に取得されるのです。 あなたが経験する待ち時間は、Django がデータベースの行をロードし、実際に反復処理できるものを返す前に、それぞれの行のオブジェクトを生成しているのです。 そして、全てをメモリに収め、結果がこぼれ落ちてくるのです。

ドキュメントを読んだ限りでは iterator() はQuerySetの内部キャッシュ機構をバイパスする以上のものではありません。 1つ1つを処理するのは理にかなっていると思いますが、その場合、逆にデータベースへの個別のアクセスが1,000万回必要です。 たぶん、それほど望ましいことではありません。

大規模なデータセットを効率的に反復処理することは、私たちがまだ完全に理解していないことですが、あなたの目的に役立つと思われるスニペットがいくつか存在します。