Autor Zpráva
Kcko
Profil
Ahoj,

v práci jsme najeli na Nette a kolegové odkoukali nějaké návyky od DGX a dostali jsme se do menšího sporu.

Teoretický příklad: (velmi zjednoduššený .. ptám se ovšem na konkrétní věc)
======================================================

Budeme mít po celém webu možnost diskuse. Diskuse bude svázana s články, videogalerií, fotogalerií ...

Jak bych vytvořil tabulku já, sloupec identifikátor označuje vazbu (tj. na články, videogalerii, fotogalerii atd.)

#comments
==========
id | parent_id | identifikator | <další pro tuto chvíli nepodstatné sloupce>


Struktura kolegů je rozdílná v tom, že by sloupec identifikator ubyl a reprezentoval by tabulku.
Tj by byly v tuto chvíli 3 stejné tabulky comments_articles, comments_videogallery, comments_photogallery ...

Můj návrh byl označen za jakýsi antipatern. Přemýšlím jaké výhody mi jejich řešení nabízí a nenacházím žádný klad.

Přibude nová vazba = nová tabulka
Úprava v nějaké tabulce = promítnout to do všech
Složitější dotazy napříč všemi komentáři (statistiky a další věci) = X UNIONů

Moje řešení je takové, že vše řeším pouze v 1 tabulce, o identifikátorech at už číselných či nečíselných vím a vím co reprezentují, dotaz bude vždy přes 1 tabulku, nikoliv opakující se dotaz viz UNION.

Zdá se mi to nějaké celkově duplicitní a zbytečně roztahané (to jejich řešení).

Jaký je Váš názor?
Tori
Profil
Kcko:
Jak moc se od sebe liší ty "nepodstatné sloupce" v návrhu kolegů?
juriad
Profil
Velký rozdíl je v možnostech kontroly integrity dat (cizí klíče).

Hodně se mi líbí prezentace http://www.slideshare.net/billkarwin/sql-antipatterns-strike-back, ve které autor popisuje tento problém a jaká existují řešení.
Jan Tvrdík
Profil
Kcko:
Nevím, jestli jsem správně pochopil problém, ale zadání „Budeme mít po celém webu možnost diskuse. Diskuse bude svázana s články, videogalerií, fotogalerií “ bych vyřešil následovně:

1) tabulky articles (PK articleId), videogalleries (PK videoGalleryId), photogalleries (PK photoGalleryId)
2) tabulka comments_threads (PK threadId, table[enum article, videogallery, photogallery], FK articleId, FK videoGalleryId, FK photoGalleryId)
3) tabulka comments (PK commendId, FK threadId)
Kcko
Profil
Tori:
Ty nepodstatné sloupce jsem nejmenoval (např. datum uložení, jméno atd.) nejsou vůbec podstatné.

juriad:
Díky mrknu se

Jan Tvrdík:
Tvoje řešení je v podstatě moje řešení akorát více rozvrstvené. Prý je to ovšem antipatern ;), zítra kolegům topic ukáži.

Ještě jednou pro Tori: na co jsem chtěl poukázat, že moje řešení skýtá 1 tabulka s identifikátorem (ENUM, číseldné ID ..to je fuk, pro "objekt" ke kterému je diskuse přifařena .. tj galerie, články ..)

Kolegové si myslí že to je antipatern a že každá takováto diskuse má mít vlastní tabulku (a jsou v ní všechny sloupce stejné, tj můj sloupeček identifikátor se u nich stává vlastní tabulkou).

To je vše co jsem tu chtěl řešit.
Jan Tvrdík
Profil
Kcko:
moje řešení skýtá 1 tabulka s identifikátorem (ENUM, číseldné ID ..to je fuk, pro "objekt" ke kterému je diskuse přifařena .. tj galerie, články ..)
A tohle je ta část, kde se mýlíš. Všechno padá a stojí na tom, jak konkrétně ten identifikátor implementuješ.
Kcko
Profil
Jan Tvrdík:
Jak to myslíš? Nerozumím ...
Jan Tvrdík
Profil
Kcko:
Prostě není jedno, jak bude ten identifikátor vypadat. Právě naopak – to jak bude ten identifikátor konkrétně vypadat je ten hlavní problém, který se tu z mého pohledu řeší (mít více „stejných“ tabulek považuji v tomhle případě od začátku za blbost).
juriad
Profil
Jan Tvrdík, Kcko:
Myslím, že se moc nechápete. Podle mě se řeší, která z následujících variant je lepší.

article (id):
1
2
3

image (id):
1
2
3

1. varianta:
comment(type, ref, text):
article 1 "pekny clanek"
image 3 "no fuj, ty prase"
article 2 "tolik pravopisnych chyb..."

2. varianta:
comment(type, ref_article, ref_image, text):
article 1 NULL "pekny clanek"
image NULL 3 "no fuj, ty prase"
article 2 NULL "tolik pravopisnych chyb..."
Jan Tvrdík
Profil
juriad:
Z toho co jsem pochopil bych řekl, že přesně tohle neřeší, načež jsem se mu snažil vysvětlit, že přesně tohle byl řešit měl. Jo a kdyby to nebylo jasné, tak já jsem jednoznačně pro variantu (2).
Kcko
Profil
Jan Tvrdík:
mít více ‚stejných‘ tabulek považuji v tomhle případě od začátku za blbost
Ano to jsem chtěl potvrdit, myslím si totéž.

Celou dobu se to řeší zda

1)
articles_comments
id | text

photogallery_comments
id | text


videogallery_comments
id | text


nebo

2)
comments
id | text | type (enum: videogallery|articles|photogallery)


Já jsem rozhodně pro 2, ale bylo mi dnes řečeno, že to je dle něčeho v NETTE antipattern a že správný způsob je 1).
Zítra si nechám přesně poukázat na místo v NETTE nebo na důvod jak na to přišli...
Jan Tvrdík
Profil
Kcko:
Podle mě to pořád nechápeš =) Obě varianty jsou (podle mého názoru) špatně. Za správné řešení považuji

3)
comments
type (enum: videogallery|article|photogallery) | article_id | videogallery_id | photogallery_id | text

Nebo-li musíš mít sloupec pro každou z vázaných tabulek. Varianta (2) neumožňuje vytvořit cizí klíč nad sloupcem comments.id.
ninja
Profil
Dělat 3samostané tabulky pro jeden typ obsahu je zvláštní a nemyslím, že by to David nějak podporoval. Rozhodně bych tedy hlasoval pro jednu tabulku, kde budou všechny komentáře.

Jan Tvrdík asi nabízí nejčistší řešení, já bych se ale nebál ani do tabulku komentářů vložit 3 sloupce article_id, image_id, video_id s tím, že u každé řádky budou 2 ze tří null.
Kcko
Profil
ninja, Jan Tvrdík:
Shodujete se ve stejném řešení. Pokud tech objektů / vazeb bude více (momentálně tu řešíme 3, ale dejme tomu 10) tak bude vždy vyplněn 1 a 9 bude NULLovych? To mi tedy přijde tedy zvláštní.

Jinak strukturou id | text | type (enum: videogallery|articles|photogallery) jsem mínil to, že id je PK + AI (pouze identifikátor) a ještě mi zde chybělo relationId které odkazuje do oněch "dalších tabulek" na PK , a tady je to tedy FK.

takže by to mělo být takto

id | text | type (enum: videogallery|articles|photogallery) | relationId

vložit 3 sloupce article_id, image_id, video_id s tím, že u každé řádky budou 2 ze tří null.
Ale jinak opakuji tohle mi přijde divné, obzvlášt při větším počtu vazeb / objektů.
Jan Tvrdík
Profil
Kcko:
Pokud tech objektů / vazeb bude více (momentálně tu řešíme 3, ale dejme tomu 10) tak bude vždy vyplněn 1 a 9 bude NULLovych?
Zjednodušeně ano. Reálně by se ale v takovém množství tabulek pravděpodobně objevily nějaké další skutečnosti, na základě kterých by bylo možné návrh upravit.

ještě mi zde chybělo relationId které odkazuje do oněch "dalších tabulek" na PK , a tady je to tedy FK.
Cizí klíč nemůže odkazovat do více tabulek zároveň. Proto potřebuješ cizí klíč pro každou tabulku. Naproti tomu enum zase tak potřeba není, přidává se především proto, že se s tou strukturou pak lépe pracuje.

Ale jinak opakuji tohle mi přijde divné, obzvlášt při větším počtu vazeb / objektů.
A já opakuji, že to nic nemění na tom, že je to podle mě správné řešení. V konkrétních případech případech může být možné to navrhnout ještě jinak, ale v obecné rovině to považuji za nejlepší řešení. A ano, reálně to tak používám na tabulkách s mnoha miliony záznamů.
Joker
Profil
Jan Tvrdík:
„Pokud tech objektů / vazeb bude více (momentálně tu řešíme 3, ale dejme tomu 10) tak bude vždy vyplněn 1 a 9 bude NULLovych?“
Zjednodušeně ano.
Nebyly by v takovém případě opravdu lepší samostatné tabulky?
juriad
Profil
Nebo jde vytvořit společného předka commentable všem typům, které mohou mít komentáře.
commentable(id PK AI, type)
article(id PK AI, commentable_id FK)
image(id PK AI, commentable_id FK)
video(id PK AI, commentable_id FK)
comment(id PK AI, commentable_id FK, text)

případně, by šlo id a commentable_id scuknout (může sloužit zároveň jako primární klíč i jako cizí klíč):
commentable(id PK AI, type)
article(commentable_id PK FK)
image(commentable_id PK FK)
video(commentable_id PK FK)
comment(id PK AI, commentable_id FK, text)

Osobně bych použil variantu, kterou navrhuje Jan Tvrdík; pokud by však bylo příliš mnoho (5 a víc) různých komentovatelných typů nebo by bylo bylo zřejmé, že jejich počet ještě poroste, mohlo by se vyplatit přidat tabulku commentable, která jakoby obrací směr vazby.

Vaše odpověď


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: