sql >> Databáze >  >> RDS >> Mysql

databáze návrhů týkající se atributu času

Zde je model pro splnění vašeho stanoveného požadavku.

Odkaz na datový model časové řady

Odkaz na zápis IDEF1X pro ty, kteří neznají standard relačního modelování.

  • Normalizováno na 5NF; žádné duplicitní sloupce; žádné anomálie aktualizací, žádné nuly.

  • Když se stav produktu změní, stačí do ProductStatus vložit řádek s aktuálním datem a časem. Není třeba se dotýkat předchozích řádků (které byly pravdivé a zůstávají pravdivé). Žádné fiktivní hodnoty, které musí nástroje pro vytváření přehledů (jiné než vaše aplikace) interpretovat.

  • DateTime je skutečné datum a čas, kdy byl produkt umístěn do tohoto stavu; "Od", chcete-li. „Do“ lze snadno odvodit:je to Datum a čas dalšího řádku (DateTime> „Od“) pro Produkt; tam, kde neexistuje, je hodnotou aktuální datum a čas (použijte ISNULL).

První model je kompletní; (ProductId, DateTime) stačí k poskytnutí jedinečnosti pro primární klíč. Protože však požadujete rychlost pro určité podmínky dotazu, můžeme model vylepšit na fyzické úrovni a poskytnout:

  • Index (již máme index PK, takže jej nejprve vylepšíme, než přidáme druhý index), aby podporoval zahrnuté dotazy (ty založené na libovolném uspořádání { ProductId | DateTime | Status } mohou být poskytnuty indexem, aniž bychom museli přejděte na datové řádky). Což změní vztah Status::ProductStatus z Non-Identifying (přerušovaná čára) na Identifying type (plná čára).

  • Uspořádání PK je zvoleno na základě toho, že většina dotazů bude Time Series na základě Product⇢DateTime⇢Status.

  • Druhý index slouží ke zvýšení rychlosti dotazů na základě stavu.

  • V alternativním uspořádání je to obrácené; tj. většinou chceme aktuální stav všech Produktů.

  • Ve všech provedeních ProductStatus je sloupec DateTime v sekundárním indexu (nikoli PK) DESCending; nejnovější je první.

Poskytl jsem vámi požadovanou diskuzi. Samozřejmě musíte experimentovat se souborem dat přiměřené velikosti a dělat svá vlastní rozhodnutí. Pokud je zde něco, čemu nerozumíte, zeptejte se a já to rozšířím.

Odpovědi na komentáře

Nahlásit všechny produkty s aktuálním stavem 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 je indexováno, úvodní sloupec, obě strany

  • DateTime v Indexed, 2. sloupec v Covered Query Option

  • StatusCode je indexovaný, 3. sloupec ve volbě krytého dotazu

  • Od StatusCode v Index je DESCending, k uspokojení vnitřního dotazu je zapotřebí pouze jedno načtení

  • řádky jsou vyžadovány současně pro jeden dotaz; jsou blízko u sebe (kvůli Clstered Index); téměř vždy na stejné stránce kvůli krátké velikosti řádku.

Toto je běžný SQL, poddotaz, využívající sílu enginu SQL, zpracování relační sady. Je to jedna správná metoda , neexistuje nic rychlejšího a jakákoli jiná metoda by byla pomalejší. Jakýkoli nástroj pro vytváření přehledů vytvoří tento kód několika kliknutími, bez psaní.

Dvě data ve stavu produktu

Sloupce jako DateTimeFrom a DateTimeTo jsou hrubé chyby. Vezměme to v pořadí podle důležitosti.

  1. Je to hrubá normalizační chyba. "DateTimeTo" je snadno odvozeno z jediného DateTime na dalším řádku; je tedy nadbytečný, duplicitní sloupec.

    • Přesnost v tom nehraje roli:ta se dá snadno vyřešit pomocí DataType (DATE, DATETIME, SMALLDATETIME). Zda zobrazíte o sekundu méně, mikrosekundu nebo nanosekundu, je obchodní rozhodnutí; nemá to nic společného s uloženými daty.
  2. Implementace sloupce DateTo je 100% duplikát (datum a čas dalšího řádku). To zabere dvojnásobek místa na disku . U velkého stolu by to bylo značné zbytečné plýtvání.

  3. Vzhledem k tomu, že se jedná o krátký řádek, budete potřebovat dvakrát tolik logických a fyzických I/O pro čtení tabulky při každém přístupu.

  4. A dvakrát více místa v mezipaměti (nebo jinak řečeno, do libovolného mezipaměti by se vešlo pouze poloviční počet řádků).

  5. Zavedením duplicitního sloupce jste zavedli možnost chyby (hodnotu lze nyní odvodit dvěma způsoby:z duplicitního sloupce DateTimeTo nebo DateTimeFrom na dalším řádku).

  6. Toto je také Anomálie aktualizace . Když aktualizujete jakékoli DateTimeFrom, je Aktualizováno, DateTimeTo předchozího řádku musí být načteno (žádný velký problém, protože je blízko) a Updated (velký problém, protože jde o dodatečné sloveso, kterému se lze vyhnout).

  7. „Kratší“ a „kódovací zkratky“ jsou irelevantní, SQL je těžkopádný jazyk pro manipulaci s daty, ale SQL je vše, co máme (Jen se s tím vypořádej). Každý, kdo neumí kódovat poddotaz, by opravdu neměl kódovat. Každý, kdo duplikuje sloupec, aby si ulehčil drobné „obtíže“ s kódováním, by ve skutečnosti neměl modelovat databáze.

Všimněte si dobře, že pokud bylo zachováno pravidlo nejvyššího řádu (normalizace), celá sada problémů nižšího řádu je eliminována.

Přemýšlejte v podmínkách sad

  • Každý, kdo má „potíže“ nebo zažívá „bolest“ při psaní jednoduchého SQL, je při vykonávání své pracovní funkce ochromen. Vývojář obvykle není myšlení z hlediska množin a relační databáze je model orientovaný na sady .

  • Pro výše uvedený dotaz potřebujeme aktuální datum a čas; protože ProductStatus je množina stavů produktů v chronologickém pořadí, potřebujeme pouze nejnovější, neboli MAX (DateTime) z množiny patřící k produktu.

  • Nyní se podíváme na něco údajně „obtížného“, pokud jde o množiny . Pro přehled doby, po kterou byl každý produkt v určitém stavu:DateTimeFrom je dostupný sloupec a definuje horizontální mez, podmnožinu (můžeme vyloučit dřívější řádky); DateTimeTo je nejstarší z dílčí množiny stavů produktu.

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
  • Přemýšlejte ve smyslu získání dalšího řádku je orientovaný na řádky, ne množinově orientované zpracování. Zmrzačení při práci s databází orientovanou na množiny. Nechte Optimizer, aby za vás všechno přemýšlel. Zkontrolujte svůj SHOWPLAN, to se krásně optimalizuje.

  • Neschopnost myslet v množinách , tedy omezení na psaní pouze jednoúrovňových dotazů, není rozumné ospravedlnění pro:implementaci masivní duplikace a anomálií aktualizací v databázi; plýtvání online zdroji a místem na disku; garantující poloviční výkon. Mnohem levnější je naučit se psát jednoduché poddotazy SQL pro získání snadno odvozených dat.



  1. Příklady POWER() v SQL Server

  2. GeoIP tabulka se spojí s tabulkou IP v MySQL

  3. Příklady DATEDIFF() v SQL Server

  4. SQL AVG() pro začátečníky