Přístupy k datovému modelování

Při návrhu databázového modelu nestavíme „na zelené louce“. Většinou stavíme návrh na základě zadání od zákazníka či transformované specifikace od aplikačního vývojáře. Existují dvě hlavní základní strategie, jak převést realitu do databázového modelu. Volba správné strategie závisí na tom, jak dobře známe zadání, jak dobře jsou informace strukturované a v jaké fázi se v projektu vlastně nacházíme.

Dva hlavní přístupy jsou:

  1. zdola nahoru (bottom-up) „induktivní přístup“ (orientovaný na atributy)
  2. shora dolů (top-down) „deduktivní přístup“ (orientovaný na relace)

Zdola nahoru

Při využití tohoto přístupu začínáme u množství nejmenších detailů (konkrétních dat či názvů atributů) a postupně z nich skládáme větší celky. Je typický pro situace, kdy máme k dispozici konkrétní dokumenty, podklady, výpovědi od zákazníka a potřebujeme vše zachytit a převést do databáze.

Postup návrhu

  1. Identifikace atributů – sepíšeme všechny datové položky (atributy), které v systému musejí být (všechno, co jsme našli na dokumentech, podkladech; ve výpovědi od zákazníka)
  2. Seskupení do relací – analyzujeme závislosti mezi atributy. Zjistíme, které atributy se váží k sobě a spojíme je do jednotlivých relací.
  3. Definice vztahů mezi relacemi – určíme, jak spolu vzniklé relace souvisejí

Příklad z praxe

Klient k Vám přednese projev na první pohled ne zcela souvisejících požadavků – přeskakuje od jednoho ke druhému tak, jak je to pro něj důležité nebo jak ho napadají jednotlivé detaily. Je možné, že na první schůzce klient ani neřekne všechny požadavky a proto se vyplatí, když o dané problematice něco víme a můžeme se doptat. Klient požaduje evidovat požadavky na výpůjčky zařízení pro stavby. Poté, co si jej vyslechnete a podíváte se na stávající způsob evidence, dáte dohromady všechny atributy, co všechno potřebuje sledovat – například:

  1. Název firmy (zákazníka)
  2. IČO zákazníka
  3. Telefonní číslo na zákazníka
  4. Email na fakturaci
  5. Adresa sídla firmy
  6. Název vypůjčeného stroje (např. „Bagr CAT 305“)
  7. Evidenční číslo stroje (unikátní kód majetku)
  8. Hmotnost stroje (kvůli dopravě)
  9. Denní sazba za pronájem
  10. Stav počitadla motohodin při předání
  11. Datum začátku výpůjčky
  12. Datum plánovaného vrácení
  13. Adresa stavby, kam se stroj veze
  14. Jméno stavbyvedoucího na místě
  15. Telefon na stavbyvedoucího
  16. Celková cena výpůjčky (kalkulace)
  17. Stav objednávky (Schváleno/Zamítnuto/Vydáno)
  18. Poznámka k technickému stavu

V kroku 2 se na seznam podíváme kritickým okem a začneme k sobě přiřazovat věci, které spolu logicky souvisejí. Hledáme atributy, které se mění společně, nebo popisují stejný objekt reálného světa.

V kroku 3 mezi výše uvedenými relacemi vytvoříme vazby:

Dále už pokračujeme tvorbou logického schématu a diagramu tříd, jak jsme zvyklí. Všimněte si ještě jednou, jak jsme postupovali:

Výhody a nevýhody

  • přesnost detailů: zachycuje konkrétní požadavky, protože vychází z reálných potřeb (dat)
  • rychlý start: můžeme začít pracovat téměř okamžitě, jakmile dostaneme první vstupy
  • ztráta kontextu: při vysokém počtu atributů se nám může stát, že „pro stromy nevidíme les“ – může chybět strategický pohled na celkovou strukturu
  • chybějící přehled: může být obtížné udržet přehled o celkovém DB modelu zvláště při složitějším návrhu

Kdy použít?

Shora dolů

Tento přístup je jako práce architekta a je sympatičtější strukturovaně přemýšlejícím – nejdříve nakreslíme hrubý obrys budovy, pak jdeme do rozvržení místností, poté detailně do každé místnosti a teprve poté řešíme, kde bude nábytek a zásuvky. Začínáme abstraktním pohledem na business logiku a až potom řešíme detaily.

Postup návrhu

  1. Identifikace relací – určíme hlavní „hráče“ v systému.
  2. Definice vztahů mezi relacemi – nakreslíme si vazby (pomocí ER diagramu), je-li potřeba, dodefinujeme ještě chybějící relace.
  3. Doplníme atributy – teprve když máme kostru, začneme k relacím doplňovat detaily.

Příklad z praxe

Ředitel firmy přijde a řekne – potřebujeme nový systém pro řízení skladových zásob. Databázový analytik si tedy sedne, napíše si seznam entit (relací), které tuší:

Poté si nakreslí ER diagram například takto:

Teprve nakonec si řekne, které relace budou mít jaké atributy:

Možná až při návrhu atributů ještě vyvstane potřeba vytvořit séparé relaci pro výrobce (Goods.Producer) a skladníky (Operation.UserID). Každopádně relace můžeme rozdělit na kmenová data (Storage, StoragePlace, Goods) – tj. data, která se mění málokdy (postavíme nový regál, zavedeme nový produkt) a pohybová (transakční) data (Operation) – tj. data, která se mění velmi často (při každém „pípnutí“ čtečkou).

Výhody a nevýhody

  • koncepční čistota – poskytuje jasný, logický a srozumitelný přehled o celém databázovém systému
  • strategický pohled – odhaluje klíčové vazby dříve, než se začne s programováním
  • abstraktní náročnost – vyžaduje zkušenost analytika, který umí myslet v souvislostech
  • riziko přehlédnutí detailů – snadno se zapomene na drobný, přitom důležitý atribut
  • pomalejší start – trvá déle, než se dostaneme k fyzické implementaci databázového modelu

Kdy použít?

Otázky návrhu databázového modelu

Je atribut dostatečně atomický?

Zde pozor, abychom splnili podmínky relačnosti, musí být hodnoty v jednotlivých buňkách elementární, tj. dále nedělitelné – není možné tedy do jednoho atributu Name umístit hodnotu Magdalena Dobromila Rettigová, protože to jsou tři různé údaje. Ze stejného důvodu není možné do atributu Address uložit hodnotu Otýlie Beníškové 2604, 269 01 Rakovník (jedná se ve skutečnosti o čtyři různé údaje).

Je atribut vypočitatelný?

Klasická otázka, když chceme ukládat do databáze například věk nebo stáří produktu. Mnohem lepší je ukládat datum narození nebo datum vyrobení produktu a aktuální věk či stáří se dá vždy jednoduše vypočítat. Nejhorší případ je, když máme uloženo oboje – datum narození i věk. V tom případě se totiž jedná o redundanci (nadbytečnost), a té se snažíme za každou cenu vyhnout.

Mám použít přirozený nebo umělý primární klíč?

Otázka, která vyvstane vždy při určování primárních klíčů a případů jako například rodné číslo u člověka, ISBN u knihy, VIN u vozu, EAN kód u zboží, atd. Anebo je lepší použít PersonID, které se bude generovat automaticky (AUTO INCREMENT)? Rada je jednoduchá – téměř vždy je bezpečnější umělý klíč (ID), přirozené klíče používáme pouze v případech, kdy je jasné, že se hodnoty již nemohou měnit (výrobní číslo, rodné číslo, VIN, ISBN, atp.), jinak raději sáhneme po umělém klíči.

Mám pro údaj použít pouze atribut nebo samostatnou relaci?

Zde se budeme ptát – váže se k řešenému údaji ještě další údaj? Mohou být hodnoty daného údaje opakovatelné? Jaký je význam daného údaje v kontextu řešené aplikace? Řešíme-li například ukládání názvu města jakožto sídla do relace Zákazníci, můžeme použít samostatnou relaci (číselník) měst a město do relace Zákazníci připojit pouze pomocí cizího klíče. Anebo vytvořit jednoduchý atribut Zakaznici.Mesto jako VARCHAR(32) a dál se o to nestarat.

Rada je zde složitější – jde-li nám více o přesnost, hodnoty mohou být opakovatelné, pak raději volíme samostatnou relaci a spojení pomocí cizího klíče. Jedná-li se o okrajový údaj (a je nám jedno, že uživatel občas napíše hodnotu Rakvoník), pak můžeme zvolit jednodušší cestu pouze pomocí atributu.

Je vazba povinná nebo volitelná?

Otázky typu „Může existovat záznam v relaci Zaměstnanec bez přiřazeného Oddělení?“ nebo „Může existovat Faktura bez přiřazené Objednávky?“. Jestliže řekneme, že každý zaměstnanec musí mít přiřazené oddělení, pak do atributu Zamestnanec.OddeleniID (cizího klíče odkazujícího na Oddeleni.OddeleniID) dáme NOT NULL a zadání vynutíme. Jestliže řekneme, že fakturu můžeme zaúčtovat i bez předchozí objednávky, bude atribut Faktura.ObjID (cizí klíč odakující na Objednavka.ObjID) NULL a zadání povinné nebude.

Co se má dít při smazání „rodičovského“ záznamu?

Vezměme si příklad, že máme v e-shopu uložené zákazníky a jejich objednávky. Vazba Zákazník:Objednávka bude mít kardinalitu 1:N (zákazník může vytvořit více objednávek, ale každou objednávku vytvořil vždy jeden zákazník). Zákazník je tedy jakýmsi pomyslným „rodičem“ objednávky. Co se má ale stát, jestliže smažu zákazníka, který má objednávky?

V praxi máme dvě možnosti: CASCADE (jestliže smažu zákazníka, smažu i všechny objednávky, které vytvořil) nebo RESTRICT (nelze smazat zákazníka, který má objednávky). Nejčastěji volíme RESTRICT (tj. nedovolujeme mazat navazující záznamy), i když občas má význam i CASCADE (jakmile smažu hlavičku objednávky, smažou se i všechny její položky).

Použít několik binárních nebo jednu n-ární vazbu?

Zde se musíme především ptát, jestli existují atributy, které lze přiřadit pouze kombinaci více participujících entit. Vezměme si příklad tří relací: oddělení, zaměstnanec a projekt. Je lepší je spojit pomocí několika binárních vazeb (odděleni:zaměstnanec, zaměstnanec:projekt) nebo jedné n-ární vazby?

Opět záleží na konkrétním využití – o co nám při používání databázového modelu jde? Je pro nás důležitější zaznamenat kteří zaměstnanci pracují v jednotlivých odděleních na jednotlivých projektech? Nebo je pro nás důležitější zapojení zaměstnanců do oddělení, a projektová účast pouze informativní?

Jestliže ale existuje atribut (například AssignedBudget), který nezbytně nutně potřebuje kombinaci všech třech relací, použití n-ární vazby se nevyhneme. Proč potřebujeme všechny tři? Protože na projektu e-shop Wasabi má p. Novotný za IT oddělení přiřazen rozpočet 10 MD, p. Klíma za IT oddělení 5 MD a p. Novotný za oddělení účtárny ještě dalších 5 MD. Navíc může mít 1 MD p. Novotného různou sazbu pracuje-li za IT nebo pracuje-li za účtárnu.

Mění se data v čase a zajímá mě historie?

Co když se zákazník přestěhuje a přepíše si svoji adresu v relaci Customers? Ze stejné relace ale beru data pro generování faktur – adresa se ale na loňských fakturách v žádném případě měnit nesmí – co tedy s tím? Pokud to opravdu vadí, bude lépe mít adresy v séparé relaci a udržovat si ještě informaci o platnosti dat.