0

私たちの GAE アプリは、NDB に別の Web サイトのリレーショナル データベースのローカル コピーを作成します。ユーザー、テーブル、行、フィールドの 4 つのエンティティ タイプがあります。各ユーザーには多数のテーブルがあり、各テーブルには多数の行があり、各行には多数のフィールドがあります。

SomeUser > SomeTable > ARow > AField

したがって、各ユーザーは 1 つのエンティティ グループになります。特定のユーザーのすべてのテーブル (およびその行) を消去できる機能が必要です。~5 操作/秒の競合制限を回避しながら、すべてのテーブルとすべての行を削除する正しい方法は何ですか。

TransactionFailedErrorエンティティ グループで競合が発生したため、現在のコードは s を取得しています。(私が見落としていた詳細は、特定の値に設定された属性「サービス」を持つテーブルのみを削除したいということです)

def delete_tables_for_service(user, service):
    tables = Tables.query(Tables.service == service, ancestor=user.key).fetch(keys_only=True)
    for table in tables:
        keys = []
        keys += Fields.query(ancestor=table).fetch(keys_only=True)
        keys += TableRows.query(ancestor=table).fetch(keys_only=True)
        keys.append(table)
        ndb.delete_multi(keys)
4

2 に答える 2

1

削除するすべてのエンティティが 1 つのエンティティ グループにある場合は、1 つのトランザクションですべてを削除してみてください。明示的なトランザクションがない場合、各削除は独自のトランザクションで発生し、エンティティ グループを変更するには、すべてのトランザクションが (競合と再試行によって) 整列する必要があります。

于 2014-09-15T18:23:12.910 に答える
0

競合ベースであると確信していますか、それとも上記のコードがトランザクション内で実行されるためでしょうか? 迅速な解決策として、再試行回数を増やし、このメソッドのグループ間トランザクションを有効にすることが考えられます。

@ndb.transactional(retries=5, xg=True)

詳細については、 https ://developers.google.com/appengine/docs/python/ndb/transactions を参照してください。それが原因でない場合は、削除を遅延または非同期で実行して、時間をかけて小さなバッチで実行することを検討してください。NDB の秘訣は、大量の作業を頻繁に行うのではなく、小さなバーストの作業を定期的に行うことです。そのコードを非同期の作業単位に変換する 1 つの方法を次に示します。

def delete_tables_for_service(user, service):
    tables = Tables.query(Tables.service == service, ancestor=user.key).fetch(keys_only=True)
    for table in tables:
        # Delete fields
        fields_keys = Fields.query(ancestor=table).fetch(keys_only=True)
        ndb.delete_multi_async(fields_keys)

        # Delete table rows
        table_rows_keys = TableRows.query(ancestor=table).fetch(keys_only=True)
        ndb.delete_multi_async(table_rows_keys)

        # Finally delete table itself
        ndb.delete_async(table.key)

削除、再試行、失敗をより細かく制御したい場合は、タスク キューを使用するか、単純に遅延ライブラリ ( https://developers.google.com/appengine/articles/deferred )を使用できます。

  1. app.yaml で deferred を有効にする
  2. ndb.delete_multi への呼び出しを deferred に変更します。

    def delete_tables_for_service(user, service):
        tables = Tables.query(Tables.service == service, ancestor=user.key).fetch(keys_only=True)
        for table in tables:
            keys = []
            keys += Fields.query(ancestor=table).fetch(keys_only=True)
            keys += TableRows.query(ancestor=table).fetch(keys_only=True)
            keys.append(table) 
            deferred.defer(_deferred_delete_tables_for_keys, keys)
    
    def _deferred_delete_tables_for_keys(keys):
        ndb.delete_multi(keys)
    
于 2014-09-15T16:30:04.790 に答える