sql >> Database teknologi >  >> RDS >> Mysql

designdatabase relateret til tidsattribut

Her er en model til at opfylde dine angivne krav.

Link til tidsseriedatamodel stærk>

Link til IDEF1X-notation for dem, der ikke er bekendt med Relational Modeling Standard.

  • Normaliseret til 5NF; ingen duplikerede kolonner; ingen opdateringsanomalier, ingen nuller.

  • Når status for et produkt ændres, skal du blot indsætte en række i ProductStatus med den aktuelle DateTime. Ingen grund til at røre ved tidligere rækker (som var sande og forbliver sande). Ingen dummy-værdier, som rapportværktøjer (andre end din app) skal fortolke.

  • DateTime er det faktiske DateTime, som produktet blev placeret i den pågældende status; "Fra", om du vil. "Til" er let udledt:det er DateTime for den næste (DatoTime> "Fra") række for Produktet; hvor den ikke findes, er værdien den aktuelle DateTime (brug ISNULL).

Den første model er færdig; (ProductId, DateTime) er nok til at give en unikhed for den primære nøgle. Men da du anmoder om hastighed for visse forespørgselsbetingelser, kan vi forbedre modellen på det fysiske niveau og levere:

  • Et indeks (vi har allerede PK-indekset, så vi vil forbedre det først, før vi tilføjer et andet indeks) for at understøtte dækkede forespørgsler (dem, der er baseret på ethvert arrangement af { ProductId | DateTime | Status } kan leveres af indekset uden at have for at gå til datarækkerne). Hvilket ændrer Status::ProductStatus-relationen fra Ikke-identificerende (stiplet linje) til Identificerende type (ubrudt linje).

  • PK-arrangementet er valgt ud fra, at de fleste forespørgsler vil være tidsserier, baseret på Produkt⇢DatoTid⇢Status.

  • Det andet indeks leveres for at øge hastigheden af ​​forespørgsler baseret på Status.

  • I det alternative arrangement er det omvendt; dvs. vi ønsker for det meste den aktuelle status for alle produkter.

  • I alle gengivelser af ProductStatus er DateTime-kolonnen i det sekundære indeks (ikke PK) faldende; den seneste er først.

Jeg har leveret den diskussion, du anmodede om. Selvfølgelig skal du eksperimentere med et datasæt af rimelig størrelse og træffe dine egne beslutninger. Hvis der er noget her, du ikke forstår, så spørg venligst, og jeg vil udvide.

Svar på kommentarer

Rapporter alle produkter med aktuel tilstand på 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 er indekseret, førende kolonne, begge sider

  • DateTime i indekseret, 2. kol. i dækket forespørgselsmulighed

  • StatusCode er indekseret, 3. kolonne i dækket forespørgselsmulighed

  • Siden StatusCode i indekset er faldende, der kræves kun én hentning for at opfylde den indre forespørgsel

  • rækkerne er påkrævet på samme tid for den ene forespørgsel; de ligger tæt sammen (på grund af Clstered Index); næsten altid på samme side på grund af den korte rækkestørrelse.

Dette er almindelig SQL, en underforespørgsel, der bruger kraften fra SQL-motoren, Relationel sætbehandling. Det er den en rigtige metode , der er ikke noget hurtigere, og enhver anden metode ville være langsommere. Ethvert rapportværktøj vil producere denne kode med nogle få klik, ingen indtastning.

To datoer i produktstatus

Kolonner såsom DateTimeFrom og DateTimeTo er grove fejl. Lad os tage det i rækkefølge efter vigtighed.

  1. Det er en grov normaliseringsfejl. "DateTimeTo" er let afledt af den enkelte DateTime i næste række; den er derfor overflødig, en dublet kolonne.

    • Nøjagtigheden kommer ikke ind i det:det løses nemt i kraft af DataTypen (DATE, DATETIME, SMALLDATETIME). Om du viser et sekund mindre, mikrosekund eller nanosekund, er en forretningsbeslutning; det har intet at gøre med de data, der er gemt.
  2. Implementering af en DateTo-kolonne er en 100 % duplikat (af DateTime i næste række). Dette tager dobbelt så meget diskplads . For et stort bord ville det være betydeligt unødvendigt spild.

  3. Da det er en kort række, skal du bruge dobbelt så mange logiske og fysiske I/O'er at læse tabellen, ved hver adgang.

  4. Og dobbelt så meget cacheplads (eller sagt på en anden måde, kun halvt så mange rækker ville passe ind i en given cacheplads).

  5. Ved at introducere en dubletkolonne har du introduceret muligheden for fejl (værdien kan nu udledes på to måder:fra den duplikerede DateTimeTo kolonne eller DateTimeFrom i næste række).

  6. Dette er også en opdateringsanomali . Når du opdaterer en DateTimeFrom opdateres, skal DateTimeTo fra den forrige række hentes (ingen big deal, da den er tæt på) og opdateret (big deal, da det er et ekstra verbum, der kan undgås).

  7. "Kortere" og "kodningsgenveje" er irrelevante, SQL er et besværligt datamanipulationssprog, men SQL er alt, hvad vi har (Bare håndtere det). Enhver, der ikke kan kode en underforespørgsel, burde virkelig ikke kode. Enhver, der dublerer en kolonne for at lette mindre kodnings-"vanskeligheder", burde virkelig ikke modellere databaser.

Bemærk godt, at hvis den højeste ordens regel (normalisering) blev opretholdt, er hele sættet af lavere ordens problemer elimineret.

Tænk i vilkår for sæt

  • Enhver, der har "besvær" eller oplever "smerte", når de skriver simpel SQL, er forkrøblet i at udføre deres jobfunktion. Typisk er udvikleren ikke tænker i sæt og den relationelle database er sætorienteret model .

  • Til forespørgslen ovenfor har vi brug for Current DateTime; da ProductStatus er et sæt af produkttilstande i kronologisk rækkefølge, skal vi blot bruge det seneste, eller MAX(DatoTime) af sættet tilhørende produktet.

  • Lad os nu se på noget, der angiveligt er "svært", i form af sæt . For en rapport om varigheden af ​​hvert produkt har været i en bestemt tilstand:DateTimeFrom er en tilgængelig kolonne og definerer den horisontale cut-off, et under sæt (vi kan udelukke tidligere rækker); DateTimeTo er det tidligste under sættet af produktstater.

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
  • Tænker i at få den næste række er rækkeorienteret, ikke sæt-orienteret bearbejdning. Lammende, når man arbejder med en sæt-orienteret database. Lad Optimizer gøre alt den tankegang for dig. Tjek dit SHOWPLAN, dette optimerer smukt.

  • Manglende evne til at tænke i sæt , der således er begrænset til kun at skrive forespørgsler på et enkelt niveau, er ikke en rimelig begrundelse for:at implementere massiv duplikering og opdateringsanomalier i databasen; spild af onlineressourcer og diskplads; garanterer halvdelen af ​​præstationen. Meget billigere at lære at skrive simple SQL-underforespørgsler for at opnå let afledte data.



  1. SQL Server-indekser - stigende eller faldende, hvilken forskel gør det?

  2. ved at bruge if and else Stored Procedures MySQL

  3. Eksport af en AWS Postgres RDS-tabel til AWS S3

  4. BIN() – Få den binære værdi af et tal i MySQL