sql >> Database >  >> RDS >> Mysql

ontwerpdatabase met betrekking tot tijdattribuut

Hier is een model om aan uw gestelde eis te voldoen.

Link naar Time Series-gegevensmodel

Link naar IDEF1X-notatie voor degenen die niet bekend zijn met de Relational Modeling Standard.

  • Genormaliseerd naar 5NF; geen dubbele kolommen; geen update-afwijkingen, geen nulls.

  • Wanneer de status van een product verandert, voegt u eenvoudig een rij in ProductStatus in, met de huidige DateTime. Het is niet nodig om vorige rijen aan te raken (die waar waren en waar blijven). Geen dummy-waarden die rapportagetools (anders dan uw app) moeten interpreteren.

  • De DateTime is de werkelijke DateTime waarop het Product in die Status is geplaatst; de "Van", zo u wilt. De "Aan" is gemakkelijk afgeleid:het is de DateTime van de volgende (DateTime> "From") rij voor het Product; waar het niet bestaat, is de waarde de huidige DateTime (gebruik ISNULL).

Het eerste model is af; (ProductId, DateTime) is voldoende om de primaire sleutel uniek te maken. Omdat u echter snelheid vraagt ​​voor bepaalde zoekvoorwaarden, kunnen we het model op fysiek niveau verbeteren en het volgende bieden:

  • Een index (we hebben al de PK-index, dus we zullen die eerst verbeteren, voordat we een tweede index toevoegen) om gedekte zoekopdrachten te ondersteunen (die op basis van een rangschikking van { ProductId | DateTime | Status } kunnen door de Index worden geleverd, zonder dat om naar de gegevensrijen te gaan). Wat de Status::ProductStatus-relatie verandert van Niet-identificerend (onderbroken lijn) in Identificerend type (ononderbroken lijn).

  • Het PK-arrangement is gekozen op basis van het feit dat de meeste zoekopdrachten tijdreeksen zullen zijn, gebaseerd op Product⇢DateTime⇢Status.

  • De tweede index wordt geleverd om de snelheid van zoekopdrachten op basis van Status te verbeteren.

  • In de Alternatieve Regeling is dat omgekeerd; dat wil zeggen, we willen meestal de huidige status van alle producten.

  • In alle uitvoeringen van ProductStatus is de kolom DateTime in de secundaire index (niet de PK) DESCending; de meest recente staat bovenaan.

Ik heb de door u gevraagde discussie gegeven. Natuurlijk moet je experimenteren met een dataset van redelijke omvang en je eigen beslissingen nemen. Als er hier iets is dat je niet begrijpt, vraag het dan, en ik zal het uitbreiden.

Reacties op opmerkingen

Rapporteer alle producten met huidige status van 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 is geïndexeerd, leidende col, beide zijden

  • DateTime in Geïndexeerd, 2e col in Covered Query Option

  • StatusCode is geïndexeerd, 3e col in Covered Query Option

  • Sinds StatusCode in de Index is DESCending, er is slechts één ophaalactie nodig om aan de innerlijke vraag te voldoen

  • de rijen zijn tegelijkertijd vereist voor die ene query; ze liggen dicht bij elkaar (vanwege de gegroepeerde index); bijna altijd op dezelfde pagina vanwege de korte rijen.

Dit is gewone SQL, een subquery, die gebruik maakt van de kracht van de SQL-engine, relationele setverwerking. Het is de ene juiste methode , er is niets sneller en elke andere methode zou langzamer zijn. Elke rapportagetool produceert deze code met een paar klikken, zonder typen.

Twee datums in productstatus

Kolommen zoals DateTimeFrom en DateTimeTo zijn grove fouten. Laten we het in volgorde van belangrijkheid nemen.

  1. Het is een grove normalisatiefout. "DateTimeTo" is gemakkelijk afgeleid van de enkele DateTime van de volgende rij; het is daarom overbodig, een dubbele kolom.

    • De precisie komt er niet in aan:dat is eenvoudig op te lossen dankzij het DataType (DATE, DATETIME, SMALLDATETIME). Of u een seconde minder, microseconde of nanoseconde weergeeft, is een zakelijke beslissing; het heeft niets te maken met de gegevens die worden opgeslagen.
  2. Het implementeren van een DateTo-kolom is een 100% duplicaat (van DateTime van de volgende rij). Dit kost twee keer zoveel schijfruimte . Voor een grote tafel zou dat een aanzienlijke onnodige verspilling zijn.

  3. Aangezien het een korte rij is, heb je twee keer zoveel logische en fysieke I/O's nodig om de tabel te lezen, bij elke toegang.

  4. En twee keer zoveel cacheruimte (of anders gezegd, slechts de helft van het aantal rijen zou in een bepaalde cacheruimte passen).

  5. Door een dubbele kolom te introduceren, heeft u de mogelijkheid van fouten geïntroduceerd (de waarde kan nu op twee manieren worden afgeleid:van de dubbele kolom DateTimeTo of de DateTimeFrom van de volgende rij).

  6. Dit is ook een Update-afwijking . Wanneer u een DateTimeFrom bijwerkt, moet de DateTimeTo van de vorige rij worden opgehaald (geen probleem omdat het dichtbij is) en bijgewerkt (groot probleem omdat het een extra werkwoord is dat kan worden vermeden).

  7. "Korter" en "codeersnelkoppelingen" zijn niet relevant, SQL is een omslachtige taal voor gegevensmanipulatie, maar SQL is alles wat we hebben (Leer er maar mee leven). Iedereen die een subquery niet kan coderen, zou eigenlijk niet moeten coderen. Iedereen die een kolom dupliceert om kleine "moeilijkheden" bij het coderen te vergemakkelijken, zou eigenlijk geen databases moeten modelleren.

Merk op dat als de regel van de hoogste orde (normalisatie) werd gehandhaafd, de hele reeks problemen van de lagere orde wordt geëlimineerd.

Denk in termen van sets

  • Iedereen die "moeilijkheden" heeft of "pijn" ervaart bij het schrijven van eenvoudige SQL, is verlamd bij het uitvoeren van zijn functie. Meestal is de ontwikkelaar niet denken in termen van sets en de relationele database is een set-georiënteerd model .

  • Voor de bovenstaande query hebben we de Current DateTime nodig; aangezien ProductStatus een set is van productstatussen in chronologische volgorde, we hebben alleen de laatste, of MAX(DateTime) van de set nodig die bij het product horen.

  • Laten we nu eens kijken naar iets dat zogenaamd "moeilijk" is, in termen van sets . Voor een rapport van de duur dat elk Product in een bepaalde Staat is geweest:de DateTimeFrom is een beschikbare kolom en definieert de horizontale cut-off, een sub set (we kunnen eerdere rijen uitsluiten); de DateTimeTo is de vroegste van de sub set van productstatussen.

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
  • Denken in termen van de volgende rij halen is rijgericht, niet set-georiënteerde verwerking. Verlammend, bij het werken met een set-georiënteerde database. Laat de Optimizer al dat denkwerk voor u doen. Controleer je SHOWPLAN, dit optimaliseert prachtig.

  • Onvermogen om in sets te denken , dus beperkt tot het schrijven van alleen query's op één niveau, is geen redelijke rechtvaardiging voor:het implementeren van massale duplicatie en updateafwijkingen in de database; het verspillen van online bronnen en schijfruimte; garant voor de helft van de prestaties. Veel goedkoper om te leren hoe u eenvoudige SQL-subquery's schrijft om gemakkelijk afgeleide gegevens te verkrijgen.



  1. SQL Server Besturingssysteemfout 5:5 (Toegang is geweigerd.)

  2. MySQL:fouten negeren bij importeren?

  3. Mysql, hervorm gegevens van lang / hoog naar breed

  4. 1064-fout in CREATE TABLE ... TYPE=MYISAM