2010-12-11 13 views
6

Mam dość powszechny problem z projektowaniem: muszę zaimplementować dziennik historii (ścieżka audytu) dla rekordów w Google App Engine. Dziennik historii musi być ustrukturyzowany, tzn. Nie mogę dołączyć wszystkich zmian do jakiegoś swobodnego tekstu i przechowywać w polu ciągu.Wdrażanie skutecznej ścieżki audytu rekordowych zmian w Google App Engine - wzorce projektowe

Rozważyłem następujące opcje dla modelu historii i po zauważeniu problemów z wydajnością w opcji nr 1, zdecydowałem się zaimplementować opcję # 3. Ale mają pewne wątpliwości, czy to rozwiązanie jest wydajne i skalowalne. Na przykład: czy istnieje ryzyko, że wydajność pogorszy się znacząco wraz ze wzrostem liczby właściwości dynamicznych w opcji nr 3?

Czy dysponujesz większą wiedzą na temat zalet/wad dla każdej opcji lub czy możesz zaproponować inne wzorce projektowe ścieżki audytu, które mają zastosowanie do charakterystyki bazy danych Google App Engine?

  1. Zastosowanie klasyczny SQL "master-detail" relacja
    • Plusy
      • proste do zrozumienia dla programistów baz danych z SQL tle
      • czyste: bezpośredni definicja zapis historii i jej własności
      • wyszukiwania wydajność: łatwe przeszukiwanie historii (można używać indeksów)
      • rozwiązywanie problemów: łatwy dostęp za pomocą narzędzi administracyjnych (_ah/admin)
    • Wady
      • jeden-do-wielu relacjach często nie są zalecane, aby być realizowane w ten sposób w GAE DB
      • wydajność
      • odczytu: nadmierna ilość operacji odczytu rekordu pokazać długą ścieżkę audytu np w okienku szczegółów dużej listy rekordów.
  2. historia Przechowywać w polu BLOB (marynowane struktury python)
    • Plusy
      • prosty do wdrożenia i elastyczne wydajność
      • odczytu: bardzo wydajny
    • Wady
      • wydajność zapytań: Nie można wyszukiwać za pomocą indeksów
      • rozwiązywanie problemów: nie można sprawdzić dane przez widza Administrator dB (_ah/admin)
      • nieczystego nie tak łatwo zrozumieć/zaakceptować dla programistów SQL (uznają to brzydki)
  3. Historia sklepu w dynamicznych właściwościach Expando. Na przykład. dla każdego pola fieldName utwórz pola history_fieldName_n (gdzie n = < 0 ..N> to numer zapisu historii)
    • Plusy:
      • prosta: łatwe do wdrożenia i zrozumieć
      • rozwiązywanie problemów: można odczytać wszystkie właściwości historii poprzez interfejs administratora
      • wydajność odczytu: Operacja jeden odczytu do dostać rekord
    • Wady:
        wydajność
      • wyszukiwania: nie można po prostu przeglądać rekordy Historia (oni hAV e inna nazwa)
      • nie
      • zbyt czysty: liczba właściwości mogą być mylące, na pierwszy rzut oka
  4. historię Przechowywać w pewnym zestawem pól wykazu w głównym rekordzie. Na przykład. dla każdego fieldName stworzyć fieldName_history lista pól
    • Plusy:
      • czyste: bezpośredni definicja właściwości historii
      • prosta: łatwe do zrozumienia dla programistów SQL
      • wydajność
      • odczytu: operacja przeczytać, aby uzyskać zapis
    • Wady:
        wydajność
      • wyszukiwania: można wyszukiwać za pomocą indeksów O dla rekordów, które kiedykolwiek miały jakąś wartość i nie mogą wyszukiwać rekordów mających kombinację wartości w określonym czasie;
      • rozwiązywania problemów: list kontrolnych jest trudny w opiekunie db widza

Odpowiedz

3

Jeśli musiałbym wybrać chciałbym przejść do opcji 1. brzmi to jak (jeśli nie więcej) wydajnych dla inne opcje. Wszystkie inne opcje mają jedynie zalety prędkości w określonych okolicznościach (małe lub bardzo duże zestawy zmian). Zapewni to również dużą elastyczność (z większą łatwością), taką jak usuwanie historii po x dniach lub historii zapytań w różnych modelach. Upewnij się, że tworzysz elementy historii jako dziecko zmienionego podmiotu w tej samej transakcji, aby zagwarantować spójność. Możesz skończyć z jednym z nich:

class HistoryEventFieldLevel(db.Model): 
    # parent, you don't have to define this 
    date = db.DateTime() 
    model = db.StringProperty() 
    property = db.StringProperty() # Name of changed property 
    action = db.EnumProperty(['insert', 'update', 'delete']) 
    old = db.PickleProperty() # Old value for field, empty on insert 
    new = db.PickleProperty() # New value for field, empty on delete 

class HistoryEventModelLevel(db.Model): 
    # parent, you don't have to define this 
    date = db.DateTime() 
    model = db.StringProperty() 
    action = db.EnumProperty(['insert', 'update', 'delete']) 
    change = db.PickleProperty() # Dictionary with changed fields as keys and tuples (old value, new value) as values