Návrh databáze

Školení, která pořádám

Při vytváření webové aplikace, která načítá nebo ukládá nějaká data, je jedním z nejdůležitějších prvních kroků správný návrh datových struktur, ve kterých budou tato data uchována. V první řadě musím doporučit pro ukládání dat zásadně používat databáze. K webovým aplikacím totiž může přistupovat více uživatelů najednou a např. při ukládání dat do souborů se nevyhnete nutnosti tyto soubory např. správně zamykat. Kromě toho databáze nabízí nesrovnatelně větší komfort při jakékoliv manipulaci s daty.

Optimálnímu návrhu databáze se věnují celé teorie, obvykle ale stačí používat selský rozum a dodržovat několik zásad:

  1. Hodnoty v jednotlivých sloupcích tabulek by měly být vnitřně nedělitelné. Je tedy např. lepší ukládat samostatně Křestní jméno a Příjmení než celkové Jméno. Správně by odděleně mělo být uloženo např. i Ulice a Číslo popisné, to mi ale připadá už jako zbytečné pedantství.
  2. Data by měla být ukládána do sloupců správných typů. Nebojte se používat typy ENUM nebo DATE. Pokud pro některá data neexistuje odpovídající databázový typ (např. telefonní číslo), zvolte a používejte pro něj jednotný formát (nejlépe podle již existující normy).
  3. Jednotlivé řádky by měly mít jednoznačný identifikátor (primární klíč) nezávislý na uložených datech. Nezávislost na datech je důležitá kvůli možnosti libovolná data změnit, skutečných jednoznačných identifikátorů navíc ve skutečném životě není moc (nelze se spolehnout např. ani na rodné číslo). Tento identifikátor se nikde nemusí zobrazovat, ale použije se při aktualizaci nebo mazání záznamů, při odkazování na záznam z jiných tabulek a podobně. V MySQL lze s výhodou použít modifikátor AUTO_INCREMENT, jinde se obvykle používají sekvence.
  4. Veškerá data kromě odkazů na primární klíče by v databázi měla být uložena právě jednou. Tedy např. tabulka vyrobky(id int, nazev varchar(100), skupina varchar(50)) je navržená špatně, správný návrh zahrnuje dvě tabulky – vyrobky(id int, nazev varchar(100), skupina int) a skupiny(id int, nazev varchar(50)). Pokud se data opakují, vede to k neefektivitě (jak paměťové, tak výkonnostní) a zhoršuje se možnost úpravy dat a případného rozšiřování databáze (např. situace, kdy bychom kromě názvu skupiny chtěli evidovat také pořadí skupiny při výpisu). Pokud se jeden výrobek může nacházet ve více skupinách, obsahuje správný návrh tři tabulky – vyrobky(id int, nazev varchar(100)), skupiny(id int, nazev varchar(50)) a vyrobky_skupiny(vyrobek int, skupina int).
  5. Návrh databáze by měl být pevný a webová aplikace by ani neměla mít právo modifikovat strukturu existujících tabulek nebo vytvářet tabulky nové. Viděl jsem aplikaci, která pro každé diskusní fórum vytvářela tabulku s jeho příspěvky, tedy něco jako prispevky_id_skupiny(id int, autor varchar(50), zprava text). Takto navržená databáze je rychle zamořená spoustou tabulek, takže např. příkaz SHOW TABLES se stává v podstatě nepoužitelný, a jakékoliv změny ve struktuře nebo datech tabulky jsou mnohem pracnější. Správný návrh je prispevky(id int, skupina int, autor varchar(50), zprava text), při správně navržených indexech samozřejmě ani neutrpí výkon.

Dobrou zásadou je také ukládat opravdu všechna data do databáze a ne např. přímo do PHP kódu. Při vytvoření vhodného administračního rozhraní vás pak uživatel aplikace nemusí obtěžovat ani v případě, kdy bude chtít změnit nějakou zdánlivě neměnnou položku jako např. cenu poštovného a balného nebo výši DPH.

Přijďte si o tomto tématu popovídat na školení Návrh a používání MySQL databáze.

Jakub Vrána, Výuka, 2.5.2005, diskuse: 20 (nové: 0)

Diskuse

Erix:

"by ani neměla mít právo modifikovat strukturu existujících tabulek"
Prave premyslim, jak vytvorit vicejazycny web. Mel jsem v hlave tabulku se strukturou, kde kazdy radek by predstavoval jeden urcity vyraz
a sloupce jednotlive jazyky. Ale prave pri pridavani dalsiho jazyka by se modifikovala tabulka pridanim dalsiho sloupce. Jak lepe byste to resili?
Erix

ikona dgx:

Asi bych vytvořil tabulku se třemi sloupci:

ID výrazu (řetězec)
ID jazyka (dva znaky)
přeložený výraz (řetězec)

(ID výrazu + ID jazyka) by tvořilo primární klíč.

Takže přidání dalšího jazyka by znamenalo jen přidání řádků do tabulky.

ikona Jakub Vrána OpenID:

Nechci "kázat vodu a pít víno", takže přiznávám, že modifikaci struktury tabulek kvůli přidání jazykové verze pokládám za nejmenší zlo. Mám o tom napsaný článek, vydám ho ve středu.

tom:

delat vicejazycnou verzi pres ukladani do dbs je podle me zbytecne, staci vyuzit definovani vlastnich konstant do nejekeho souboru a ten si nacitat

ikona Jakub Vrána OpenID:

Myšlena je situace, kdy např. u výrobku má být uložen např. jak anglický název, tak český. To přes konstanty dost dobře dělat nejde.

crook:

Vyrobek ID Angl verze + nazev
Vyrobek ID Ceska verz verze + nazev ID jsou samozrejme stejna

DaMage:

Ak ide o jazykové mutácie systému (nie článkov), ja využívam jazyky v XML, hodnoty načitávam pomocou SimpleXML... celkovo vratane štruktury frameworku je to pod 50 riadkov kódu

Llaik:

K posledni vete - to je mysleno tak, ze na kazde te strance budu mit minimalne o jeden dotaz do db vice jen proto, abych si vytahl hodnoty, ktere se meni jednou za X let?

Vas databazovy server vas musi mit rad:)

ikona dgx:

Pomiňme fakt, že takové dotazy jsou nesmírně rychlé a že vše se dá ještě vylepšit chytrým kešováním.

Obecně jde o to, že v dnešní době máme gigaherzové procesory za pár korun a doslova nadbytek strojového času. Pokud se využije ke zkvalitnění kódu, tedy jako režie dobrých programátorských technik, je to jen dobře.

Uvědomte si, že při rozšířování prasácky napsané aplikace vyhodíte stovky hodin práce jen kvůli hledání chyb a testování. Zatímco s křištálově čistým kódem je radost pracovat. A třeba tři stovky hodin programátora po 800,- Kč dělají v přepočtu 100 rychlých procesorů Pentium 2.4

maro:

Uvítal bych i nějaký článek o kešování. dík

JersyWoo:

K nějakému článku o kešování se přidávám taky.

Llaik:

No pokud mam na stranku 200 hitu za vterinu, tak to znamena dalsich 200 dotazu za vterinu.

V pripade, ze se mi jeden update zdrzi o 0.1s, tak za nim ceka ve fronte dalsich 200 dotazu, za kterymi muze cekat dalsi update...

Jiste, v tomto pripade je to spatne navrzena db, ale co tim chci rici - proc delat naprosto zbytecne dotazy? Kvuli jednodussi administraci? Pokud se ta data meni jednou za rok, v cem je problem napsat administracni system, ktery hodnoty ulozi do konfiguraku na disk ke zbytku nastaveni?

ikona dgx:

>> ktery hodnoty ulozi do konfiguraku na disk ke zbytku nastaveni?

ano, to je právě to kešování. Data mohou být v databázi a při změně se v nějaké v(ý)hodné formě uloží na rychleji přístupné místo.

Solvina:

"Optimálnímu návrhu databáze se věnují celé teorie, obvykle ale stačí používat selský rozum a dodržovat několik zásad"

Jirka ma jiste pravdu. Nicmene o normalnich formach by mel slyset (a neco si precist) opravdu kazdy. Ony se vlastne ani moc nelisi od tech principu popsanych v clanku.

lamka:

Jo, jenom člověk který ty xNF zná, může pracovat mnohem efektivněji, protože ví co dělá a kdy je která podoba dat výhodná. Narozdíl od lamy která slepě opakuje jakási dogmata.

K poznámce o rozdělení jméno, příjmení a ulice, číslo:

Všiml jste si pane geniální autore, že některé obce nemají ulice? Nebo že někteří lidé mají kromě jména a příjmení ještě něco jiného? Možná tomu navrhování db nerozumíte až tak jak si myslíte.

ikona Jakub Vrána OpenID:

"Všiml jste si pane geniální autore, že některé obce nemají ulice? Nebo že někteří lidé mají kromě jména a příjmení ještě něco jiného?"

No a? Pokud mě zajímá jen křestní jméno a příjmení, tak se o nic dalšího starat přeci nemusím. A pokud nejsou v obci ulice, tak je neukládám. Pokud jsou uloženy dohromady s číslem popisným, používá se "č. p.".

Nějak nerozumím, o co vám jde. Možná by bylo lepší napsat něco konstruktivního než štěkat, že tomu nikdo kromě lamky nerozumí.

migon:

osobne a na velkych projektech zvlast mam v php ulozeny jen pristup k DB a konfig je celej v DB nikdy totiz nevim kdy budu muset neco pridat a pak je IMHO DB lepsi
ale to je jen muj nazor

Kudlanka:

Při normalizaci databáze je třeba dbát na výkonnost. Striktním dodržováním normalizačních forem může dojít k zahlcení databáze. Nejčastějším případem  jsou joiny přes více než 3 tabulky, kdy např. načítáme číselníkové hodnoty.

Používejte diakritiku. Vstup se chápe jako čistý text, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL: Reakce na: Kudlanka

Druid:

Mám dotaz ohledně návrhu databáze, monitoruju zařízení do logu, soubor. Sleduje se 8 hodnot cca po minutě. Jak správně pro toto nazvrhout databázy, co den to tabulka nebo co hotnota to tabulka? Z hodnot se budou dělat většinou dení grafy na příč přez dny to půjde jen minimálně. Děkuji za podměty.

ikona Jakub Vrána OpenID:

Každá hodnota bude jeden sloupec. Každé měření jeden řádek. Vše v jedné tabulce.

Rád bych vás pozval na školení http://php.vrana.cz/skoleni-navrh-a-pouzi…-databaze.php.
avatar © 2005-2018 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.