Czy złą praktyką jest agregowanie danych z różnych tabel w jedną?

12

tło

Piszę wiele dużych raportów i ogólnie prowadzę dużą dokumentację medyczną DB (piszę SP, funkcje, zadania itp.). Oryginalny schemat i oprogramowanie, które go używa, pochodzi od innego dostawcy, więc nie mogę wiele zmienić strukturalnie. Istnieje wiele zapisów, które wymagają śledzenia, takich jak laboratoria, procedury, szczepionki itp. I są one rozrzucone po dziesiątkach tabel, z których wiele jest rozdętych i źle indeksowanych (udało mi się to nieco naprawić).

Problem

Problem polega na tym, że ponieważ mamy niewielką kontrolę nad bazą danych, a ponieważ może ona zmieniać się z dowolnej aktualizacji lub poprawki, sprawia, że ​​pisanie i obsługa tych raportów jest trudna i żmudna - szczególnie, gdy nakładają się na siebie duże nakłady. Wystarczy jedna łatka i utknąłem przepisując duże części tuzina raportów. Ponadto zapytania szybko stają się zaciemnione i powolne w miarę łączenia, zagnieżdżania zaznaczeń i nakładania stosów.

Moje „rozwiązanie”

Mój plan polegał na zapisaniu wszystkich tych rekordów w jednej tabeli „catch-all” i zapisaniu wyzwalaczy na oryginalnych tabelach w celu utrzymania rekordów w tej tabeli zbiorczej. Oczywiście musiałbym upewnić się, że moje wyzwalacze były nienaruszone po aktualizacji, ale byłoby to o wiele łatwiejsze z punktu widzenia łatwości konserwacji i po prostu odwoływania się do danych.

Tabela byłaby cienka i długa, przechowująca tylko wymagane dane, mniej więcej tak:

CREATE TABLE dbo.HCM_Event_Log (
    id INT IDENTITY,
    type_id INT NULL,
    orig_id VARCHAR(36) NULL,
    patient_id UNIQUEIDENTIFIER NOT NULL,
    visit_id UNIQUEIDENTIFIER NULL,
    lookup_id VARCHAR(50) NULL,
    status VARCHAR(15) NULL,
    ordered_datetime DATETIME NULL,
    completed_datetime DATETIME NULL,
    CONSTRAINT PK_HCM_Event_Log PRIMARY KEY CLUSTERED (id)
)

Potem miałbym różne tabele relacyjne dla takich rzeczy jak ID_typu i grupowanie elementów.

Zaczynam zastanawiać się nad tym pomysłem, ponieważ kilka z tych tabel jest napisanych dość często, SP i raporty, które piszę, również często odnoszą się do danych. Dlatego obawiam się, że ta tabela stanie się koszmarem blokowania rekordów i wydajności przy tak dużej liczbie operacji we / wy.

Moje pytanie

Czy to zły czy dobry pomysł? Zdaję sobie sprawę, że każda sytuacja jest inna w SQL Server (2008 R2 Standard Edition BTW) i reguła „czasami”, ale tak naprawdę szukam tylko ogólnych porad.

Zacząłem rozważać skorzystanie z brokera usług, ale wykonuję tylko proste aktualizacje / wstawki ( zobacz alternatywę dla zaakceptowanej odpowiedzi ). Dane w wielu przypadkach muszą być przesyłane w czasie rzeczywistym, więc użycie kopii zapasowej bazy danych naprawdę nie działałoby. Wydajność już stanowi dla nas pewien problem, ale większość z nich dotyczy sprzętu, który wkrótce zostanie rozwiązany.

jreed121
źródło
1
Czy możesz egzekwować zaplanowane przestoje? Jeśli żadna z tych aktualizacji nie usunie wyzwalacza, nie zaktualizujesz swoich agregatów, co może prowadzić do złych danych.
Erik,
Zastanawiasz się nad umieszczeniem wszystkich informacji o laboratoriach, procedurach, szczepionkach i pacjentach w jednym miejscu? Kiepski pomysł. Możesz użyć schematu gwiaździstego, jeśli odpowiada to rodzajowi zapytań, które prowadzisz.
Michael Green
1
Czy zastanawiałeś się nad tworzeniem indeksowanych widoków? Umieściłoby to logiczną warstwę między twoim kodem a kodem dostawcy, dzięki czemu możesz po prostu zaktualizować widok, jeśli dostawca zmieni rzeczy pod spodem. Ponadto indeksowane widoki zostaną wstępnie wypełnione i zapewnią dobrą wydajność odczytu. Jednym z większych rozważań przy wykonywaniu tego jest to, ile obciąża operacje zapisu tabel bazy danych dostawcy. Byłoby to jednak prawdopodobnie czystsze i łatwiejsze w utrzymaniu rozwiązanie niż używanie wyzwalaczy itp.
Micah Nikkel
Przepraszamy za spóźnioną odpowiedź, dziękuję za opinie. @Erik - Tak, zaplanowaliśmy aktualizacje i sprawdzam, czy wszystkie moje poprzednie zmiany są nadal wprowadzone za pomocą serii skryptów listy kontrolnej, które uruchamiam, więc nie będzie żadnych niespodzianek i zachowam skrypty CREATE dla wszystkie wyzwalacze.
jreed121
@MichaelGreen - przyjrzę się schematowi gwiazd, ale jestem ciekawy, dlaczego uważasz, że posiadanie wszystkich danych w jednej tabeli jest złym pomysłem? Środowisko aplikacji jest całkowicie odizolowane w sieci VPN, w każdym razie nie jest dostępne poza siecią. Jeśli coś pójdzie nie tak ze stołem, to nie koniec świata, ponieważ mógłbym po prostu wszystko do niego zapisać. Tabela nie będzie używana do danych o znaczeniu krytycznym, a przynajmniej nie będzie to jedyne ani podstawowe miejsce przechowywania tych danych.
jreed121

Odpowiedzi:

8

Jeśli dobrze cię zrozumiałem,

  • masz duży system innej firmy,
  • nie masz nad tym dużej kontroli,
  • tworzysz złożone raporty, które odczytują dane bezpośrednio z tej zewnętrznej bazy danych,
  • Twoje zapytania zależą od wewnętrznej struktury zewnętrznej bazy danych.

Chciałbym podejść do tego w ten sposób:

  • Skonfiguruj własną oddzielną bazę danych, nad którą mam pełną kontrolę.
  • Skonfiguruj proces synchronizacji, który odczytuje dane z odpowiednich tabel i kolumn z bazy danych innych firm oraz wstawia / aktualizuje do mojej.
  • Rozwijaj moje złożone raporty w oparciu o stabilną strukturę mojej bazy danych.

W takim przypadku możesz dostosować strukturę i indeksy swojej bazy danych, aby poprawić wydajność raportów, bez wpływu na system innej firmy. O ile oryginalna struktura danych nie zmieni się gwałtownie, logika zapytań dotyczących raportów nie zmieni się, jeśli baza danych innej firmy ulegnie zmianie. Trzeba będzie dostosować tylko proces synchronizacji.

Proces synchronizacji jest w rzeczywistości procesem konwersji - konwertujesz dane z zewnętrznych baz danych na potrzebną strukturę. Częścią tego procesu konwersji może być naprawienie wszelkich problemów z normalizacją, które może mieć oryginalna baza danych innej firmy. Tylko ta część systemu musi znać wewnętrzną strukturę systemu zewnętrznego i zależeć od niej. Główne raporty i główne zapytania zależą tylko od bazy danych.

Tak więc, głównym celem jest - oddzielenie i ograniczenie części systemu, która zależy od wewnętrznych elementów systemu innej firmy.

aktualizacja

Odnośnie wymagań w czasie rzeczywistym. BTW, zawsze myślałem, że definicja „w czasie rzeczywistym” to „gwarantowany czas reakcji”, a nie „jakiś mały czas reakcji”. Oczywiście zależy to od zastosowania. W mojej praktyce wystarczy zsynchronizować dwie bazy danych w ciągu minuty od wykrytej zmiany. Jeśli użytkownik zobaczy raport na ekranie i pewne podstawowe zmiany danych, raport należy jakoś ponownie uruchomić, aby odzwierciedlić tę zmianę. Możesz sondować zmiany lub odsłuchiwać jakieś zdarzenie / wiadomość, nadal należy ponownie wykonać zapytanie dotyczące raportu, aby wyświetlić najnowsze zmiany.

Już zamierzasz pisać wyzwalacze, aby przechwytywać zmiany w oryginalnych tabelach i zapisywać je w jednej tabeli ogólnej. Przechwytuj zmiany zgodnie z zamierzeniami, ale zapisuj je w odpowiednio znormalizowanych tabelach, a nie w jednej tabeli.

Jest to więc skrajny przypadek - konwersja struktury danych firm zewnętrznych na wewnętrzną strukturę danych odbywa się w wyzwalaczach uruchamianych w INSERT/UPDATE/DELETEtabelach firm zewnętrznych. To może być trudne. Kod wyzwalaczy zależałby od wewnętrznej struktury obu systemów. Jeżeli konwersja nie jest trywialna, może opóźnić oryginał INSERT/UPDATE/DELETEdo momentu jego awarii. Jeśli w twoim wyzwalaczu jest błąd, może to wpłynąć na pierwotną transakcję aż do momentu jej niepowodzenia. Jeśli zmieni się system innej firmy, może to spowodować uszkodzenie wyzwalacza, co spowodowałoby niepowodzenie transakcji systemu zewnętrznego.

Mniej skrajny przypadek. Aby kod twoich wyzwalaczy był prostszy i mniej podatny na błędy, napisz wszystkie przechwycone zmiany do niektórych tabel pomostowych / kontrolnych / różnicowych, ustaw flagę / wyślij komunikat o oczekujących zmianach i uruchom główny proces konwersji, który przejdzie za pomocą tych tabel pośrednich i wykonaj konwersję. Najważniejsze jest to, że potencjalnie ciężki proces konwersji powinien nastąpić poza zakresem oryginalnej transakcji.

Na drugi rzut oka wygląda prawie jak twoja oryginalna sugestia w pytaniu. Różnica polega jednak na tym, że wszystkie tabele przechwytywania przechowują dane tylko tymczasowo; ilość danych jest niewielka - tylko to się zmieniło; nie musi to być pojedynczy stół; ostatecznie dane będą przechowywane w osobnych, odpowiednio znormalizowanych stałych tabelach, nad którymi masz pełną kontrolę, które są niezależne od systemu zewnętrznego i które możesz dostroić do swoich zapytań.

Vladimir Baranov
źródło
Jeśli korzystasz z trasy przesyłania partii, odnieśliśmy sukces dzięki funkcji śledzenia zmian (i zmiany przechwytywania danych, w zależności od potrzeb) przy dość dużej liczbie transakcji (100 000 dziennie). Jest to prostsze niż implementacja własnych tabel pomostowych / audytowych / różnicowych i można je wdrożyć bez zmiany kodu aplikacji ani wyzwalaczy.
Michael Green
Niezależnie od tego, czy są to wyzwalacze, czy CDC, jedynym sposobem, aby naprawdę zbliżyć się do czasu rzeczywistego, jest streaming lub kolejkowanie. Oparty na kolejkach jest dobrym kompromisem dla opóźnienia i efektywności kosztowej. Twój czas zostanie poświęcony na metody szybszego przetwarzania kolejki. pozostawiając większość pracy asynchroniczną z aplikacji i mniej obciążając transakcje użytkownika. W przeszłości robiłem to samo przeciwko Allscripts Sunrise EMR za pomocą usługi, która przetwarzała kolejkę za pomocą kilku równoległych wywołań foreach C #. typowe opóźnienie przetwarzania nowych danych i udostępniania ich w magazynie wynosiło
Brad D
Być może powiedziałem ponad „w czasie rzeczywistym”, nie jestem zbytnio zainteresowany milisekundami, a nawet 5 sekundami, ale mam wiele zapytań, na których nasi pracownicy polegają w celu zwiększenia przepływu pracy. Jeśli klient coś mu zrobił (procedura, szczepienie itp.), Musimy to pokazać w krótkim czasie. Konwersje są trywialne i / lub nawet nie są konwersjami. Nie przejmuję się zbytnio zmianami w tabelach dostawców, ponieważ nie zmieniają się tak często i muszę to zrobić teraz, ale pomyślałem, że łatwiej jest zaktualizować / odtworzyć jeden wyzwalacz niż tuzin raportów / zapytań / SPs. Po każdej aktualizacji uruchamiam kontrole.
jreed121,
@ jreed121, ja też myślę, że to jest łatwiejsze do aktualizacji wyzwalacza (s) niż raportów. Prawdopodobnie będziesz mieć wyzwalacz w każdej tabeli źródłowej, aby uchwycić zmiany, więc prawdopodobnie będzie to więcej niż jeden wyzwalacz. Nie próbuj jednak zapisywać wszystkich tych przechwyconych zmian w jednej ogromnej, zdormalizowanej tabeli. Zapisz je w odpowiednio znormalizowanym zestawie tabel. Twoje raporty powinny opierać się na tych znormalizowanych tabelach, które kontrolujesz, i nie powinny zależeć od oryginalnych tabel, które mogą ulec zmianie.
Vladimir Baranov,
3

Zasadniczo umieść go w znormalizowanym zestawie tabel, abyś mógł dostosować etap importowania zamiast zmieniać złożone raporty i zapytania. Ale dane powinny być nadal znormalizowane, co będzie wymagało wielu tabel (ale z dobrymi indeksami).

Jak wspomnieli inni, nie używaj wyzwalaczy, synchronizuj partiami.

Nie martw się o wiele sprzężeń, gdy dane są normalizowane i odpowiednio indeksowane, nie powodują znacznych kosztów ani obciążeń związanych z zarządzaniem.

Czas na denormalizację w coś takiego jak hurtownia danych to czas, kiedy trzeba mieć możliwość wykonania wielu różnych zapytań o dane, których nie można przewidzieć. Ma swoje wady i koszty ogólne i powinien być używany w stosownych przypadkach, a nie jako codzienna sprawa.

JamesRyan
źródło
3

Pracowałem z bardzo podobną sytuacją w przeszłości w firmie produkcyjnej 24x7 i ostatecznie zdecydowałem się na replikację transakcyjną. Możliwe jest skonfigurowanie replikacji DDL tak, aby można było wypychać wszelkie zmiany, które zmieniają subskrybent. Oczywiście są plusy i minusy wszystkiego i musisz je zważyć, aby określić, co możesz wesprzeć w stosunku do tego, co działa najlepiej dla firmy.

Z dobrej strony:

  1. „W czasie rzeczywistym” ogranicza się tylko do wydajności zatwierdzania transakcji sieciowych i transakcji przez subskrybenta. Z mojego doświadczenia z umiarkowanie wysokim systemem TPS, byliśmy replikowani w ciągu mniej niż 10 sekund danych „w czasie rzeczywistym”.
  2. Rozdzielenie obciążeń. Aktualnie używasz mieszanego obciążenia na jednym serwerze. Jeśli potrafisz rozdzielić te dwa problemy, możesz być w stanie uzyskać korzyści wydajnościowe w obu systemach po usunięciu jednego obciążenia z równania
  3. Kontrola. Będziesz mógł wprowadzać modyfikacje indeksowania / statystyki / konserwacji w celu dostosowania do obciążenia raportowaniem.

Istnieją jednak wady:

  1. Koszt. Kolejna licencja i więcej sprzętu (wirtualnego lub innego).
  2. Replikacja Działa świetnie po prawidłowym skonfigurowaniu, ale dotarcie do tego punktu może być kłopotliwe.
  3. Konserwacja. Jeśli dokonasz szkodliwych zmian w strukturach (np. Upuścisz indeks), zostaną one zwrócone po zastosowaniu migawki (po zmianie publikacji lub zmianie artykułów).
swasheck
źródło
2

Mój plan polegał na zapisaniu wszystkich tych rekordów w jednej tabeli „catch-all” i zapisaniu wyzwalaczy na oryginalnych tabelach w celu utrzymania rekordów w tej tabeli zbiorczej.

Wyzwalacze mają tak wiele problemów, że powinieneś ich unikać:

  • Błąd w wyzwalaczu może spowodować przerwanie oryginalnej transakcji
  • Wyzwalacze, które poprawnie obsługują operacje w wielu wierszach, są trudne do napisania
  • Wyzwalacze mogą mylić aplikacje klienckie poprzez modyfikację zwróconego zestawu wierszy (na przykład wyzwalacz zastępuje liczbę dotkniętych wierszy)
  • Gdy jeden wyzwalacz wyzwala inny, wyniki są trudne do przewidzenia

Lepszą opcją jest zadanie, które okresowo kopiuje dane do nowej tabeli. Twoje raporty mogą być uruchamiane z kopii. Zadanie, które kopiuje wiersze, jest łatwe do napisania i utrzymania i nie ma ryzyka, że ​​wpłynie to na działanie aplikacji innej firmy.

Andomar
źródło
1. Wyzwalacze byłyby proste, więc zgłaszane błędy byłyby minimalne, gdyby w ogóle istniały. 2. Sam wyzwalacz nie obsługiwałby wielu wierszy (IE jeden wiersz zaktualizowany w tabeli z wyzwalaczem nie spowodowałby aktualizacji wielu wierszy w innym miejscu), ale wiele wierszy można wstawiać / aktualizować / usuwać jednocześnie w źródle stół - czy to masz na myśli? 3. czy nie można tego rozwiązać NOCOUNT? 4. W tabeli docelowej nie byłoby żadnych wyzwalaczy, a dla innych mogłem zapewnić to samo.
jreed121,
Jak mówisz, teoretycznie możliwe jest uruchomienie wyzwalaczy. Po prostu w praktyce nigdy tego nie robią.
Andomar,