ORMからのデータベース挿入の高速化
-
05-07-2019 - |
質問
私はDjangoビューを持っています。これは、ループ内に500〜5000個の新しいデータベースINSERTSを作成します。問題は、本当に遅いことです! Postgres 8.3では1分あたり約100の挿入を取得しています。以前はより小さなハードウェア(より小さなEC2インスタンス)でMySQLを使用していましたが、この種の速度の問題は一度もありませんでした。
詳細: Ubuntu Server 9.04上のPostgres 8.3。 サーバーは「大」ですEBS(ext3)上のデータベースを備えたAmazon EC2-11GB / 20GB。
こちらは私のpostgresql.confの一部です-さらに必要な場合はお知らせください
shared_buffers = 4000MB
effective_cache_size = 7128MB
私のpython:
for k in kw:
k = k.lower()
p = ProfileKeyword(profile=self)
logging.debug(k)
p.keyword, created = Keyword.objects.get_or_create(keyword=k, defaults={'keyword':k,})
if not created and ProfileKeyword.objects.filter(profile=self, keyword=p.keyword).count():
#checking created is just a small optimization to save some database hits on new keywords
pass #duplicate entry
else:
p.save()
上からの出力:
top - 16:56:22 up 21 days, 20:55, 4 users, load average: 0.99, 1.01, 0.94
Tasks: 68 total, 1 running, 67 sleeping, 0 stopped, 0 zombie
Cpu(s): 5.8%us, 0.2%sy, 0.0%ni, 90.5%id, 0.7%wa, 0.0%hi, 0.0%si, 2.8%st
Mem: 15736360k total, 12527788k used, 3208572k free, 332188k buffers
Swap: 0k total, 0k used, 0k free, 11322048k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
14767 postgres 25 0 4164m 117m 114m S 22 0.8 2:52.00 postgres
1 root 20 0 4024 700 592 S 0 0.0 0:01.09 init
2 root RT 0 0 0 0 S 0 0.0 0:11.76 migration/0
3 root 34 19 0 0 0 S 0 0.0 0:00.00 ksoftirqd/0
4 root RT 0 0 0 0 S 0 0.0 0:00.00 watchdog/0
5 root 10 -5 0 0 0 S 0 0.0 0:00.08 events/0
6 root 11 -5 0 0 0 S 0 0.0 0:00.00 khelper
7 root 10 -5 0 0 0 S 0 0.0 0:00.00 kthread
9 root 10 -5 0 0 0 S 0 0.0 0:00.00 xenwatch
10 root 10 -5 0 0 0 S 0 0.0 0:00.00 xenbus
18 root RT -5 0 0 0 S 0 0.0 0:11.84 migration/1
19 root 34 19 0 0 0 S 0 0.0 0:00.01 ksoftirqd/1
その他の詳細が役立つかどうか教えてください。
解決
まず、ORM操作は常に純粋なSQLよりも遅くなります。 ORMコードで大規模なデータベースの更新プログラムを作成し、それを実行するように設定したことがありますが、ほんの数分で完了した数時間後に終了しました。 SQLで書き直した後、全体が1分未満で実行されました。
第二に、ここでのコードは、データセットのすべての行に対して最大4つの個別のデータベース操作を実行していることに注意してください-get_or_createの get
、または create
、フィルターの count
、最後に save
。これは多くのデータベースアクセスです。
最大5000個のオブジェクトはそれほど大きくないことを念頭に置いて、開始時にデータセット全体をメモリに読み込むことができるはずです。次に、単一の filter
を実行して、既存のすべてのKeywordオブジェクトを一度に取得し、キーワード get_or_create
に膨大な数のクエリを保存し、重複をインスタンス化する必要もありません。そもそもProfileKeywords。
他のヒント
このようなバルク操作が遅い一般的な理由の1つは、各挿入が独自のトランザクションで発生することです。それらすべてを単一のトランザクションで発生させることができれば、はるかに高速になります。