Mysql
 sql >> Baza danych >  >> RDS >> Mysql

projektowa baza danych dotycząca atrybutu czasu

Oto model, który pozwoli Ci spełnić określone wymagania.

Link do modelu danych szeregów czasowych

Link do notacji IDEF1X dla tych, którzy nie są zaznajomieni ze standardem modelowania relacyjnego.

  • Znormalizowane do 5NF; brak zduplikowanych kolumn; bez anomalii aktualizacji, bez zer.

  • Gdy zmieni się status produktu, po prostu wstaw wiersz do ProductStatus z bieżącą datą i godziną. Nie trzeba dotykać poprzednich wierszy (które były prawdziwe i pozostają prawdziwe). Nie ma żadnych fikcyjnych wartości, które narzędzia raportujące (inne niż Twoja aplikacja) muszą interpretować.

  • Data i godzina to rzeczywista data i godzina, w której produkt został umieszczony w tym statusie; „Od”, jeśli chcesz. „Do” można łatwo wyprowadzić:jest to data i godzina następnego wiersza (DataCzas> „Od”) dla Produktu; tam, gdzie nie istnieje, wartością jest bieżąca data i godzina (użyj ISNULL).

Pierwszy model jest kompletny; (ProductId, DateTime) wystarczy, aby zapewnić unikatowość klucza podstawowego. Ponieważ jednak żądasz szybkości w określonych warunkach zapytania, możemy ulepszyć model na poziomie fizycznym i zapewnić:

  • Indeks (mamy już indeks PK, więc ulepszymy ten pierwszy, przed dodaniem drugiego indeksu) do obsługi zapytań objętych zakresem (te oparte na dowolnym układzie { ProductId | DateTime | Status } mogą być dostarczone przez indeks, bez konieczności posiadania aby przejść do wierszy danych). Który zmienia relację Status::ProductStatus z Nieidentyfikujące (linia przerywana) na Typ identyfikujący (linia ciągła).

  • Układ PK jest wybierany na podstawie tego, że większość zapytań będzie dotyczyć szeregów czasowych, w oparciu o stan produktu⇢data i godzina⇢.

  • Drugi indeks jest dostarczany w celu zwiększenia szybkości zapytań w oparciu o Status.

  • W układzie alternatywnym jest to odwrócone; tzn. zależy nam głównie na aktualnym stanie wszystkich Produktów.

  • We wszystkich wersjach ProductStatus kolumna DateTime w indeksie wtórnym (nie PK) to DESCending; najnowsza jest pierwsza.

Udostępniłem dyskusję, o którą prosiłeś. Oczywiście musisz poeksperymentować z zestawem danych o rozsądnej wielkości i podjąć własne decyzje. Jeśli jest tu coś, czego nie rozumiesz, zapytaj, a ja rozwinę.

Odpowiedzi na komentarze

Zgłoś wszystkie produkty o aktualnym stanie 2

SELECT  ProductId,
        Description
    FROM  Product       p,
          ProductStatus ps
    WHERE p.ProductId = ps.ProductId  -- Join
    AND   StatusCode  = 2             -- Request
    AND   DateTime    = (             -- Current Status on the left ...
        SELECT MAX(DateTime)          -- Current Status row for outer Product
            FROM  ProductStatus ps_inner
            WHERE p.ProductId = ps_inner.ProductId
            )
  • ProductId jest indeksowany, wiodący kolor, obie strony

  • DateTime w indeksie, druga kolumna w Covered Query Option

  • StatusCode jest indeksowany, trzecia kolumna w Covered Query Option

  • Od StatusCode w indeksie to DESCending, do spełnienia wewnętrznego zapytania wymagane jest tylko jedno pobranie

  • wiersze są wymagane w tym samym czasie dla jednego zapytania; są blisko siebie (ze względu na Clustered Index); prawie zawsze na tej samej stronie ze względu na krótki rozmiar wiersza.

Jest to zwykły SQL, podzapytanie, wykorzystujące moc silnika SQL, przetwarzanie zbiorów relacyjnych. Jest to jedna poprawna metoda , nie ma nic szybszego, a każda inna metoda byłaby wolniejsza. Każde narzędzie raportujące wygeneruje ten kod za pomocą kilku kliknięć, bez wpisywania.

Dwie daty w stanie produktu

Kolumny takie jak DateTimeFrom i DateTimeTo są błędami rażącymi. Weźmy to w kolejności ważności.

  1. Jest to poważny błąd normalizacji. „DateTimeTo” można łatwo wyprowadzić z pojedynczej DateTime następnego wiersza; dlatego jest zbędna, zduplikowana kolumna.

    • Precyzja nie wchodzi w grę:można to łatwo rozwiązać dzięki DataType (DATE, DATETIME, SMALLDATETIME). Niezależnie od tego, czy wyświetlasz jedną sekundę mniej, mikrosekundę, czy nanosekundę, to decyzja biznesowa; nie ma to nic wspólnego z przechowywanymi danymi.
  2. Implementacja kolumny DateTo jest 100% duplikatem (z DateTime następnego wiersza). Zajmuje to dwa razy więcej miejsca na dysku . W przypadku dużego stołu byłoby to znaczne niepotrzebne marnotrawstwo.

  3. Biorąc pod uwagę, że jest to krótki rząd, będziesz potrzebować dwa razy więcej logicznych i fizycznych operacji we/wy czytać tabelę przy każdym dostępie.

  4. I dwa razy więcej miejsca w pamięci podręcznej (lub ujmując to inaczej, tylko o połowę mniej wierszy zmieściłoby się w danej przestrzeni pamięci podręcznej).

  5. Wprowadzając zduplikowaną kolumnę, wprowadziłeś możliwość wystąpienia błędu (wartość można teraz wyprowadzić na dwa sposoby:ze zduplikowanej kolumny DateTimeTo lub DateTimeFrom następnego wiersza).

  6. Jest to również Anomalia aktualizacji . Po zaktualizowaniu dowolnego DateTimeFrom jest aktualizowany, należy pobrać DateTimeTo z poprzedniego wiersza (nic wielkiego, ponieważ jest blisko) i zaktualizować (duża sprawa, ponieważ jest to dodatkowy czasownik, którego można uniknąć).

  7. „Krótsze” i „skróty kodowania” są nieistotne, SQL jest niewygodnym językiem do manipulacji danymi, ale SQL to wszystko, co mamy (Licz sie z tym). Każdy, kto nie potrafi zakodować podzapytania, tak naprawdę nie powinien kodować. Każdy, kto duplikuje kolumnę w celu ułatwienia „trudności” kodowania, tak naprawdę nie powinien modelować baz danych.

Zauważ dobrze, że jeśli została zachowana reguła najwyższego rzędu (Normalizacja), cały zestaw problemów niższego rzędu zostanie wyeliminowany.

Myśl w kategoriach zestawów

  • Każdy, kto ma „trudności” lub doświadcza „bólu” podczas pisania prostego SQL, ma problemy z wykonywaniem swojej funkcji. Zazwyczaj programista nie myślenie w kategoriach zestawów a relacyjna baza danych jest modelem zorientowanym na zbiór .

  • Dla powyższego zapytania potrzebujemy Current DateTime; ponieważ ProductStatus to zestaw stanów produktów w porządku chronologicznym, potrzebujemy po prostu najnowszego lub MAX(DateTime) zestawu należące do Produktu.

  • Teraz spójrzmy na coś rzekomo „trudnego” w kategoriach zestawów . W przypadku raportu na temat czasu trwania każdego produktu w określonym stanie:kolumna DateTimeFrom jest dostępną kolumną i definiuje poziome odcięcie, pod zestaw (możemy wykluczyć wcześniejsze wiersze); DateTimeTo jest najwcześniejszym z pod zestawu stanów produktów.

SELECT               ProductId,
                     Description,
        [DateFrom] = DateTime,
        [DateTo]   = (
        SELECT MIN(DateTime)                        -- earliest in subset
            FROM  ProductStatus ps_inner
            WHERE p.ProductId = ps_inner.ProductId  -- our Product
            AND   ps_inner.DateTime > ps.DateTime   -- defines subset, cutoff
            )
    FROM  Product       p,
          ProductStatus ps
    WHERE p.ProductId = ps.ProductId 
    AND   StatusCode  = 2             -- Request
  • Myślenie w kategoriach uzyskania następnego wiersza jest zorientowany na wiersz, nie przetwarzanie zorientowane na zbiór. Paraliż podczas pracy z bazą danych zorientowaną na zbiór. Niech Optymalizator zrobi to wszystko za Ciebie. Sprawdź swój SHOWPLAN, to świetnie optymalizuje.

  • Niezdolność do myślenia zestawami , ograniczając się tym samym do pisania tylko jednopoziomowych zapytań, nie jest rozsądnym uzasadnieniem dla:implementacji masowej duplikacji i aktualizacji anomalii w bazie danych; marnowanie zasobów online i miejsca na dysku; gwarantując połowę wydajności. O wiele taniej jest nauczyć się pisać proste podzapytania SQL, aby uzyskać łatwo wyprowadzone dane.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak uzyskać nazwy wszystkich kolumn dla wszystkich tabel w MySQL?

  2. Problem z dostępem do rzekomo wyłączonej funkcji w CODEIGNITER

  3. Jak obliczyć całkowitą sprzedaż miesięcznie w MySQL?

  4. Jak sprawić, by Sequelize używał pojedynczych nazw tabel

  5. Czy powinniśmy uwzględnić kolumnę sortowania, klucz podstawowy w indeksie złożonym (MySQL)