sql >> Databasteknik >  >> RDS >> Mysql

designdatabas relaterad till tidsattribut

Här är en modell för att uppnå dina angivna krav.

Länk till tidsseriedatamodell stark>

Länk till IDEF1X-notation för dem som inte är bekanta med Relational Modeling Standard.

  • Normaliserad till 5NF; inga dubbletter av kolumner; inga uppdateringsavvikelser, inga nollor.

  • När statusen för en produkt ändras, infoga helt enkelt en rad i ProductStatus, med aktuell DateTime. Du behöver inte röra tidigare rader (som var sanna och förblir sanna). Inga dummyvärden som rapportverktyg (andra än din app) måste tolka.

  • DateTime är den faktiska DateTime som produkten placerades i den statusen; "Från", om du så vill. "Till" är lätt att härleda:det är DateTime för nästa (DateTime> "From") rad för produkten; där det inte finns är värdet aktuell DateTime (använd ISNULL).

Den första modellen är klar; (ProductId, DateTime) är tillräckligt för att ge unikhet för den primära nyckeln. Men eftersom du begär hastighet för vissa frågevillkor kan vi förbättra modellen på fysisk nivå och tillhandahålla:

  • Ett index (vi har redan PK-indexet, så vi kommer att förbättra det först, innan vi lägger till ett andra index) för att stödja täckta frågor (de som är baserade på valfritt arrangemang av { ProductId | DateTime | Status } kan tillhandahållas av Indexet utan att behöva för att gå till dataraderna). Vilket ändrar Status::ProductStatus-relationen från Icke-identifierande (streckad linje) till Identifierande typ (heldragen linje).

  • PK-arrangemanget väljs utifrån att de flesta frågorna kommer att vara tidsserier, baserat på Produkt⇢DatumTid⇢Status.

  • Det andra indexet tillhandahålls för att öka hastigheten på frågor baserat på Status.

  • I det alternativa arrangemanget är det omvänt; dvs vi vill oftast ha den aktuella statusen för alla produkter.

  • I alla återgivningar av ProductStatus är kolumnen DateTime i det sekundära indexet (inte PK) Sjunkande; den senaste är först ut.

Jag har tillhandahållit diskussionen du begärde. Naturligtvis måste du experimentera med en datamängd av rimlig storlek och fatta dina egna beslut. Om det är något här som du inte förstår, vänligen fråga, så utökar jag.

Svar på kommentarer

Rapportera alla produkter med aktuellt tillstånd 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 är indexerad, ledande kol, båda sidor

  • DateTime i Indexerad, 2:a kolumn i Covered Query Option

  • StatusCode är indexerad, 3:e kolumnen i Covered Query Option

  • Sedan StatusCode i indexet är sjunkande, bara en hämtning krävs för att tillfredsställa den inre frågan

  • raderna krävs samtidigt för en fråga; de ligger nära varandra (på grund av Clstered Index); nästan alltid på samma sida på grund av den korta radstorleken.

Detta är vanlig SQL, en underfråga, som använder kraften i SQL-motorn, Relationsuppsättningsbearbetning. Det är den en korrekta metoden , det finns inget snabbare, och alla andra metoder skulle vara långsammare. Alla rapportverktyg kommer att producera den här koden med några få klick, utan att skriva.

Två datum i produktstatus

Kolumner som DateTimeFrom och DateTimeTo är grova fel. Låt oss ta det i viktordning.

  1. Det är ett grovt normaliseringsfel. "DateTimeTo" härleds lätt från den enda DateTime på nästa rad; den är därför redundant, en dubblettkolumn.

    • Precisionen kommer inte in i det:det är lätt att lösa med hjälp av DataTypen (DATE, DATETIME, SMALLDATETIME). Oavsett om du visar en sekund mindre, mikrosekund eller nanosekund är ett affärsbeslut; det har ingenting att göra med den data som lagras.
  2. Att implementera en DateTo-kolumn är en 100 % dubblett (av DateTime på nästa rad). Detta tar dubbelt så mycket diskutrymme . För ett stort bord skulle det vara ett stort onödigt slöseri.

  3. Med tanke på att det är en kort rad behöver du dubbelt så många logiska och fysiska I/O att läsa tabellen, vid varje åtkomst.

  4. Och dubbelt så mycket cacheutrymme (eller uttryckt på annat sätt, bara hälften så många rader skulle passa in i ett givet cacheutrymme).

  5. Genom att introducera en dubblettkolumn har du introducerat möjligheten till fel (värdet kan nu härledas på två sätt:från kolumnen Duplicate DateTimeTo eller DateTimeFrom på nästa rad).

  6. Detta är också en uppdateringsavvikelse . När du uppdaterar någon DateTimeFrom uppdateras, måste DateTimeTo från föregående rad hämtas (ingen stor sak eftersom den är nära) och uppdaterad (big deal eftersom det är ett extra verb som kan undvikas).

  7. "Kortare" och "kodningsgenvägar" är irrelevanta, SQL är ett besvärligt datamanipuleringsspråk, men SQL är allt vi har (Bara ta itu med det). Den som inte kan koda en underfråga borde verkligen inte koda. Alla som duplicerar en kolumn för att underlätta mindre kodnings-"svårigheter" borde verkligen inte modellera databaser.

Observera väl att om den högsta ordningens regel (normalisering) bibehölls, elimineras hela uppsättningen av lägre ordningsproblem.

Tänk i termer av set

  • Alla som har "svårigheter" eller upplever "smärta" när de skriver enkel SQL är lamslagen när det gäller att utföra sin arbetsfunktion. Vanligtvis är utvecklaren inte tänker i termer av uppsättningar och den relationella databasen är uppsättningsorienterad modell .

  • För frågan ovan behöver vi Current DateTime; eftersom ProductStatus är en uppsättning av produkttillstånd i kronologisk ordning behöver vi helt enkelt den senaste, eller MAX(DateTime) av uppsättningen som tillhör produkten.

  • Låt oss nu titta på något som påstås vara "svårt", i termer av uppsättningar . För en rapport om hur länge varje produkt har varit i ett visst tillstånd:DateTimeFrom är en tillgänglig kolumn och definierar den horisontella gränsen, en under uppsättning (vi kan utesluta tidigare rader); DateTimeTo är den tidigaste av sub-uppsättningen av 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 termer av att få nästa rad är radorienterad, inte set-orienterad bearbetning. Förlamande, när man arbetar med en set-orienterad databas. Låt optimeraren göra allt det där tänkandet åt dig. Kontrollera ditt SHOWPLAN, detta optimerar vackert.

  • Oförmåga att tänka i uppsättningar , som alltså är begränsad till att bara skriva ennivåfrågor, är inte en rimlig motivering för att:implementera massiv duplicering och uppdateringsavvikelser i databasen; slösa onlineresurser och diskutrymme; garanterar halva prestandan. Mycket billigare att lära sig att skriva enkla SQL-underfrågor för att få lätt härledda data.



  1. Typer av SQL-kommandon

  2. Mysql SELECT inuti UPPDATERING

  3. välj duplicerad post och räkna post från kommaseparerad i mysql

  4. Villkorlig aggregeringsfråga med en grupp efter