Fórum Root.cz

Hlavní témata => Vývoj => Téma založeno: Urvustrop 25. 04. 2019, 13:18:45

Název: Návrh relační databáze
Přispěvatel: Urvustrop 25. 04. 2019, 13:18:45
Nechci někomu na potkání vykládat know-how, ani nežádám vyzrazení suprfičur ostatních. Spíš chci dát prostor ostříleným architektům, aby se pochlubili svým originálním přístupem a inspirovali jiné ztracené duše.
Nastíním problém, který jsem řešil u nás a zároveň předložím řešení, které momentálně používáme:

Vyvíjíme nástroj pro vytváření formulářových aplikací. Je psaná ve WPF, datovou část stavíme nad MSSQL. Klíčem je pro nás silně relační databáze. Výhodou je následná vizualizace její struktury v návrháři datových zdrojů (přes cizí klíče je možné se "proklikat" hlouběji a vynášet sloupce, které jsou potřeba).
Pomocí tohoto nástroje, který obsahuje rozšířené formulářové kontrolky a další komponenty, se poskládá celá appka podle potřeb zákazníka. Její skládání mají na starost implementátoři.

Momentálně vytváříme aplikaci pro evidenci blíže nespecifikovaných objektů, pro účely dalšího popisu řekněme auta a jejich součásti. Objekty jsou mezi sebou svázány (kolo je namontované na nějaké auto). Nad objekty jsou vytvářené různé agendy (např. tickety, platnost kontrol, ...).
Problém je, že objektů je spousta druhů, každý druh má své specifické vlastnosti, které jsou irelevantní pro jiné druhy (auto má počet náprav, které jsou pro kola nesmyslnou vlastností, a naopak poloměr je pro kolo fajn, ale evidovat ho u auta je jaksi zbytečné).
Rozhodli jsme se proto, že objekty budeme dělit do skupin a pro každou skupinu bude vytvořena konkrétní tabulka s potřebnými sloupci. S tím samozřejmě přišla spousta problémů, například jednoznačný identifikátor, který by byl snadný k vygenerování a přesto dostatečně rychlý při vyhledávání (GUID je z hlediska rychlosti tragický). Nebo způsob, jak propojit přes cizí klíče tyto tabulky s tabulkami jednotlivých agend. V neposlední řadě je tu samotné zobrazení dat v aplikaci - jak v seznamu ticketů vypsat jméno objektu, když je pokaždé uložené v jiné tabulce?
Po řadě pokusů a omylů jsme dospěli k řešení, které jistě není dokonalé, ale momentálně splňuje naše požadavky. Pomocí řady triggerů, funkcí, procedur a jiných hrůz jsme zapracovali do struktury databáze tabulku, která funguje jako most mezi tabulkami objektů a tabulkami agend. Toto přemostění obsahuje primární autoinkrementální klíč, který je používaný jako cizí klíč v tabulkách agend a zároveň jako cizí klíč u jednotlivých řádků v tabulkách objektů. Pod každou objektovou tabulkou je vygenerovaný AFTER INSERT, DELETE trigger, který po insertu řádku objektové tabulky vytvoří nový řádek v tabulce přemostění a Id vytvořeného řádku následně vloží do řádku s objektem, který trigger spustil. Toto Id je používáno ve všech místech aplikace - agendy, hierarchie objeků, atd. Obdobná automatika funguje při mazání.
Další tabulka slouží k evidenci skupin (její název, název tabulky). Pod touto tabulkou je trigger, který má na starost generování view, které dává k dispozici přehled všech evidovaných objektů a jejich základních vlastností (evidenční číslo, název, ...). Při vytvoření nové skupiny je select view triggerem upravený tak, aby prováděl union i z tabulky nové skupiny. Implementátor pak ví, že přehled objektů je v tomto view a při vytváření datového zdroje formulářů agend chodí pro vlastnosti objektů právě sem (je to prakticky jediná situace, kdy nemůže při vytváření datového zdroje jednoduše procházet vazby mezi tabulkami).
Tímhle molochem je zajištěná integrita dat (nelze smazat objekt, na který je vystaven ticket apod), každý objekt má svůj jednoznačný identifikátor, a zároveň není v databázi hypertabulka, která by musela obsahovat stovky sloupců, aby zahrnula všechny evidovatelné vlastnosti.

Popsaný přístup má samozřejmě i své nevýhody. Mezi největší momentálně řadím nemožnost/náročnost přesunu objektu z jedné skupiny do druhé.

Řešili jste někdy něco podobného? A jak?
Název: Re:Návrh relační databáze
Přispěvatel: Filip Jirsák 25. 04. 2019, 14:15:07
Já bych váš text parafrázoval jako „nejprve jsme se rozhodli pro silně relační databázi, ale pak jsme otočili a z databáze jsme udělali jen nestrukturované úložiště“. Možné jsou oba přístupy, každý má své výhody a nevýhody. Pokud chcete ukládat nestrukturovaná data, jsou na to obvykle lepší NoSQL databáze. Pokud byste chtěli „silně relační databázi“, znamená to zapomenout na nějaké skupiny objektů a univerzální tabulky, ale prostě v databázi opravdu namodelovat to, co chcete řešit. Takže když máte auta a kola, budete mít tabulku aut a tabulku kol, přičemž v tabulce kol bude odkaz do tabulky aut. Ano, znamená to vytvořit velké množství tabulek, ale tohle je model, kdy hodně využíváte vlastností relačního databázového modelu.
Název: Re:Návrh relační databáze
Přispěvatel: Logik 25. 04. 2019, 14:22:46
Já bych v takovémto případě velmi silně přemýšlel nad kombinací SQL a noSQL přístupu. Tedy objekty všechny v jedné tabulce, a ty variabilní vlastnosti uložené jako json.

Nevím, jak přesně umí MSSQL s json, ale v postgresql se s tím krásně pracuje, včetně indexace.

Jediné, co mne teď napadá, že to z běžných věcí neumí, jsou cizí klíče (na položky jsonu), ale to jde v případě potřeby dopsat trigerama.
Název: Re:Návrh relační databáze
Přispěvatel: Urvustrop 25. 04. 2019, 14:29:48
Filip Jirsák: Tenhle postup by se mi taky líbil, problém je v tom, že Monitor má cizí klíč ParentId, což může být Počítač z tabulky Pocitace, ale také DVD přehrávač z tabulky dbo.ElektronickaZarizeni. Je to ten samý atribut, ale pokaždé směřuje jinam.
Nevím, jestli jsme se náhodou špatně nepochopili, ale nevidím nic nerelačního na tom, když všechny tabulky se skupinami objektů mají cizí klíč MostId do tabulky dbo.Most, a všechny agendy se odkazují cizím klíčem MostId do téže tabulky.

Logik: Snažit se držet vazbu triggery je dle mého cesta do pekel.
Název: Re:Návrh relační databáze
Přispěvatel: KarelE 25. 04. 2019, 14:36:51
Řešili, několikrát. Používáme tyto tři šablony:

1. Item Extension Codes

A. Máme tabulku položek, kde jsou její základní údaje (branch plant, item number, item description, item type, gl class atd.)
B. A pak máme tabulku "Item Extension Codes", která má PK stejný jako ta první. V té máme cca 120 sloupců pojmenovaných stylem "number01, number02, date01, date02, text01,..."
C. Další tabulka je tabulka IID. Má sloupce Branch Plant, IID Key, IID Value a IID Description. Typický záznam je Branch Plant 728 (Brno), IID Key VPRODTYPE, IID Value "S2", IID Description "NHP SAS 2.5 10K"
D. A nakonec existuje tabulka "Extension Code Definition", kde je primárním klíčem Branch Plant, Item Type a FieldName. Další sloupec je Description, příznak Mandatory a IID Key. Do té se při nastavování databáze třebas napíše, že pro Branch Plant 728 (Brno) a Item Type IM (vyráběná položka) se sloupec "text05" jmenuje "Vendor Product Type", Mandatory má nastaveno na "yes" a IID klíč je "VPRODTYPE".

Celé to pak funguje tak, že založím položku v první tabulce. Do té druhé můžu ale nemusím. Pro tu druhou funguje formulář tak, že je tam tuším na třech záložkách až stovky políček. Systém sám podle tabulky z bodu D ví, které zobrazit (mají mandatory yes nebo no) a které ne (nemají záznam nebo mají mandatory disabled). Z tabulky D pak i nastaví správný popisek daného pole. Takže pro každý typ položky (nakupovaná, vyráběná, polotovar, fiktivní atd.) se zobrazí jen ta pole, která sleduji. Tabulka C se pak používá na kontrolu zadaných hodnot - pokud tabulka D specifikuje nějaký klíč, tak se zaprvé uživateli nabízí seznam hodnot a zadruhé se ověřuje, že vybral některou z nich.

Přidat nový atribut je pak o tom najít si pro danou pobočku a typ položky dosud nepoužité pole a udělat pro něj záznam do tabulky D.

2. Item Cross References

A. Máme tabulku položek, kde jsou její základní údaje (branch plant, item number, item description, item type, gl class atd.)
B. Mámě tabulku Item Cross Reference Type. Primární klíč je XType. Jediný další je sloupeček Description. Hodnoty typu VP = Vendor Part Number, EM = Customer Model Number atd.
C. A finálně tabulka Item Cross Reference, kde primární klíč je Item Number, Address Number a XType.

Do tabulky A se vkládají položky. Ke každé je pak možné do tabulky C přiřadit další údaje. Tím, že je v tabulce C v primárním klíči i Address Number, tak můžete mít jeden údaj (například Customer Part Number) pro různé address booky jiný. Address Book je typicky ID zákazníka, ID dodavatele, ID nákupčího apod. Takže když někomu dodáte svou položku 3731052, tak mu můžete na dodací list napsat číslo, jaké chce on. Což je docela běžné, že stálí zákazníci chtějí objednávat podle jejich čísla položky. A pokud jednu položku dodáváte více zákazníkům, tak se vám tahle vlastnost tabulky C dost hodí.

3. Kaskáda tabulek

A. Máme základní tabulku, například Transaction. Primární klíč ID transakce. Další sloupce typu datum transakce, účetní datum, typ transakce, celková částka atd.
B. K ní máme další tabulku, například InventoryTransaction. Primární klíč je stále to samé ID transakce a má FK na tabulku Transaction. Přidává další sloupce typu Item Number, Quantity, Unit of Measure, Branch Plant atd.
C. A máme i jinou tabulku, například PaymentTransaction. Primární klíč stále to samé ID transakce a opět FK na Transaction. Přidává sloupce typu VAT Code, Net Amount, atd.
D. A ještě jiná tabulka pro EventTransaction. Klíč stále stejný a opět FK na Transaction. Navíc sloupce jako EventId, EntryType, AuthorizationMethod atd.

Každá transakce je pak v tabulce A s tím, že dodatečné údaje má v některé z dalších tabulek podle typu transakce. Tohle se používá ve chvíli, kdy mám několik typů daného objektu, které ale znám už ve fázi návrhu. Výhoda je v tom, že všechny sloupce můžete hezky navázat přes foreign key a obecně se s tím dělá trochu lépe.

--- Co vybrat ---

Metoda 1 je docela snadná na implementaci a dělá se k ní i hezké uživatelské rozhraní. Dobře se pro to píší sestavy. Blbě se s tím ale dělá cokoliv obecného. Do té míry, že vám sestava pro Brno nebude fungovat v Ploveru, protože tam mají stejný údaj v jiném sloupci, protože ten původní už roky používali pro jiného zákazníka.

Metoda 2 má výhodu v tom, že k jedné položce nejen že máte libovolný počet dodatečných údajů, ale dokonce pro každého zákazníka/dodavatele jinou hodnotu. Hůř se proto ale dělá uživatelské rozhraní - zaprvé nevíte který z definovaných 84 typů Cross Reference máte nabídnout, zadruhé z toho hezké okénko neuděláte už proto, že dopředu nevíte pro kolik různých zákazníků uživatel bude chtít vyplnit End Customer Model Number.

Metoda 3 je velmi jednoduchá na implementaci. Vše je předem dáno a vy si můžete snadno vytvářet formuláře, sestavy, integritní omezení apod. Nevýhoda je v tom, že za běhu už nic nezměníte. A skrytá nevýhoda je v tom, že se vám v průběhu let začnou vývojáři v té kaskádě tabulek ztrácet a budou mít tendenci to lepit novými tabulkami.

Všechny mají výhodu v tom, že máte jednu tabulku A, kde máte definované všechny položky/transakce apod. Základ formuláře nebo sestavy tedy má jediný zdroj, jedinou tabulku. Stejně tak tabulky typu kusovník se budou odkazovat přes FK právě do tabulky A. Jediné, co si pak musíte dolepit jinak, jsou dodatečné informace.
Název: Re:Návrh relační databáze
Přispěvatel: Filip Jirsák 25. 04. 2019, 14:46:13
Filip Jirsák: Tenhle postup by se mi taky líbil, problém je v tom, že Monitor má cizí klíč ParentId, což může být Počítač z tabulky Pocitace, ale také DVD přehrávač z tabulky dbo.ElektronickaZarizeni. Je to ten samý atribut, ale pokaždé směřuje jinam.
Nevím, jestli jsme se náhodou špatně nepochopili, ale nevidím nic nerelačního na tom, když všechny tabulky se skupinami objektů mají cizí klíč MostId do tabulky dbo.Most, a všechny agendy se odkazují cizím klíčem MostId do téže tabulky.
V relačních databázích to není ten samý atribut, byly by to dva různé atributy ParentPočítačId a ParentElektronickazarizeniId. Plus kontrola, že vyplněn je právě jeden.

Pokud ty typy, na které se odkazujete, tvoří strom (např. počítač a DVD mají společného předka, na kterého by mohl odkazovat Monitor.ParentId), dalo by se to v PostgreSQL řešit pomocí dědičnosti tabulek.

Záleží hlavně na tom, kolik tam takových vazeb máte. Pokud monitor může odkazovat na dva tři různé typy, můžete použít ty různé sloupce. Pokud množství vazeb je spíš „každý s každým“, není relační model asi ten nejvhodnější a zvážil bych grafovou databázi.
Název: Re:Návrh relační databáze
Přispěvatel: Kit 25. 04. 2019, 14:48:55
Záleží na tom, co od toho chcete. Dá se to pojmout třeba i tak, že jedno auto == jeden záznam v MongoDB. Všechny jeho komponenty budou nacpány do jednoho JSONu jako dokument. Pro některé UC to může být naprosto vyhovující, pro jiné nikoli.
Název: Re:Návrh relační databáze
Přispěvatel: Logik 25. 04. 2019, 15:09:19
Urvustop: Pokud jde o konkrétní implementaci jednoho cizího klíče do JSONu, kde je problém? V čem je to cesta do pekel? Ten trigger bude mít naprosto jasnou sémantiku, je to obecné, bez problémů rozšiřitelné řešení, pro další vývoj naprosto transparentní (nijak se nelišící od "nativních" FK). Kde je ta cesta do pekel?

===

Fór je v tom, že tato situace nemá dobré řešení. Něco musíš oželit. A furt radši jednou napíšu vlastní implementaci foreign key, abych pak s databází pracoval naprosto standardně, než používal antipatterny typu EAV, nebo ukládání vlastností do políček number01, number02, number03, ani se ti databáze nerozpadá na padesát milionů tabulek, kde řešíš klasické problémy s mnohonásobnými dědičnostmi.

Řešení s JSON a explicitně napsaným triggerem neporušuje žádné databázové paradigma. Řeší problém "řídkých dat" pomocí nástroje na ukládání řídkých dat - a jen si dopíšeš jednu operaci, kterou (zatím) současná verze postgresu neumí.

Jiné zde navržené postupy zpravidla ohýbají relační databáze a práce s takovým systémem bude dřív či později na palici. Protože se snaží nacpat řídké struktury do

plných matic, což prostě rozumným způsobem nejde a ať se to "vobčůrá" jakkoli, tak to bude vždycky jen "vobčůraný". Ať uděláš s kladivem cokoli, na šroubování to bude pořád hodně nešikovnej nástroj.

Filip, Kit:
Grafové a jiné nosql databáze jsou sice dobré, ale do té doby, než s nima chce člověk pracovat v součinnosti s věcma, které má v SQL databázi. Např. proto se prosazují "in-databaze" fulltexty, protože fulltext mimo databázi může být nakrásně rychlejší, lepší a nevím co, ale když chceš kromě fulltextu filtrovat ještě podle dalších X kritérií, tak je to na palici. Navíc rozdělení dat do dvou databází musíš řešit takové lahůdky, jako synchronizace transakcí atd. atd....
A protože se na většinu věcí SQL hodí hodně dobře, zpravidla je lepší cesta používat nosql rozšíření SQL databází - např. ten json sloupec - než data dělit do dvou různých databází, anebo se zcela zbavovat možností SQL (a ukládat vše do noSQL databáze).

Název: Re:Návrh relační databáze
Přispěvatel: Urvustrop 25. 04. 2019, 15:26:32
KarelE:
Díky za skvělý popis. U všech tří metod mě napadá otázka: Jak ošetřujete zabalení ukládání změn do transakce? Pokud máte například u první metody formulář rozdělený na záložky, musí uživatel provádět ukládání na každé zvlášť, nebo volání tří updatů (pro každou záložku) provedete transakcí?
V prvních verzích jsme měli také nespecifikované univerzální sloupce, ovšem naráželi jsme na dva zásadní problémy. Prvním bylo zpřístupnění dat za účelem integrace ve formě pochopitelné pro druhou stranu. Vytvoření pohledu z tabulky, kdy pro různé řádky představuje jeden sloupec různé atributy, bylo značně komplikované, a výsledek byl navíc statický a musel se upravovat při vytváření dalších typů objektů.
Druhým problémem byl přesun objektu z jednoho typu do druhého - sloupec v tu chvíli znamenal něco jiného, opět to končilo specifickou jednorázovou operací, jejíž vytvoření zabíralo zbytečný čas.

V relačních databázích to není ten samý atribut, byly by to dva různé atributy ParentPočítačId a ParentElektronickazarizeniId. Plus kontrola, že vyplněn je právě jeden.
Takový přístup podle mě není správný. N-sloupci vyjadřujete jednu vlastnost, nehledě na to, že musíte provádět další ošetření. Opět nevidím nic špatného na tom, že sloupec ParentId odkazuje do tabulky, která obsahuje řekněme core objektů, a tabulky skupin obsahují jejich vlastnosti.

Aplikace je tvořena s důrazem na co největší univerzálnost a obecnost (bohužel). Tedy například parent objektu může být jakýkoliv jiný objekt (pochopitelně jen jeden).

A co jsem měl zmínit nejspíš hned na začátku: Použité technologie (MSSQL+C#) jsou kvůli oblasti trhu, ve které působíme, nedotknutelné.
Název: Re:Návrh relační databáze
Přispěvatel: Ondrej Nemecek 25. 04. 2019, 15:55:16
Filip Jirsák: Tenhle postup by se mi taky líbil, problém je v tom, že Monitor má cizí klíč ParentId, což může být Počítač z tabulky Pocitace, ale také DVD přehrávač z tabulky dbo.ElektronickaZarizeni. Je to ten samý atribut, ale pokaždé směřuje jinam.
Nevím, jestli jsme se náhodou špatně nepochopili, ale nevidím nic nerelačního na tom, když všechny tabulky se skupinami objektů mají cizí klíč MostId do tabulky dbo.Most, a všechny agendy se odkazují cizím klíčem MostId do téže tabulky.

Logik: Snažit se držet vazbu triggery je dle mého cesta do pekel.

Nevím jestli jsem pochopil celé téma diskuze, nicméně podotýkám, že v některých ORM existuje Polymorphic associations (ActiveJDBC, Hibernate). Např. Image má parent_id a parent_type, takže lze přiřadit k různým typům záznamu (třeba Section i Article) - typ se zjistí z parent_type. Databázově to sice tak čisté ale občas to může být vhodné řešení.

Název: Re:Návrh relační databáze
Přispěvatel: redustin 25. 04. 2019, 16:33:47
Používáme už skoro 20 let defakto ORM uložení do SQL - objekty a vazby mezi nimi.

Tabulka objektů se základními parametry objektů (ID objektu, ID typu objektu, název, datum vytvoření, přístupová práva atd.). ID typu objektu odpovídá příslušné třídě v javě - potomku InfoObject. Přímo třída objektu může nést už byznys kód, protože jsou vytvořené pro konkrétní účel (téma, dokument, uživatel, firma, skupina, obrázek, žádost, atd. atd.).

Pak je evidenční tabulka atributů, která obsahuje typ (string/int/date/JSON) a ID typu atributu. Stále častěji používáme typ JSONAttrib. Opět typu atributu odpovídají třídy v javě.

Každý atribut má vlastní tabulku attr_IDatributu se sloupcem value dle jeho typu a samozřejmě id_obj s navázáním na objekt.

Tabulka relations s ID typu vazby, id_obj_from, id_obj_to + pár dalších údajů. ID vazby odpovídá příslušné třídě v javě - potomku Relation. Přímo třída vazby může nést už byznys kód, protože je pro konkrétní účel a obvykle si i kontroluje, zda se ji snažíme vázat na správný typ objektu.

Je nad tím poměrně robustní vrstva v javě, která vše přes weak vazby kešuje v paměti. Paměť je dnes velice levná. DB slouží pro perzistenci a pro vyhledávání.

Tabulka 4 mil. objektů cca 100 typů,  1000 tabulek atributů, tabulka 20 mil. vazeb cca 150 typů. Vše provázané cizími klíči přes objID včetně fulltextových tabulek - při odstranění objektu se vyčistí všechny jemu odpovídající záznamy v DB. MariaDB + innodb zcela v pohodě. Hledání je svižné i při hodně komplikovaných query (spoustu podmínek na atributy a vazby, left joiny atd.). Je fakt, že má MariaDB na produkčních serverech nastavené celkem dost RAM (100GB) a vše samozřejmě na SSD (nové servery na PCIe NVMe).

Problém je fulltext. Máme interní indexátor nad atributy textového typu přímo v mysql, ale ten neumí spoustu fulltextových vychytávek, takže bokem defakto elastic search s asynchronní aktualizací z objektové vrstvy a to není úplně dobré. Jenže kvalitní fulltext (více jazyků, přibližná hledání) je opět elasticsearch...

Drží to dobře, asi bych to dneska dělal znovu podobně, noSQL DB zatím pořád nějak nevěřím, mongo mě pro tyto účely rozhodně nepřesvědčilo (máme pro statistiky přístupů, cca 100 mil. objektů). Jenom ten fulltext je problém, snad se nativní fulltext mariadb posune (podpora více jazyků apod...)
Název: Re:Návrh relační databáze
Přispěvatel: Ondrej Nemecek 25. 04. 2019, 16:54:16
Používáme už skoro 20 let defakto ORM uložení do SQL - objekty a vazby mezi nimi.

Tabulka objektů se základními parametry objektů (ID objektu, ID typu objektu, název, datum vytvoření, přístupová práva atd.). ID typu objektu odpovídá příslušné třídě v javě - potomku InfoObject. Přímo třída objektu může nést už byznys kód, protože jsou vytvořené pro konkrétní účel (téma, dokument, uživatel, firma, skupina, obrázek, žádost, atd. atd.).

Pak je evidenční tabulka atributů, která obsahuje typ (string/int/date/JSON) a ID typu atributu. Stále častěji používáme typ JSONAttrib. Opět typu atributu odpovídají třídy v javě.

Každý atribut má vlastní tabulku attr_IDatributu se sloupcem value dle jeho typu a samozřejmě id_obj s navázáním na objekt.

(...)

Pokud to dobře chápu, máte tam Entity–attribute–value model (EAV (https://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value_model))? Pokud ano, bylo by dobré zmínit, že to ledaskdo považuje za antipattern. Což samozřejmě neznamená, že to nemůže fungovat, otázkou je pracnost a vlastnosti.
Název: Re:Návrh relační databáze
Přispěvatel: Filip Jirsák 25. 04. 2019, 17:03:56
Takový přístup podle mě není správný. N-sloupci vyjadřujete jednu vlastnost, nehledě na to, že musíte provádět další ošetření. Opět nevidím nic špatného na tom, že sloupec ParentId odkazuje do tabulky, která obsahuje řekněme core objektů, a tabulky skupin obsahují jejich vlastnosti.
Podle mne je to přístup, pro jaký byly relační databáze navrženy. Z hlediska relačních databází to není jedna vlastnost, je to několik vlastností, protože se odkazujete na různé tabulky. Relační model vychází z toho, že vše vyjadřujete jako tabulky a vazby mezi tabulkami, nic jako polymorfismus původní relační model nezná.

Já neříkám, že ten váš model je špatný – jenom to není relační model, ale spíš asi objektový, který do relačního modelu serializujete. Na tom není nic špatného, dělá se to tak často, akorát je dobré to vědět, nemyslet si, že mám „silně relační model“, a také k tomu tak přistupovat – např. počítat s tím, že nedokážu prostředky relačního modelu zajistit konzistenci dat. Můžu se ji pokusit zajistit v databázi imperativně (pomocí triggerů nebo procedur), ale relační databáze nejsou úplně nejlepší nástroje pro imperativní programování.

Aplikace je tvořena s důrazem na co největší univerzálnost a obecnost (bohužel). Tedy například parent objektu může být jakýkoliv jiný objekt (pochopitelně jen jeden).
Univerzálnost je v přímém rozporu s tím, k čemu je určený relační model databáze. Opět, není na tom nic špatného, ostatně proto vznikly různé NoSQL databáze – a proto si před nimi kde kdo implementovaly svá key-value nebo entity–attribute–value řešení nad relačními databázemi.

A co jsem měl zmínit nejspíš hned na začátku: Použité technologie (MSSQL+C#) jsou kvůli oblasti trhu, ve které působíme, nedotknutelné.
Jestli se nepletu, má MSSQL slušnou podporu XML. Pak můžete v tabulkách ukládat údaje, podle kterých se vyhledává, a ty zbývající vlastnosti ukládat do XML.

Ale nedá se odpovědět, jak to dělat správně nebo že by měl někdo nějaký zázračný tip. Kdyby to šlo dělat dobře v relačních databázích, nebylo potřeba vymýšlet NoSQL – nebo opačně, ten zázračný tip jsou NoSQL databáze (samozřejmě, že ne každá – NoSQL databáze používají spoustu různých modelů).
Název: Re:Návrh relační databáze
Přispěvatel: redustin 25. 04. 2019, 17:48:09

Pokud to dobře chápu, máte tam Entity–attribute–value model (EAV (https://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value_model))? Pokud ano, bylo by dobré zmínit, že to ledaskdo považuje za antipattern. Což samozřejmě neznamená, že to nemůže fungovat, otázkou je pracnost a vlastnosti.

Přiznám se, že teoretické antipatterny neřeším, zajímají mě praktické požadavky. Snadná rozšiřitelnost do všech stran, podpora spolehlivého dlouhodobého vývoje (žádná reflexe apod, vše typově hlídané) a v neposlední řadě rozumný výkon. Ale ten lze dnes nahonit HW, který je velice levný. Repas server DL580 s 512GB DDR3 12800, 40 jádry a spoustou PCI-e v.3 slotů pro NVMe disky jsme nedávno kupovali za 30k Kč s dopravou. Tichá pracovní stanice Precision T7600 2x octa e-5 xeon 128GB RAM + spoustu PCI-e v.3 vyjde na 21k Kč, s 256GB RAM něco přes 30k. Kolik je to proti měsíčním nákladům na jednoho vývojáře...

Narozdíl od nákladů na vývoj, které jen porostou. Požadavky na změny a nové funkce chodí od byznysu každý den, zatímco ruční zásah do struktury DB jsme nedělali už hodně let. Tabulky atributů si samozřejmě vyrábí ORM samo.
Název: Re:Návrh relační databáze
Přispěvatel: Zabanovaný Anonymní Troll 25. 04. 2019, 18:08:22
Nechci někomu na potkání vykládat know-how, ani nežádám vyzrazení suprfičur ostatních. Spíš chci dát prostor ostříleným architektům, aby se pochlubili svým originálním přístupem a inspirovali jiné ztracené duše.

No tvl ty budes architekt jak vino. .NET developer, motto "nechci nekomu vykladat sve knowhow". A jaky jsi skromny, chces dat ostanim ostrilenym architektum (jako ty) prostor.

Jsem tu jediny, komu prijde bizarni, ze tady na diskuzni forum prijde clovek s otazkou, kterou zacne jako "nechci nikomy vykladat sve knowhow", a pote co v textu sdeli, ze "Po řadě pokusů a omylů jsme dospěli k řešení, které jistě není dokonalé, ale momentálně splňuje naše požadavky", popise, jak naimplementoval tak strasnou sracku, ze se z toho cloveku uplne jezi vlasy hruzou?

Ja mam dojem, ze tvoji aroganci predchazi snad uz jen tva neschopnost.
Název: Re:Návrh relační databáze
Přispěvatel: Ondrej Nemecek 25. 04. 2019, 20:20:01

Pokud to dobře chápu, máte tam Entity–attribute–value model (EAV (https://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value_model))? Pokud ano, bylo by dobré zmínit, že to ledaskdo považuje za antipattern. Což samozřejmě neznamená, že to nemůže fungovat, otázkou je pracnost a vlastnosti.

Přiznám se, že teoretické antipatterny neřeším, zajímají mě praktické požadavky. Snadná rozšiřitelnost do všech stran, podpora spolehlivého dlouhodobého vývoje (žádná reflexe apod, vše typově hlídané) a v neposlední řadě rozumný výkon. Ale ten lze dnes nahonit HW, který je velice levný. Repas server DL580 s 512GB DDR3 12800, 40 jádry a spoustou PCI-e v.3 slotů pro NVMe disky jsme nedávno kupovali za 30k Kč s dopravou. Tichá pracovní stanice Precision T7600 2x octa e-5 xeon 128GB RAM + spoustu PCI-e v.3 vyjde na 21k Kč, s 256GB RAM něco přes 30k. Kolik je to proti měsíčním nákladům na jednoho vývojáře...

Narozdíl od nákladů na vývoj, které jen porostou. Požadavky na změny a nové funkce chodí od byznysu každý den, zatímco ruční zásah do struktury DB jsme nedělali už hodně let. Tabulky atributů si samozřejmě vyrábí ORM samo.

To ale není moc dobrá reklama - když něco člověk dělá, měl by vědět jak tomu ostatní říkají, ostatně potřebuje komunikovat s ostatními vývojáři apod. Zasazení vlastní praxe do odborného kontextu by byl bod pro vás (ostatně ona to není ani nějaká akademická terorie).

Každopádně mě zajímalo jen to, zda to odpovídá tomu EAV patternu (odkaz jsem připojil).
Název: Re:Návrh relační databáze
Přispěvatel: redustin 25. 04. 2019, 21:16:17
Deset minut smolím odpověď a mezitím mě zdejší geniální systém odhlásí a odpověď zahodí.

Je to normální selský rozum, jak pokud možno trochu efektivně uložit objekty s atributy a vazbami. Název mě až tak nepálí, s kolegy si to umím vysvětlit i bez teoretických pouček od akademiků.

* tabulka objektů - klíč obj_id. Objekty jsou různých typů - class_id

* tabulka druhů/názvů atributů - klíč attrib_id

* každý typ atributu má vlastní tabulku attrib_XXX, kde XXX je jeho attrib_id. Řádky jsou hodnoty pro objekty, tedy cizí klíč obj_id na objekt. Sloupec value je textový, číslo, datum, json atd., dle konkrétního typu atributu . Atributů/tabulek jsme zatím nadefinovali cca tisíc.

* tabulka vazeb s obj_from_id, obj_to_id a opět class_id - třída vazby. Vazby mají privátní číselnou položku, která určuje např. pořadí podtémat ve výpisu jedné úrovně stromu, snadno se podle toho stromy zpracovávají.

* další tabulky pro práva, fulltext nad stringovými atributy atd.

Samozřejmě to vyžaduje ORM vrstvu v javě, přes kterou se dělají všechny změny. Ta kešuje načtené objekty, atributy, vazby. Klidně úplně všechny, od toho paměť je. Změna nejdříve transakčně zapisuje do DB, když se podaří, změní i nakešovaná data, takže to samozřejmě drží synchronizované.

Jak říkám, je to selský rozum. Ale docela se to osvědčilo a zatím moc změn nevidím potřeba. Chybí atributy u vazeb, to bude potřeba pořešit. A samozřejmě to chce nativní fulltext, klasický problém spousty projektů.
Název: Re:Návrh relační databáze
Přispěvatel: Ondrej Nemecek 25. 04. 2019, 22:23:36
Deset minut smolím odpověď a mezitím mě zdejší geniální systém odhlásí a odpověď zahodí.

Je to normální selský rozum, jak pokud možno trochu efektivně uložit objekty s atributy a vazbami. Název mě až tak nepálí, s kolegy si to umím vysvětlit i bez teoretických pouček od akademiků.

(...)

No bez těch akademiků byste neměl ani SQL ani SQL databázi, takže byste se pak neměl o čem s kolegy bavit.

Ale jinak děkuji za popis. Bylo by určitě zajímavé, jak dlouho a v kolika lidech jste to řešení vyvíjeli, aby to bylo možné porovnat s alternativami.
Název: Re:Návrh relační databáze
Přispěvatel: redustin 25. 04. 2019, 23:04:21
Umím ocenit teorii, když má opravdu hodnotu. Třeba o jejím významu pro SQL ani o DB nijak nepochybuji. Nicméně dle mého názoru je celá řada návrhových vzorů úplně normální řešení, které každý slušnější vývojář použije, protože mu přijde správné a samozřejmé a vůbec nemusí ani tušit, že to má nějaký odborný název. Taková teorie jde mimo mě. Zrovna tenhle princip EAV je jedno z těch úplně normálních řešení.

V roce 2003 moc hotových ORM v javě nebylo, obzvláště ne s výkonově optimalizovanou podporou ACL pro read/write/delete/link/grant na úrovni jednotlivých objektů a z nich poskládaných stromových struktur. Defakto adresářová struktura s ACL, původně to sloužilo jako DMS pro přímé propojení se sambou - přístup přes file manager i přes prohlížeč. Dneska už práva na objektech tolik neřešíme, je to spíš na byznys vrstvě, ale občas jsou potřeba.

Design/vývoj javovského ORM 1 hodně šikovný člověk cca půl roku, způsob uložení dat do DB jsme měli již ověřený z dřívějšího projektu ještě v PHP (od r. 2000).

Dneska bych se podíval po něčem hotovém, ale osobně bych opět volil nějaké efektivní mapování ORM do klasického SQL, s pořádnou podporou kešování. Líbí se mi grafové databáze, ale ty principy se pomalu dostávají do SQL, což je IMO správná a užitečná cesta.
Název: Re:Návrh relační databáze
Přispěvatel: Kit 25. 04. 2019, 23:22:17
Filip, Kit:
Grafové a jiné nosql databáze jsou sice dobré, ale do té doby, než s nima chce člověk pracovat v součinnosti s věcma, které má v SQL databázi. Např. proto se prosazují "in-databaze" fulltexty, protože fulltext mimo databázi může být nakrásně rychlejší, lepší a nevím co, ale když chceš kromě fulltextu filtrovat ještě podle dalších X kritérií, tak je to na palici. Navíc rozdělení dat do dvou databází musíš řešit takové lahůdky, jako synchronizace transakcí atd. atd....
A protože se na většinu věcí SQL hodí hodně dobře, zpravidla je lepší cesta používat nosql rozšíření SQL databází - např. ten json sloupec - než data dělit do dvou různých databází, anebo se zcela zbavovat možností SQL (a ukládat vše do noSQL databáze).

Pokud někdo chce prznit relační databázi nějakým EAV a ORM, tak mu rovnou doporučím NoSQL, kde tyhle dva nesmysly nebude potřebovat. Takový vývojář si relační databázi ani nezaslouží.
Název: Re:Návrh relační databáze
Přispěvatel: SB 26. 04. 2019, 14:27:49
Pokud někdo chce prznit relační databázi nějakým EAV a ORM, tak mu rovnou doporučím NoSQL, kde tyhle dva nesmysly nebude potřebovat. Takový vývojář si relační databázi ani nezaslouží.

Já bych se zeptal jinak: Jak je možné, že u tolika projektů je problémem č. 1, jak dostat data do a z relační databáze. To nedává smysl - buďto je formát dat projektu vhodný na RDB, nebo se na ni vy*eru a použiju něco, kde nebudu potřebovat rovnáky na ohýbáky.
Název: Re:Návrh relační databáze
Přispěvatel: BoneFlute 26. 04. 2019, 15:17:58
Já bych se zeptal jinak: Jak je možné, že u tolika projektů je problémem č. 1, jak dostat data do a z relační databáze. To nedává smysl - buďto je formát dat projektu vhodný na RDB, nebo se na ni vy*eru a použiju něco, kde nebudu potřebovat rovnáky na ohýbáky.

Protože relační databáze jsou dlouhodobě nejvymazlenější nástroj co se manipulace s daty týče. Samozřejmě bychom mohli prohlásit, že tak ať se lidé seznamují s novinkami, a ono by se nakonec něco vytvořilo, jenže znáš to.
Název: Re:Návrh relační databáze
Přispěvatel: Ladislav Zitka 26. 04. 2019, 19:58:52
Pokud někdo chce prznit relační databázi nějakým EAV a ORM, tak mu rovnou doporučím NoSQL, kde tyhle dva nesmysly nebude potřebovat. Takový vývojář si relační databázi ani nezaslouží.

Já bych se zeptal jinak: Jak je možné, že u tolika projektů je problémem č. 1, jak dostat data do a z relační databáze. To nedává smysl - buďto je formát dat projektu vhodný na RDB, nebo se na ni vy*eru a použiju něco, kde nebudu potřebovat rovnáky na ohýbáky.

O jakych projektech mluvis?...
Název: Re:Návrh relační databáze
Přispěvatel: Ladislav Zitka 26. 04. 2019, 20:21:07
Jinak k navrhu reseni mam par poznamek, ktere by mozna pomohly:
1. Prestat veci mazat, spis se na data koukat jako na bankovni transakce, tj. time series data, a podle toho navrhout model. Neco jako star kvazi-star schema s identifikatory(klici) v centralni tabulce, kde by bylo take jejich linkovani. Slo by implementovat na nejakem key/value storu (Redis, nebo Hbase)
2. Specificke typy budou mit kazdy svou tabulku, pokud jich mate hodne tech typu, tak bych to radsi rval nekam zase do nejakyho K/V storu.
3. Oddelit ingestion(write) a query(read) modely. Prvni je vice normalizovany, druhy muze byt denormalizovany pro fast query. Nelze dosahnout obojiho v jednom modelu. Nevim detaily architektury, ale doporucoval bych se kouknout na patterny jako CQRS, SAGA, resp. Event Sourcing, napr. pomoci Confluent, Axon nebo Eventuate na Springu(by famous Richardson)

Q; mate nejake ETL/integracni pumpy, nebo jak se tam ty data dostavaj, to si vubec nepopsal?
Q: Jaky je volume (GB,TB,PB..) a pocet zaznamu napr. za 1 rok?
Název: Re:Návrh relační databáze
Přispěvatel: rhubner 27. 04. 2019, 12:38:52
Dobry den,

pridam moji odpoved, ktera sice nebude primo pro Vas(nepouziva SQL), ale nekomu se muze v budoucnu hodit.
Zkusil bych se podivat na tripplestore, RDF, a veci kolem semantickeho webu : https://en.wikipedia.org/wiki/Triplestore

Pomoci jazyka OWL jde definova neco jako "schema", nazyva se to Ontology, kde si pro kazdy objek vytvorite "tridu". Techto trid muzete mit tisice. Daji se taky ulozit do databaze. Nasledne do databaze ulozite "instance" trid, ktere mohou odkazovat jedna na druhou, delat stromove struktury, pouzivat vicenasobnou dedicnost. Navic databaze vas nijak neomezuje co kde smite ukladat. Act se to myslim da zapnout.

V programu nasledne muzete generovat rozhrani na zaklade "tridy" a jejich datovych typu. Jazyk OWL je mocny, nekdy az moc, ale zase se v nem daji definovat pravidla ktere vylucuji napriklad aby jedna "instance" nemohla byt jak auto, tak letadlo. Nasledne muzete pomoci jazyka SPARQL generovat dotazy do databaze. Jako dej mi vsechny instance tridy Auto vcetne jejich potomku (Nakladak, tahac, sportak).

https://jena.apache.org/documentation/ontology/
https://jena.apache.org/documentation/fuseki2/index.html
https://en.wikipedia.org/wiki/SPARQL

Radek
Název: Re:Návrh relační databáze
Přispěvatel: redustin 27. 04. 2019, 13:25:52
OWL - zajímavé, díky.

Tohle stále ještě platí (citace z wiki)?

Limitations
No direct language support for n-ary relationships. For example, modelers may wish to describe the qualities of a relation, to relate more than 2 individuals or to relate an individual to a list. This cannot be done within OWL. They may need to adopt a pattern instead which encodes the meaning outside the formal semantics.