Wydajne przechowywanie zestawów par klucz-wartość z bardzo różnymi kluczami

9

Odziedziczyłem aplikację, która łączy wiele różnych rodzajów działań z witryną. Istnieje około 100 różnych rodzajów aktywności, a każdy z nich ma inny zestaw 3-10 pól. Jednak wszystkie działania mają co najmniej jedno pole daty (może to być dowolna kombinacja daty, daty rozpoczęcia, daty zakończenia, zaplanowanej daty rozpoczęcia itp.) Oraz jedno pole osoby odpowiedzialnej. Wszystkie pozostałe pola różnią się znacznie, a pole daty początkowej niekoniecznie będzie nosiło nazwę „Data początkowa”.

Utworzenie jednej tabeli podtypów dla każdego rodzaju działania skutkowałoby schematem zawierającym 100 różnych tabel podtypów, co byłoby zbyt dziwne, aby sobie z tym poradzić. Obecnym rozwiązaniem tego problemu jest przechowywanie wartości aktywności jako par klucz-wartość. Jest to znacznie uproszczony schemat obecnego systemu, aby uzyskać punkt.

wprowadź opis zdjęcia tutaj

Każde działanie ma wiele pól ActivityField; każda witryna ma wiele działań, a tabela SiteActivityData przechowuje KVP dla każdej SiteActivity.

To sprawia, że ​​aplikacja (internetowa) jest bardzo łatwa do kodowania, ponieważ wszystko, co naprawdę musisz zrobić, to zapętlić rekordy w SiteActivityData dla danego działania i dodać etykietę i kontrolę wejściową dla każdego wiersza do formularza. Ale jest wiele problemów:

  • Uczciwość jest zła; możliwe jest umieszczenie pola w SiteActivityData, które nie należy do typu działania, a DataValue jest polem varchar, więc liczby i daty muszą być stale rzutowane.
  • Raporty i zapytania ad hoc tych danych są trudne, podatne na błędy i powolne. Na przykład uzyskanie listy wszystkich działań określonego typu, które mają datę końcową w określonym zakresie, wymaga osi przestawnych i rzutowania varcharów na daty. Autorzy raportu NIENAWIDZĄ tego schematu i nie winię ich.

Tak więc szukam sposobu na przechowywanie dużej liczby działań, które prawie nie mają wspólnych pól w sposób, który ułatwia raportowanie. Do tej pory wymyśliłem XML do przechowywania danych aktywności w formacie pseudo-noSQL:

wprowadź opis zdjęcia tutaj

Tabela aktywności zawierałaby XSD dla każdego działania, eliminując potrzebę korzystania z tabeli ActivityField. SiteActivity będzie zawierał klucz-wartość XML, więc każde działanie dla witryny będzie teraz w jednym wierszu.

Aktywność wyglądałaby mniej więcej tak (ale nie w pełni ją rozwinąłem):

<SomeActivityType>
  <SomeDateField type="StartDate">2000-01-01</SomeDateField>
  <AnotherDateField type="EndDate">2011-01-01</AnotherDateField>
  <EmployeeId type="ResponsiblePerson">1234</EmployeeId>
  <SomeTextField>blah blah</SomeTextField>
  ...

Zalety:

  • XSD sprawdziłby poprawność XML, wychwytując błędy takie jak wstawianie ciągu znaków w polu liczbowym na poziomie bazy danych, co było niemożliwe w starym schemacie, który przechowywał wszystko w varchar.
  • Zestaw rekordów KVP używanych do budowy formularzy internetowych można łatwo odtworzyć przy użyciu select ... from ActivityXML.nodes('/SomeActivityType/*') as T(r)
  • Podkwerenda xpath w pliku XML może zostać użyta do wygenerowania zestawu wyników zawierającego kolumny dla daty początkowej, końcowej itp. Bez użycia osi przestawnej, coś w rodzaju select ActivityXML.value('.[@type=StartDate]', 'datetime') as StartDate, ActivityXML.value('.[@type=EndDate]', 'datetime') as EndDate from SiteActivity where...

Czy to wydaje się dobrym pomysłem? Nie mogę wymyślić innych sposobów przechowywania tak dużej liczby różnych zestawów właściwości. Inną myślą, którą miałem, było zachowanie istniejącego schematu i przetłumaczenie go na coś łatwiejszego do zapytania w hurtowni danych, ale nigdy wcześniej nie projektowałem schematu gwiazdy i nie mam pojęcia, od czego zacząć.

Dodatkowe pytanie: jeśli zdefiniuję znacznik jako typ danych daty w XSD za pomocą xs:date, czy SQL Server będzie indeksował go jako wartość daty? Obawiam się, że jeśli zapytam według daty, będzie musiał rzucić ciąg daty na wartość daty i zniszczyć każdą szansę na użycie indeksu.

Paul Abbott
źródło
Jak aktualne muszą być dane do raportów? Czy raporty trafią do produkcji?
James Anderson
Większość raportów trafia teraz do hurtowni danych (która nie jest tak naprawdę DW, jest to zasadniczo kopia produkcyjnego schematu transakcyjnego z dodanym craptonem widoków i tabel z innych baz danych). Posiadanie raportów, które są nieaktualne, jest dopuszczalne, ale byłby to bonus, gdyby mógł być na żywo.
Paul Abbott,
Ile nakładają się pola? Czy dziesięć pól obejmuje wszystkie 100 podtypów, czy też jest około 500 całkowicie odrębnych pól?
Jon of All Trades,
Istnieje 72 pola i 75 rodzajów aktywności. 30 pól jest używanych tylko przez jedno działanie, a większość pozostałych jest wykorzystywana przez 5-10 działań. Istnieje kilka pól, które są wykorzystywane przez ~ 30 różnych działań. W przeważającej części nie ma zbyt dużej podobieństwa między działaniami.
Paul Abbott,

Odpowiedzi:

7

Tak więc szukam sposobu na przechowywanie dużej liczby działań, które prawie nie mają wspólnych pól w sposób, który ułatwia raportowanie.

Za mało przedstawicieli, aby skomentować, więc proszę bardzo!

Jeśli głównym celem jest raportowanie i masz DW (nawet jeśli nie jest to schemat gwiazdy), zaleciłbym próbę przekształcenia tego w schemat gwiazdy. Korzyści to szybkie, proste zapytania. Minusem jest ETL, ale już rozważasz przeniesienie danych do nowego projektu, a ETL do schematu gwiaździstego jest prawdopodobnie łatwiejszy w budowie i utrzymaniu niż rozwiązanie opakowania XML (a SSIS jest objęty licencją SQL Server). Ponadto rozpoczyna proces uznanego projektu raportowania / analizy.

Jak to zrobić ... Wygląda na to, że masz tak zwany fakt bez faktów . Jest to skrzyżowanie atrybutów, które definiują zdarzenie bez powiązanej miary (takiej jak cena sprzedaży). Masz dostępne daty niektórych lub wszystkich swoich działań? Prawdopodobnie powinieneś naprawdę przeciąć działanie, witrynę i datę (daty).

DimActivity- Zgaduję, że istnieje wzorzec, coś, co może pozwolić ci podzielić je na przynajmniej względnie wspólne kolumny. Jeśli tak, możesz mieć trzy? pięć? wymiary dla klas zajęć. W najgorszym przypadku masz kilka spójnych kolumn, takich jak nazwa działania, możesz je filtrować i pozostawiasz ogólne nagłówki, takie jak „Atrybut1” itp. Dla pozostałych losowych szczegółów.

Nie potrzebujesz wszystkiego w wymiarze - tam (prawdopodobnie) nie powinny znajdować się żadne daty w wymiarze Aktywność - wszystkie powinny być w rzeczywistości, ponieważ Klucz zastępczy odnosi się do wymiaru Data. Na przykład data, która pozostanie w wymiarze osoby, byłaby datą urodzenia, ponieważ jest to atrybut osoby. Termin wizyty w szpitalu byłby związany z faktem, ponieważ jest to wydarzenie w czasie związane między innymi z osobą, ale nie jest atrybutem osoby odwiedzającej szpital. Więcej faktów na temat dyskusji.

DimSite- wydaje się prosty, więc opiszemy tutaj klucze zastępcze. Zasadniczo jest to tylko rosnący, unikalny identyfikator. Kolumna Tożsamość całkowita jest wspólna. Umożliwia to separację systemów DW i źródłowych oraz zapewnia optymalne połączenia w hurtowni danych. Twój klucz naturalny lub klucz biznesowy jest zwykle przechowywany, ale do celów konserwacji / projektowania nie należy analizować i dołączać. Przykładowy schemat:

CREATE TABLE [DIM].[Site]
(
 SiteSK INT NOT NULL IDENTITY PRIMARY KEY
,SiteNK INT NOT NULL --source system key
,SiteName VARCHAR(500) NOT NULL
)

DimDate- atrybuty daty. Zrób „inteligentny klucz” zamiast Tożsamości. Oznacza to, że możesz wpisać znaczącą liczbę całkowitą odnoszącą się do daty dla zapytań, takich jak WHERE DateSK = 20150708. Istnieje wiele bezpłatnych skryptów do załadowania DimDate, a większość zawiera ten inteligentny klucz. ( jedna opcja )

DimEmployee - Twój XML to uwzględnił, jeśli jest to bardziej ogólna zmiana w DimPerson i wypełnij odpowiednie atrybuty osoby, ponieważ są one dostępne i odnoszą się do raportowania.

A twoim faktem jest:

FactActivitySite
DimSiteSK - FK to DimSite
DimActivitySK - FK to DimActivity
DimEmployee - FK to DimEmployee
DimDateSK - FK to DimDate

Możesz zmienić ich nazwy w faktach i możesz mieć wiele kluczy daty na wydarzenie. Fakty są zwykle bardzo duże, więc unikanie aktualizacji jest zwykle dobre ... jeśli masz wiele aktualizacji daty dla jednego zdarzenia, możesz spróbować projektu Usuń / Wstaw, dodając SK do faktu, który umożliwia wybór wierszy „aktualizacja” do zostać usunięte, a następnie wstawiając najnowsze dane.

Rozwiń dat fakcie co trzeba: StartDateSK, EndDateSK, ScheduledStartDateSK.

Wszystkie wymiary powinny mieć nieznany wiersz, zwykle z zakodowanym na stałe -1 SK. Gdy załadujesz fakt, a działanie nie ma żadnej z zawartych dat, powinno po prostu załadować -1.

Faktem jest zbiór odniesień liczb całkowitych do twoich atrybutów przechowywanych w wymiarach, połącz je ze sobą, a otrzymasz wszystkie szczegóły, w bardzo czysty wzór łączenia, a fakt, ze względu na typy danych, jest wyjątkowo mały i szybki. Ponieważ jesteś w programie SQL Server, dodaj indeks magazynu kolumn, aby jeszcze bardziej zwiększyć wydajność. Możesz po prostu upuścić i odbudować podczas ETL. Po przejściu do SQL 2014+ możesz pisać do indeksów magazynu kolumn.

wprowadź opis zdjęcia tutaj

Jeśli pójdziesz tą drogą, poszukaj Modelowania wymiarowego. Polecam metodologię Kimball . Istnieje również wiele bezpłatnych przewodników, ale jeśli będzie to coś innego niż jednorazowe rozwiązanie, inwestycja jest prawdopodobnie tego warta.

Dave
źródło
(pytanie od wesdev): @Dave, jakiego narzędzia ERD użyłeś?
ypercubeᵀᴹ
Dokonano tego w Microsoft Visio 2013
Dave