Google App Engine には適切なサイズのデータベース (50,000 を超えるエンティティ) があり、そこから古いデータを消去したいと考えています。計画は、不要になったエンティティを繰り返し処理する遅延タスクを作成し、それらをバッチで削除することでした。
厄介なことの 1 つは、エンティティには削除したい子エンティティもあるということです。これは問題ありません。これらのエンティティのデータストアをクエリし、親と同時にドロップします。
query = ParentKind.all()
query.count(100)
query.filter('bar =', 'foo')
to_delete = []
for entity in enumerate(query):
to_delete.append(entity)
to_delete.extend(ChildKindA.all().ancestor(entity).fetch(100))
to_delete.extend(ChildKindB.all().ancestor(entity).fetch(100))
db.delete(to_delete)
ParentKind
一度に 100 個のエンティティを削除するように制限しました。それぞれParentKind
に合計で約 40 の子ChildKindA
とChildKindB
エンティティがあり、おそらく 4000 のエンティティでした。
これは当時は合理的と思われましたが、テストとして 1 つのバッチを実行したところ、結果のクエリの実行に 9 秒かかり、データストアへのアクセスに課金対象の CPU 時間で1933秒が費やされました。
これはかなり厳しいように思えます -- エンティティごとに 0.5 秒の請求が可能です! -- しかし、何が間違っているのか完全にはわかりません。それは単にバッチのサイズですか?祖先クエリは特に遅いですか? それとも、削除 (および実際にはすべてのデータストア アクセス) が単に糖蜜のように遅いのでしょうか?
アップデート
クエリを に変更しました。keys_only
これにより、1 つのバッチの実行時間が 4.5 秒に短縮されましたが、それでも CPU 時間は約 1900 秒かかりました。
次に、Appstats をアプリにインストールし (ありがとう、kevpie)、より小さいサイズのバッチを実行しました。10 個の親エンティティで、合計で最大 450 個のエンティティになります。更新されたコードは次のとおりです。
query = ParentKind.all(keys_only=True)
query.count(10)
query.filter('bar =', 'foo')
to_delete = []
for entity in enumerate(query):
to_delete.append(entity)
to_delete.extend(ChildKindA.all(keys_only=True).ancestor(entity).fetch(100))
to_delete.extend(ChildKindB.all(keys_only=True).ancestor(entity).fetch(100))
db.delete(to_delete)
Appstats の結果:
service.call #RPCs real time api time
datastore_v3.RunQuery 22 352ms 555ms
datastore_v3.Delete 1 366ms 132825ms
taskqueue.BulkAdd 1 7ms 0ms
Delete
呼び出しは、操作の中で最もコストのかかる部分です。
これを回避する方法はありますか?Nick Johnson 氏は、現時点では一括削除ハンドラを使用するのが最速の削除方法であると述べましたが、理想的には、同じ種類のすべてのbar = foo
エンティティを削除するのではなく、最初のクエリに一致し、その子であるエンティティだけを削除したいと考えています。