Databáze v PHP elegantně s NotORM

Většina webových aplikací potřebuje pracovat s propojenými daty uloženými v databázi. Pro pohodlnější práci s databázemi existuje velké množství mezivrstev a knihoven, které mají práci usnadnit. Novou PHP knihovnu, nazvanou NotORM, nám v článku představí její autor, Jakub Vrána.
Psát SQL dotazy spojující třeba šest tabulek v databázi může být zpočátku docela zábavné, pak se z toho ale stane nudná rutina. Navíc spojení tabulek nemusí být vždy nejefektivnější, protože se znovu přenáší už jednou přenesená data. Takže někdy je výhodnější položit šest jednoduchých dotazů a propojit až jejich výsledky, což už je úplná nuda.
Elegance
Pro získání dat pomocí PHP proto vznikla knihovna, která propojená data z databáze dokáže elegantně a zároveň efektivně získat. Jmenuje se NotORM a připodobnil bych ji k PHP extenzi SimpleXML, která podobným způsobem pracuje s XML dokumenty. Základní API je jednoduché:
<?php // připojení k databáziinclude "NotORM.php"; $pdo = new PDO("mysql:dbname=software"); $software = new NotORM($pdo); // získání prvních deseti aplikací foreach ($software->application()->order("title")->limit(10) as $application) { // vypsání jejich titulku echo $application["title"]; // získání jména autora z propojené tabulky echo " (" . $application->author["name"] . ")n"; // vypsání všech nálepek z propojené tabulky M:N foreach ($application->application_tag() as $application_tag) { echo "- " . $application_tag->tag["name"] . "n"; } } ?>
Efektivita
Jak už bylo řečeno, tak knihovna je nejen elegantní, ale zároveň i efektivní. Klade tedy jen minimální počet jednoduchých dotazů a z databáze přenáší jen ta data, která jsou potřeba. Dosahuje se toho dvěma způsoby:
- Získání souvisejících záznamů se provádí najednou pro všechny řádky výsledku jedním dotazem.
- Přenášejí se jen ty sloupce, které se nakonec skutečně použijí (při povolení této vlastnosti).
Díky těmto vlastnostem se pro zpracování příkladu položí jen čtyři jednoduché dotazy:
SELECT id, title, author_id FROM application ORDER BY title LIMIT 10; SELECT id, name FROM author WHERE (id IN ('11', '12')); SELECT application_id, tag_id FROM application_tag WHERE (application_id IN ('1', '4', '2', '3')); SELECT id, name FROM tag WHERE (id IN ('21', '22', '23'));
Všimněte si, že z tabulek se přenáší jen ty sloupce, které se nakonec použijí, aniž by se jejich seznam musel kdekoliv specifikovat. To je zařízeno tak, že knihovna napoprvé získá všechny sloupce, pak si ale zapamatuje, které sloupce skutečně použila a příště už si vyžádá jen ty použité. Když se skript změní a chceme vypsat nějaké sloupce navíc, tak se automaticky zase získají všechny a seznam se rozšíří. Pro zajištění tohoto chování si knihovna potřebuje ukládat data, což lze nastavit třetím parametrem konstruktoru NotORM
– jsou připravena úložiště do session proměnných, souborů, databáze a sdílené paměti, další si můžete snadno doplnit.
Kešování výsledků dotazů knihovna nepoužívá, protože takováto keš zastarává a navíc zabírá paměť, kterou lze využít k něčemu užitečnějšímu. Lepší je data získávat efektivně rovnou od databáze, pro což dává knihovna výborné podmínky.
Struktura databáze
NotORM umí pracovat se všemi databázemi, které podporuje PDO, testovaná je s MySQL, SQLite, PostgreSQL a MS SQL. Kromě toho je NotORM k dispozici i pro oblíbenou knihovnu Dibi.
Co se pojmenování sloupců týče, tak se používá nejrozšířenější konvence – primární klíč je id
, cizí klíč table_id
, kde table
je název odkazované tabulky. Předáním druhého parametru konstruktoru NotORM
si ale můžeme nastavit i vlastní konvenci. K dispozici je i třída načítající informace o primárních a cizích klíčích přímo z meta-informací databáze (tabulky InnoDB v MySQL >= 5), ta má ale určitou režii, takže je lepší dodržovat nějakou konvenci.
Validace a ukládání dat
NotORM se nestará o ukládání a tím pádem ani validaci dat. Ve webových aplikacích je totiž ukládání obvykle mnohem méně časté než načítání a není problém ho zajistit konvenčními způsoby. Pro administrační rozhraní lze použít Adminer Editor, který ukládání vyřeší zadarmo.
Validaci dat je lepší řešit na úrovni databáze pomocí unikátních a cizích klíčů, datových typů, povinných sloupců a dalších kontrol. Jinak totiž hrozí, že se nám do databáze dostanou nekonzistentní data, se kterými aplikace stejně bude muset umět pracovat. Ohlašování chyb uživateli je zase vhodné řešit co nejblíže místu jejich vzniku, výborně se o to starají třeba formuláře Nette.
Větší příklad
NotORM se báječně hodí pro malé webíky se třemi propojenými tabulkami stejně jako pro velké projekty s desítkami složitě propojených tabulek. U těchto projektů dává NotORM pocit klidu, že se bez velkého přemýšlení vyhodnocují všechny dotazy efektivně (samozřejmě pokud jsou definované indexy na vyhledávání a třídění). Ukážeme si proto použití u obchodu, který organizuje produkty do kategorií a u každého produktu eviduje jeho možné dodavatele. Kromě toho se k produktům evidují parametry, které se načítají z tabulky všech možných hodnot (ta se používá třeba i pro sestavení vyhledávacího formuláře), která se zase odkazuje do tabulky všech možných názvů parametrů. Na obrázku je pouze relevantní část schématu celé databáze a jsou vynechány nevyužité sloupce.
<?php include "NotORM.php"; $pdo = new PDO("mysql:dbname=shop"); $shop = new NotORM($pdo, null, new NotORM_Cache_Database($pdo)); $category = $shop->category[$_GET["id"]]; if (!$category) { // 404 exit; } echo "<h1>" . htmlspecialchars($category["name"]) . "</h1>n"; $products = $category->product() ->where("disabled", 0) ->order("price") ->limit(10) ; foreach ($products as $product) { echo "<h3>" . htmlspecialchars($product["name"]) . "</h3>n"; list($suppliers) = $product->product_supplier()->aggregation("COUNT(*)"); echo "<p>Cena: $product[price] Kč, dodavatelů: $suppliers</p>n"; $product_parameters = $product->product_parameter(); if (count($product_parameters)) { echo "<table cellspacing='0'>n"; foreach ($product_parameters as $product_parameter) { $parameter = $product_parameter->parameter; $parameter_name = $parameter->parameter_name; echo "<tr>"; echo "<th>" . htmlspecialchars($parameter_name["name"]) . "</th>"; echo "<td>" . htmlspecialchars("$parameter[value] $parameter_name[unit]") . "</td>"; echo "</tr>n"; } echo "</table>n"; } } ?>
Při spuštění se položí následující dotazy:
SELECT id, name FROM category WHERE (id = '25'); SELECT id, category_id, name, price FROM product WHERE (category_id IN ('25')) AND (disabled = '0') ORDER BY price LIMIT 10; SELECT product_id, COUNT(*) FROM product_supplier WHERE product_id IN ('102920', '102915', '116549', '102902', '108993', '102907', '102900', '102922', '102930', '102909') GROUP BY product_id; SELECT product_id, parameter_id FROM product_parameter WHERE (product_id IN ('102920', '102915', '116549', '102902', '108993', '102907', '102900', '102922', '102930', '102909')); SELECT id, parameter_name_id, value FROM parameter WHERE (id IN ('1', '131', '3780', '6109', '2561', '2576', '6110', '3787', '5374', '6111', '6113', '6114', '8783')); SELECT id, name, unit FROM parameter_name WHERE (id IN ('1', '46', '120', '187'));
Dávat tyto dotazy dohromady ručně nebo konstruovat dotazy spojující více tabulek by se mi opravdu nechtělo. Obslužná logika pro jejich projití by navíc byla prakticky stejná jako u NotORM. Navíc bych nejspíš skoro všude z pohodlnosti použil SELECT *
, abych nemusel sloupec dodatečně přidaný do výpisu dopisovat ještě do dotazu.
Závěr
Knihovna NotORM se dá použít pro pohodlné a efektivní procházení propojených záznamů v databázi, ať už u malých nebo u velkých projektů. Neřeší validaci ani ukládání dat, které je obvykle lepší řešit na jiné úrovni.
Ahoj,
knihovnu NotORM se zájmem sleduji a chystám se vyzkoušet. Rád bych se ale předem zeptal, jak se bude chovat v situacích, kdy by se do WHERE IN (…) podmínky měly dostat desítky tisíc ID z nadřazené tabulky.. nemá query string omezenou délku?
Díky za případnou odpověď.
MK
Např. v MySQL je délka dotazu omezena konfigurační direktivou max_allowed_packet. Velké výsledky je ale stejně lepší zpracovávat postupně – nejen kvůli délce dotazu, ale i kvůli zabrané paměti. Typicky to je lepší i pro databázový server. Je to popsané na http://www.notorm.com/#faq.
Ja myslim ze tak ta otazka nebyla minena… Pokud ten prvni select vrati treba 1000 zaznamu (cemuz bych se mel rekneme vyhnout, ale muze se stat, ale to same plati i pro 100 redku, coz uz je bezne), tak abych mohl sestavit ten IN, tak musi knihovna projit vracene radky a posladat z nich IN. Pak tenhleten rekneme dlooooooouhy dotaz poslu do MySQL, ten to nejdriv musi parsovat a zase ty IDcka ze stringu lovit, pak to musi chudak nejak vykonat (nerad bych podcenoval jeho optimalizator, ale optimalni to jiste nebude) a pak to posle na server, kde se to musi znovu prochazet a joinovat ty vracene radky… Vubec radeji nemluvim o tom, jak je to v pripade, ze je tech joinu vic nebo se dela join pres dalsi tabulku.
Nemuzu si pomoct, ale kdyz proti tomu postavim jeden rucne psany JOIN, na ktery je server optimalizovany, prijde mi to dost nesrovnatelne…
Doporučuji si to prostě změřit. Parsování dotazu je prakticky okamžité, dotazy používající IN vyhodnocuje MySQL velmi efektivně (např. lépe než BETWEEN) a spojení dat v PHP (kterému nevhodně říkáte joinování) probíhá v konstantním čase, jak už jsem vysvětloval.
Zmeril jsem… Tvrdit o cemkoli, ze je „prakticky okamzite“ je podle me dost odvazne, ale budiz. Na realnych datech, kde se z tabulky s miliony radku vybira asi tisicovka a ta se joinuje s tabulkou s desetitisici radku mi to vyslo tak, ze jen provedeni dvou selectu (jeden s IN) trvalo 150–200% casu JOINu… coz podle me nemi na zatizenych webech zanedbatelne (nepocitam narust zateze na strane PHP, ktery bude prakticky zadny, ale presto nejaky). A joinovani je mozna nehodne slovo, ale pokud je join=spojit a „spojovani v PHP“ nahrazuje onen sql JOIN, a myslim, ze si jiste rozumime ;)
Ty niekde potrebuješ VYPÍSAŤ asi 1000 záznamov z databázy? Môžeš uviesť konkrétny príklad?
Poměrně běžné to je u XML exportů, např. pro Zboží nebo Sitemaps.
Test by to chtělo udělat pořádněji, protože záleží na spoustě věcí. Např. „jen provedeni dvou selectu“ je jen část celého problému, protože data je potřeba taky přenést. Tím pádem taky záleží na tom, jestli jde o server lokální nebo vzdálený. Záleží taky na spojovaných tabulkách, jestli se jejich vztah blíží 1:1 nebo jde o 1:N, jde taky o šířku dat v jednotlivých tabulkách.
Test prostě musí být přesný a reprodukovatelný, takhle to je jen výkřik do tmy stejně jako kdyby řekl, že na reálných datech je NotORM dvakrát rychlejší.
Každopádně jak jsem ukazoval, tak NotORM nikdy nebude řádově horší (tedy u 1000 řádek třeba tisíckrát) než jiné řešení – nemůže ustřelit. Může být pouze konstanta-krát horší, což se ve velkých objemech řeší snadno. Naopak spojování tabulek ustřelit může v objemu přenášených dat, které má na celkovou rychlost taky vliv. Tam, kde NotORM přenese O(N + M) dat může spojování tabulek přenášet O(N * M) dat.
Všimněte si, že z tabulek se přenáší jen ty sloupce, které se nakonec použijí, aniž by se jejich seznam musel kdekoliv specifikovat. To je zařízeno tak, že knihovna napoprvé získá všechny sloupce, pak si ale zapamatuje, které sloupce skutečně použila a příště už si vyžádá jen ty použité.
To je myšleno jako další level v podporování lenosti programátorů? :)
Ale pro větší data a projekty je to stejně nebezpečné jako klasické ORM. Navíc to vede k naivnímu způsobu programování, kdy bombarduji SQL databázi jednoduchými dotazy – což vyhovuje MySQL, ale všem ostatním databázím to dobře nedělá, přičemž je to stejně hloupost, protože ostatní db si dokáží poradit i s komplikovanějšími než triviálními dotazy.
Ono nejde jen o složitost dotazů, ale i o to, kolik se přenáší dat. Podívej se podrobně na obrázky v odkázaném článku http://php.vrana.cz/srovnani-dotazu-do-zavislych-tabulek.php. Spojování tabulek vede k tomu, že se opakovaně přenáší data, která už se jednou přenesla. To nevyhnutelně stojí nějaký čas. Naproti tomu NotORM klade konstantní počet dotazů, kde se přenáší objem dat minimální. V odkázaném článku je i srovnání časů – tam jsou výsledky vyrovnané.
Zkus si udělat podobný test i pro PostgreSQL, možná budeš překvapen. Záleží samozřejmě na charakteru dotazů – spojování tabulek 1:1 se dá trochu efektivněji dělat i JOINem, ale jakmile chceš přenést hodně sloupců z jedné tabulky a k tomu připojit hodně řádků z jiné tabulky, tak objem přenesených dat zbytečně narůstá.
Nebudu se přít, že o tom, že denormalizovaná data jsou větší – to je jasné. Na druhou stranu – pokud nejsou extrémně delší, tak je mnohem větší brzdou režie na straně serveru – každý dotaz se musí poslat po síti, musí se parsovat, musí se generovat plán, musí se generovat snapshot. Navíc obcházíš planner – v případě chtřejších db, lze efektivně provést JOIN aniž bys musel mít index na tabulkách – čímž zase zrychluji DML operace. Případně planner si může vybrat z několika metod implementace JOINu – v tvém případě je to vždy NESTED LOOP, což je ta nejpomalejší metoda – byť je v některých případech tou správnou.
Minimálně jsou tvá doporučení hodně diskutabilní – pokud bych měl problém s pomalou sítí – pak bych spíš měl použít uloženou proceduru. Opět není problém přímo v uložené proceduře přeformátovat výsledek do JSON, XML, HTML formátu. Co se týče mne, tak rozhodně nedoporučuji tvůj přistup aplikovat pro PostgreSQL a netriviální projekty – pokud budu řešit menší eshop – nic se neděje. Při větších objemech, při komplexnějších operacích by to nedopadlo dobře – resp. výsledek by byl zbytečně zoufale pomalý.
NESTED LOOP se přece vůbec neprovádí. Při něm se pro všechny řádky jedné tabulky prozkoumají všechny řádky druhé tabulky a řádky splňující podmínku se vrátí (časová složitost M * N). NotORM nic takového nedělá – jedním dotazem získá z jedné tabulky všechny řádky výsledku a druhým dotazem získá z druhé tabulky všechny připojené řádky. Spojí to pomocí haštabulky, tedy pro každý řádek v konstantním čase. Celkový čas maximálně M + N. Líp to nejde.
Možná jsi měl na mysli případ, kdy je potřeba podle řádků v jedné tabulce vyfiltrovat řádky v druhé tabulce. To NotORM taky podpuruje, jak je popsáno v dokumentaci.
Tento kód spustí následující dotaz, se kterým si databáze hravě poradí.
Formátování výsledku přímo v SQL je podle mě lepší se vyhnout. Tam prostě prezentační logika nepatří, od toho jsou šablony.
Budu velmi rád, když mi ukážeš projekt, na kterém by si NotORM podle tebe vylámal zuby. Načrtni strukturu databáze, dodej ukázku dat a požadavky na získávaná data a já ti ukážu, jak se v NotORM dají tyto požadavky efektivně vyřešit.
Myslím si, že stačí, když dojde k situaci, kdy ORM vygeneruje dotaz … IN (několik stovek id). Tam budeš zbytečně tlačit mezi serverem a klientem data, která vůbec nepotřebuješ. Ty to dokážeš obejít skrz nested metody – ok, kolik programátorů se k tomu dopracuje? Navíc kód, který to vygeneruje je minimálně pro MySQL menší než 5.5 neefektivní (v případě větších objemů).
Můj primární protiargument je ten, že tvé NotORM dokáže v rukách průměrného programátora napachát stejnou škodu jako klasické ORM – stejně si musí výsledně programátor ověřovat dotazy, které tvoje knihovna vygeneruje, tudíž úspora práce je minimální a čitelnost celku horší. Z mého pohledu má knihovna NotORM stejné nevýhody jako klasické ORM – jen je menší – spíš bych ji pojmenoval SimpleORM.
Formátování výsledku v SQL může mít svůj význam – a) tehdy kdy řeším výkon, b) kdy db požívá víc aplikací – a třeba PHP je pouze jedním z možných interface – samozřejmě – nesmí se to přehánět – je blbost generovat v SQL komplet html stránku.
Několik stovek ID se bude zbytečně tlačit pouze u vazeb 1:1, které jsou u většiny aplikací ojedinělé. Naopak u vazeb 1:N a M:N dojde většinou k redukci objemu přenesených dat.
Příklad vazby 1:N je
$application->author["name"]
. Když bych to vyřešil spojením tabulek, tak se stejné jméno autora (a případně další informace, které bych o něm chtěl) bude přenášet opakovaně u všech aplikací, které autor vytvořil. Celkově se přenesea * (s + id)
dat, kdea
je počet získávaných aplikací,s
délka jména aid
délka primárního klíče (předpokládám, že chci přenést i id autora, abych na něj mohl třeba vytvořit odkaz). NotORM přenese jméno autora (a případné další informace) jen jednou a opakovaně přenese pouze jeho ID. Celkový objem přenesených dat je tedya * id + b * (s + 2*id)
, kdeb
je počet různých autorů ve výpisu. To je horší pouze v situaci, kdy počet různých autorů skoro dosahuje počtu vypisovaných aplikací (tedy téměř vazba 1:1).U vazeb M:N (např.
$application->application_tag()
) by bylo spojení tabulek úplný zabiják, protože pro každou nálepku by se znovu přenášely všechny informace o aplikaci. Lepší by to mohlo být pouze v případě, kdy by aplikace měly žádnou nebo jen jednu nálepku (tedy opět téměř vazba 1:1).Omezení záznamů z jedné tabulky podle dat v druhé tabulce se dělá v NotORM zcela přirozeně a mrzí mě, že jsem to do článku nenapsal. Že to vygeneruje poddotaz (ty asi říkáš nested metodu), je zcela transparentní. Můžeš prosím popsat, co by mělo být před MySQL 5.5 neefektivní? U poddotazů dokáže MySQL použít stejné indexy a další optimalizace jako u spojení tabulek.
Vygenerované dotazy typicky kontrolovat potřeba není – jsou prostě jednoduché a rychlé. Opravdu bych byl rád za příklad, na který podle tebe NotORM nebude dost efektivní. Navíc i napsat kód tak, aby byl s NotORM neefektivní, dá na rozdíl od ručního psaní dost přemáhání.
Lišíme se v názoru na to, co je horší – jestli objem přenesených dat nebo počet SQL dotazů – v tom se neshodneme. Řešit přenos po lokální síti mi přijde irelevantní (v běžných dimenzí .. do 100KB výsledku) – něco jiného je čtení/zápis na disk.
Ohledně poddotazů – v materiálech k 5.5 (a k 5.4) jsou informace o tom, že poddotazy jsou znatelně rychlejší (v těchto verzích). Z toho vycházim.
Rozhodně se shodneme v tom, že příliš velký počet dotazů je pro databázi smrt. Takže když kvůli jednomu výpisu položím celkem 1 + M + M * N dotazů (kde M je třeba počet aplikací a N počet jejich nálepek), tak to prostě bude pomalé. Ale jestli kvůli stejnému výpisu položím 1 dotaz (který přenáší hodně dat) nebo 3 dotazy (které přenáší málo dat), tak to bude velmi podobné. Asymptoticky se položí dotazů stejně. Naopak se může u spojení tabulek asymptoticky zhoršit objem přenesených dat. NotORM je prostě asymptoticky optimální a použitá konstanta může celkový výsledek buď trochu zhoršit nebo trochu zlepšit, nikdy ho ale nezhorší podstatně.
Zlepšení poddotazů bude nejspíš v něčem jiném. Jejich současné použití v NotORM je rychlé i ve starších verzích.
Ne že bych měl něco proti tomudle frameworku, na spoustu věcí se velmi hodí, ale IMHO při složitějších aplikacích někdy selhat musí.
Vycházím z jednoduché premisy: Proč by databázové plannery byly tak sofistikované a často jim trvalo několik verzí (např. Mysql), než se podaří by generovaly alespoň trochu rozumné plány pro složitější dotazy, když by takovýto v podstatě triviální algoritmus vracel optimální nebo skoro optimální řešení?
Je to zajímavá úvaha. Vtip je v tom, že NotORM ulehčuje databázi práci – radí jí, v jakém pořadí má vyhodnocovat tabulky a jaké z nich bude potřebovat řádky. To je u obecného dotazu se spoustou spojených tabulek poměrně pracné.
Pro databázi nicméně pořád ještě nějaká práce zbývá – musí se rozhodnout, jaké u tabulek použije indexy a původní práce ji čeká i u poddotazů (které NotORM taky generuje, jak je popsáno v dokumentaci a jak jsem zmínil v diskusi).
Každopádně budu rád za úlohu, na které si NotORM podle vás vyláme zuby.
No, pokud bych jako bernou minci bral projekt, na kterém pracuju teď, tak tam by si NotORM myslím zuby nevylámalo.
Ale z úplně jednoduchého důvodu – buďto používám jednoduché selecty,
kde je úplně jedno, co se použije, nebo vnořené poddotazy, kde IMHO notOrm takovou výhodu nemá (rychlost i srozumitelnost ručně napsaného dotazu je zhruba podobná zápisu v notorm) (ručně je samo nepíšu), nebo stored procedury, často obalující různé rekurzivní SQL dotazy, což by pomocí notORM nešlo asi vůbec?
Jinak v podstatě souhlasim, že u databáze, která vnořené dotazy umí správně optimalizovat (s čímž třeba mysql měla problémy – myslím ale, že větší problém byl u dotazů typu NOT IN – umí je notOrm?) tak správně napsané dotazy v notOrm by neměly bejt (moc :-)) špatné. „Problém“ spíš vidím v tom, že u složitějších projektů použiju různý kombinace poddotazů, rekurzivní poddotazy a podobný věci, a ty v notOrm zas tak hezky popř. vůbec napsat nepůjdou.
Takže to, že notOrm většinou (klidně si to změň na vždy) generuje dobrý plány imho neni tim, že by to byl „univerzálně použitelnej princip“, ale spíš že notOrm v základu velmi hezkým způsobem obaluje pouze část toho, co databáze umí. Pokud to člověku v projektu stačí, pak notOrm může bejt dobrá volba. Mě by to ale v projektech co píšu většinou nestačilo.
Pokud by se ale přepsalo tak, aby umělo i stored procedury, pak by to byl asi opravdu hezkej frontend pro aplikace, který maj většinu logiky v databázi.
Anebo naopak na aplikace, kde člověku stačí to, co notOrm pokrejvá hezky. Ale když ona je stromová struktura tak „přirozená“ a rekurzivní dotazy tak hezký :-)
Rekurzivní dotazy nepoužívám, lepší je podle mě přizpůsobit strukturu databáze a použít nejlépe Traverzování kolem stromu.
Dotazy NOT IN se dají pokládat neintuitivním zápisem where(„field_id NOT“, $db->$tableName()).
Podporu uložených procedur přidat neplánuji.
Pokud se nepletu pri pouziti NOT IN ci != neumi mysql pouzit index.
Jinak by mne zajimalo jak se resi nasledujici problem:
Jsou tri tabulky: produkty (id, nazev, kategorie_id), cenoveskupiny (id, nazev) a ceny (cenoveskupiny_id, produkt_id, cena).
Jak efektivne vybrat produkty z dane cenove skupiny (a nejake dalsi podminky jako kategorie apod.) s cenou od do a seradit od nejlevnejsiho.
Pomocí VIEW :) Nezkoušel jsem výkon na MySQL ani PostgreSQL ale třeba na MSSQL mám odzkoušeno, že je rychlejší udělat pohled, než posílat několik dotazů a pak to šroubovat k sobě.
Databáze si sestaví nějaké schéma (zase tak moc do střev tomu nevidím) a pak už jsou selecty sranda, protože databáze ví kudy postupovat (za předpokladu, že existují indexy – bez nich se taky dá databáze úplně sestřelit) a dotazy tak trvají chviličku a je to menší zátěž pro server.
Hračka:
Položí se tyto dotazy:
Díky, NotORM mně přijde dobrý na dotazy které jsou ± stejné a a podmínky v nich se moc nemění.
Pokud by se v předchozím příkladu změnily podmínky a uživatel už by nechtěl filtrovat podle ceny ale jen podle kategorie tak už se musí změnit celý zápis, neboť programátor už musel sám určit z která tabulky se bude vybírat jako první.
Nikoliv. Když by se nemělo filtrovat podle ceny, tak by kód zůstal úplně stejný, jen by zmizela podmínka „cena BETWEEN ? AND ?“. Pořád je totiž ještě potřeba omezit cenovou skupinu a podle ceny setřídit. Když by se podle ceny třídit nemuselo, tak by se kód přepsat mohl, ale nemusel.
jde mně o to že uživatel většinou určuje podmínky a dle čeho seřadit a mysql v tomto ohledu většinou pomůže tím že správně vybere první tabulku.
Vlastně ani moc nejde o NotORM ale jak vyřesit strukturu v mysql aby tyhle dotazy byly co nejvíce efektivní.
V aktuální verzi to je ještě jednodušší:
Položí se tento dotaz:
Ohejbat realitu (zachycenou DB) tomu, že chci použít nějakej nástroj je IMHO většinou cesta do pekel. Respektive na to člověk pak hrozně nadává, když je třeba provést v projektu změna. A ať je udělaná analýza sebepečlivěji, na spoustu věcí se vždy přijde až během vývoje (nemusí to bejt ani vina programátora, často je to vinou zákazníka a zadání, nebo šéfa :-)) a změny jsou tedy nutný.
V tu chvíli díky „optimalizovaný“ struktuře databáze začne člověk prskat jako kocour a buďto dělat věci natřikrát přes ruku, nebo přepisuje půlku aplikace. Proto radši nechám realitu tak jak chci, a případný „upravený“ dotazy si taham pomocí views či uloženejch procedur.
Traverzování kolem stromu je sice hezký, ale do tý doby, než člověk záznamy v daný tabulce chce i upravovat. Takovej update celý tabulky kvůli vložení jednoho záznamu je cool. Konkurenční transakce prakticky nemaj šanci.
Nemluvě o tom, kdybych náhodou chtěl logovat všechny změny provedené v databázi (odsypávat staré záznamy do vedlejších tabulek). Kvůli změně jednoho řádku kopírovat celou tabulku… Opět je to velmi dobrá technika a nezřídka ji používám, ale její použití je omezený.
Not in dotazy se daj, ten zápis mi ale nepřipadá jednodušší než
klasickej framework, co žere SQL.
Jinak opakuju, proti notorm nic menám a dokážu si představit spoustu příkladů, kde by to byla jedna z nejvhodnějších knihoven na přístup k
databázi. Jen se IMHO prostě nehodí na vše :-)
PS: A nad ťěma stored procedure se zamyslete, dopsat by tam šly snadno – podědit objekt tabulky tak, aby jako argumenty žraly argumenty SP. Ve větších kouscích software bych se aspoň osobně bez SP obcházel těžko…
Podporu pro uložené procedury si klidně dopište, je to open-source. Ale s API bude problém, protože uložené procedury nesdílí jmenný prostor s tabulkami, takže volání $db->$tableName() musí vždy přistoupit k tabulce a uložené procedury by se musely volat krkolomněji.
No, v tom bych zrovna problém neviděl, protože i když jmenný prostor nesdílí, tak je imho prasečina je pojmenovávat stejně.
Asi bych to osobně implementoval tak, že někde v konfiguráku (škoda že php nemá aplikační server, tam by se krásně šlo vše načítat z db bez ztráty výkonu) názvy stored procedur. %db->nazev() by pak volal stored proceduru – pokud by byla v tom konfiguráku. Když by se to doplnilo ještě
speciální metodou _table($tablename) a _proc($tablename), tak by to řešilo i ty výjimky, kdy je člověk čuník, nebo nechce psát konfigurák.
V současnym projektu to moc nepoužiju, ale jestli budu někdy pracovat na projektu, kde se mi tadle knihovna bude hodit, tak si to dopíšu :-), bude to IMHO pár řádek kódu…
co přesně znamená uložené procedury nesdílí jmenný prostor s tabulkami ?
jestli si měl na mysli to co já, tak je to závislý na implementaci
MSSQL:
create table dbo.foo
(id int not null)
GO
create procedure dbo.foo
as
select * from dbo.foo
GO
Msg 2714, Level 16, State 3, Procedure foo, Line 3
There is already an object named ‚foo‘ in the database.
Může být. Každopádně se na to NotORM nemůže spolehnout.
Pořadí spojování tabulek se u moderních plannerů řídí statistikou – kdežto u tebe zápisem – to bych viděl spíš jako krok zpět. Tak asi na projekty na které se nasazuje PHP to třeba úplně tragické být nemusí – už vzhledem k tomu, že NotORM vygeneruje indexy, které jsou pro některé programátory tabu. Což na jednu stranu je výhoda, na druhou stranu nevýhoda, poněvadž pro některé dál může zůstat db black box, což je špatně.
Jediný případ, kdy by se pořadí vyhodnocení mohlo lišit, jsou vazby 1:1, které jsou ojedinělé. Jinak u vazeb 1:N a M:N by se použil LEFT JOIN, který pořadí zpracování taky jasně určuje. U omezení výsledků jedné tabulky podle druhé tabulky se použije poddotaz, takže to je ponecháno v režii databáze.
NotORM žádné indexy negeneruje, na strukturu databáze vůbec nesahá. Dokonce by se obešel i bez cizích klíčů. Naopak strukturu databáze plně respektuje, takže její správný návrh zůstává nezbytným základem.
No já používám většinou INNER JOIN i na vazby 1:N. Použití INNER nebo OUTER JOINU nemá vztah ke kardinalitě vazby.
Ad „Ale jestli kvůli stejnému výpisu položím 1 dotaz (který přenáší hodně dat) nebo 3 dotazy (které přenáší málo dat), tak to bude velmi podobné“
Ty to ale bereš tak, že jakmile máš ty data v PHP, pracuješ s nimi „zadarmo“, že drahá je jen práce databáze. Ale tak to není. Sice ušetříš nějakou práci databázi, ale pak ji musíš udělat v PHP*
*) ono to vypadá snadno, použiješ hash-tabulku, ale i její sestavení něco stojí, je to v podstatě indexování (přičemž takto indexovaná data za chvilku zahodíš) a vyhledávání sice znamená napsat data[„klíč“], což je pár znaků v kódu, ale z hlediska výkonu to taky něco stojí. Proč by měl být tvůj kód v PHP efektivnější, než kód relační databáze? Ta může navíc používat mezipaměť, která přetrvává i mezi dotazy/požadavky.
Té práci se tak jako tak nevyhneš. Zkus si napsat kód, který vypíše všechny aplikace a k nim všechny jejich značky pomocí spojování tabulek. Bez polí se dá obejít jen velmi těžko a i když to uděláš, tak musíš použít přinejmenším nějaká porovnání.
Práce s hash-tabulkou je asymptoticky zadarmo. Každé vložení nebo načtení prvku proběhne v průměrném čase závislém pouze na délce klíče, která je konstantní, takže i celá operace je konstantní. Takže nasypáním N prvků do hash-tabulky a jejich vypsáním strávíš čas O(N) (tedy nějaká konstanta krát N) a lépe to nejde, protože na každý prvek si musíš sáhnout.
„spíš bych ji pojmenoval SimpleORM“
Já bych to ani SimpleORM nenazval – že to má některé nevýhody ORM, ještě neznamená, že to je ORM. Já tu nikde nevidím ty objekty, spíš mi to přijde jako jiný pohled na výsledkovou sadu. Jakubův název (NotORM) je tedy v pořádku*.
„nesmí se to přehánět – je blbost generovat v SQL komplet html stránku.“
Souhlas, v databázi se dá vytvořit nějaký „mezitvar“, třeba v XML – může to být lepší forma, než obyčejná výsledková sada (tabulka/matice).
*) i když tahle móda negací…
Pro mě mají ORM nevýhody dvě:
1. Nutí mě vytvářet nebo generovat nějaké třídy, které mi jsou k ničemu.
2. Kladou neefektivní dotazy.
Ničím z toho NotORM netrpí. Co je to podle tebe?
„Nutí mě vytvářet nebo generovat nějaké třídy, které mi jsou k ničemu.“
WTF?
„Kladou neefektivní dotazy“
V takovém případě můžeš ten dotaz „přebít“ vlastním – donutit ORM, aby použilo tebou napsané SQL (ukážeš mu cestu), ale mapování už zase provádí to ORM (udělá za tebe tu nudnou práci). Nevýhodou je spíš to, že zakrývají relační databáze, zvyšují složitost systému, znepřehledňují*, svádí k jednoduchým (a často hloupým) řešením…
*) ale zároveň i zpřehledňují – přidají totiž jednu horizontální vrstvu, ale ve „vertikálním“ směru aplikaci zase zjednoduší
Podívej se na NotORM jako sestavovač dotazů do databáze. Nic nezakrývá, nezesložiťuje, neznepřehledňuje a nevede k hloupým řešením. Prostě jen vytváří efektivní dotazy a posílá je do databáze ke zpracování. Plně respektuje strukturu databáze i myšlenku, kterou programátor kódem vyjádří, jen k tomu poskytuje pohodlné API.
1. A kdo jinej by měl vědět, např. co se s daným objektem dá dělat, jaké poskytuje možné akce, jaké má vlastnosti atd…? V současnym projektu je
poměrně velká část logiky právě v modelech postavených na ORM.
ORMM rozhodně není ten „blbej moloch“, kterej jen zesložiťuje apliakci a pokládá blbý otázky. Jen se prostě ORM nehodí na všechno a musí se vědět jestli, kdy a jak ho použít. Pak je to výtečnej nástroj zjednodušující programátorovi život.
2. Zajímavé – používám ORM, a rozhodně do DB špatný dotazy nepokládám
(teda, aspoň jsem o tom dosti silně přesvědčen),
Ono by koneckonců ani nebyl problém udělat ORM nad notORM :-)
1. Co se s objektem dá dělat a jaké poskytuje akce, určuje model. Třídy generované ORM ale tímto modelem nejsou, to je další vrstva navíc, která je podle mého názoru zbytečná.
2. Buď prosím konkrétnější. Uveď, jaký používáš ORM, jak ho používáš a jaké to položí dotazy. Ukaž to třeba na příkladu získání aplikací spolu s jejich autory a nálepkami, který je použit v příkladu.
1. A kdo mi zabrání, abych jako model použíl třídu, kterou z ORM podědím?
2. Používám ORM vlastní výroby. Používá se zrhuba takto:
$apps=Applications::find(array(‚lmit‘ ⇒ 10));
$apps->findChild(‚autori‘)
$apps->findChild(‚nalepky‘)
foreach($apps as $app)
{
echo $apps[‚nazev‘];
foreach($apps->childs[‚autor‘] as $autor)
echo $autor[‚jmeno‘];
foreach($apps->childs[‚nalepka‘] as $nalepka)
echo $nalepka[‚nazev‘];
}
Vygenerovany dotazy:
SELECT * FROM application LIMIT 10;
SELECT * FROM autor WHERE id IN (SELECT autor_id FROM applicationautor WHERE ID in (1,2,3,4,5,6,7,8,9,10))
SELECT * FROM nalepky WHERE ID in (1,2,3,4,5,6,7,8,9,10)
1. Nezabrání ti samozřejmě nikdo (tedy třeba kromě zaměstnavatele). Jen se tím typicky zhorší udržovatelnost a testovatelnost kódu – zvýší se jeho komplexnost.
2. Vidím, že se tvé myšlenky ubíraly podobným směrem jako moje při vývoji NotORM. Ale srovnej to s kódem použitým NotORM:
Výhody NotORM vidím tyto:
applicationautor.poradi
.Výhody tvého ORM nevidím žádné. Doporučuji proto přechod na NotORM.
1) Pokud jsou optimální selecty, které získávají data z db složitý, mám dvě možnosti:
a) vždy je napsat ručně (byť za mírné podpory nějaké leighweight knihovny typu notOrm – protože v sestavení správných where a join podmínek mi žádná taková knihovna nepomůže)
b) zabudovat genrování správných sql dotazů přímo do modelů: opět k čemu mezivrstvu. Teda pokud nepočítám knihovny typu dibi apod, který trochu zpřehledněj SQL zápis.
Kód přitom zas tak složitej není, protože obecný ORM modely se napíšou jednou a pořádně se otestujou, a v jednotlivých konkrétní modelech se pak píše aplikační logika a popř. upřesnění, jak má knihovna se záznamem nakládat (např. podle kterých sloupců má kontrolovat uživatelská práva).
Až na výjimky se v nich nemusí použít SQL – ale když je potřeba, tak to jde.
Jelikož např. práva jdou efektivněji vyřešit když vím, že dělám select
na děti jednoho rodiče, od nějž jediného mohou zdědit práva než když to nevím, tak jaksi model do generování SQL dotazů tak jako tak šahat musí – takže si nedokážu představit, jak oddělit model a databázovou vrstvu a přitom zachovat efektivní generování uživatelských práv.
Nehledě na to, že např. pro získání podřízených objektů model taky musí nějak „vědět“, jaké jsou jeho podřízené objekty a jaká je relace mezi nimi. A od toho je ke generování SQL dotazů takovej kousek, že vrážet tam další vrstvu se mi zdá jako zesložitění, nikoli zjednodušení.
2) Samozřejmě, že je to v notOrm o něco jednodušší – taky je to knihovna pro jednoduchej snadnej přístup k databázi. Platí za to flexibilitou a možností rozšíření.
Není potřeba předem určovat, se kterými tabulkami se bude pracovat.
Na druhou stranu, když budeš chtít pracovat pouze s autorem první aplikace, tak se ti stejně natáhnou všechny. Což příliš optimální není. Já si můžu vybrat. Nebo si myslíš, že tam dopsat automatický přednačítání všech podřízených záznamů by byl takovej problém? Asi tak na tři řádky. Je fakt, že tam můžu dát parametr, jestli to rovnou přednačíst nebo ne, to neni blbej nápad.
API zdá se vůbec nedovoluje přistoupit ke sloupci applicationautor.poradi.
Ale umožňuje, akorát jsem to psal z hlavy, tak jsem se nekouk, že autoriaplikace neni čistě vazební tabulka. Samozřejmě můžu přistupovat i pomocí
$app->childs('applicationautor')->childs('autor')
Akorát mám možnost dopsat objektu i složitější vazbu, pokud potřebuju.
Např. „ignorovat“ MxN vazební tabulku, která je v podstatě implementační detail.
Přenášení jen použitých sloupců je zajímavá featura, nicméně zatím jsem se nedostal do situace, kde bych masivně načítal takové množství záznamů, že by mě to pálilo. Taková kontrola uživatelskejch práv je daleko větší zdržení a to se udělat musí. Nicméně je to hezký nápad a nevylučuju, že se jím někdy neinspiruju.
No á závěrem :-) výhody mojí knihovny nevidíš, protože nevíš, co umí. Samozřejmě když porovnáš lehkou knihovnu zaměřenou na co nejjednodušší načítání dat z db se složitějším frameworkem, tak jednoduchá kniohovna mírně vyhraje snadností zápisu… Stejně jako když si dá silniční speciál na dálnici závody s offroadem.
Fór je v tom, že u toho funkce Tvojí knihovny končej, zatímco mojí začínaj, ať jde o modifikaci dat (ať už s automatickou nebo manuální synchronizací s databází), kontrolu práv (poměrně dosti netriviální, pomocí ACL, uživatelských skupin a dědění oprávnění z nadřazených objektů), kontrolu kvót na počet podřízených objektů daného typu, validace dat apod. A to všechno vzhledem k databázi šetrným způsobem.
Netvrdím, že se to hodí vždy a všude – dovedu si představit spoustu projektů, kde bych notORM použil radši, ale i naopak – jen prostě tvrdím, že jsou případy, kdy ORM přístup umí využít výhody ORM, aniž by ztratil schopnost pokládat inteligentní dotazy.
Nějak nevidím, kde NotORM chybí jaká flexibilita a možnosti rozšíření. Jakákoliv logika se dá postavit NAD knihovnou, což považuji za čistší řešení než DO knihovny.
Když by se pracovalo jen s autorem první aplikace, tak se samozřejmě dá napsat
$db->applicationautor("application_id", $application["id"])
. Jenže tohle je potřeba výjimečně, takže jednodušší API ($application->applicationautor()
) je využito pro převažující variantu. Každopádně určovat to předem je zbytečné.NotORM schopnost ukládání také má. Schválně by mě zajímalo, jak v tvém ORM vypadá kód, který položí dotaz
UPDATE tab SET rank = rank + 1 WHERE group_id = ?
. To je totiž pro většinu ORM prakticky neřešitelný problém a když už se dá vyřešit, tak se napíše mnohem víc kódu, než při ručním položení dotazu. NotORM i tohle zvládne elegantně.Ad NAD knihovnou – právě podstata toho příspěvku nad tím byla ta, že pokud potřebuju do databáze přistupovat se složitejma kritériama, tak si stejně drtivou většinu podmínek a SQL logiky musím napsat sám (respektive použít knihovnu, která mi ji vygeneruje). Čímž se mi naprosto ztratí výhoda oddělení SQL od modelu.
Kdyby šlo napsat
tak by to smysl mělo, jenže to prostě nejde. Respektive nejde tak, abych pokládal dotazy efektivně, aniž by NotOrm výraz generoval samotnej model (respektive tableModel – čili objekt popisující záznamy jednoho typu, ale nechci zabejhat do podrobností).
V tom cachování máš pravdu – knihovna je ve vývoji, takže tam dopisuju co potřebuju. Todle je rozumný, takže volitelný automatický přednačítání dle parametru už tam je. :-)
Že se to používá výjimečně ale neni až tak úplně pravda – např. zobrazuju seznam věcí a u prvního (nebo i prvních třech z třicíti) zobrazuju víc podrobností. (např. seznam letenek, u první zobrazim i
kde se přesedá atd…). AJAXem pak na rozklik zobrazuju podrobnosti u dalších záznamů…
Ad ukládání – psal jsem o možnosti volby automatický synchronizace s databází. Ty máš jenom manuální. Nebo jak by Ti fungovalo
:-)
Ale zrovna jak ukládání, stejně jako (fakultativní) přednačítání, jsou naprosto nedůležitý detaily – stejně jako já si můžu dopsat načítání, tak ty synchronní ukládání nebo možnost měnit idčka. O takovejdle „blbinách“ se imho nemá smysl bavit, je to jen honění trika co koho zrovna napadlo a implementoval.
Co se týče update rank = rank + 1, tak takovýdle dotazy jsou často způsobený špatnym návrhem datový struktury – akce jednoho objektu by neměly vést k úpravě celé databáze. Navíc pokud nemáš aplikační logiku v databázi, tak jsou často i nelegální (obcházej nějakej kus aplikační logiky, takže časem při úpravách kódu může dojít k nekonzistenci).
Nicméně i pokud je nutné je použít a mám aplikační logiku v modelu, tak jediný místo, kde můžu aspoň trochu legálně takovejdle dotaz položit, tak je v modelu. A tam mam přístup k plnýmu SQL. A nevěřim, že v NOTorm bude ten zápis o tolik jednodušší než v SQL.
Ono třeba v tom tvym případě – je to jednoduchej dotaz: ale já bych zas u toho např. musel řešit práva – můžu to vůbec udělat? A zajistit, že pro všechny ty záznamy bude hodnota rank+1 povolená, promyslet, co se stane když tydle dotazy poběžej dva najednou atd…
Nicméně, protože kromě samotnejch modelů používám i tableModely, tak
pokud bych takovýdle update potřeboval tak často, že by byl opruz je psát v čistym SQL, tak by nedalo moc práce tam tydle metody dopsat – metody na generování where podmínek mám, na generování update SQL taky.
Ad 1) Tohle se nedá říct obecně, pokud vytváříš aplikaci s bohatým doménovým modelem, nejen že není tato vrstva navíc zbytečná, ale dokonce se stává jsou z nejdůležitějších částí kódu vůbec. NotORM vypadá šikovně pro primárně read-only stránky, ORM má zase svou sílu v „plnohodnotných“ aplikacích. Možná jsi to tak i myslel, jen zde v komentářích nějak zapadl kontext.
Nebolo by lepšie pri ukladaní/loadovaní do/z cache robiť hash z toho namiesto ukladania celého dotazu ?
$this->notORM->cache->load("$this->table;" . implode(",", $this->conditions));
na
$this->notORM->cache->load(md5("$this->table;" . implode(",", $this->conditions)));
???
Jistě by to šlo, ale přínos v podobně pevné délky klíče se mi zdá malý ve srovnání s tím, že by nebylo možné selektivně smazat záznamy týkající se nějaké tabulky nebo sloupce a poznat, co v cache vlastně je.
S tim prozkoumávánim cache souhlasim, ale selektivně promazávat cache se stejně bude jen pro určitou tabulku či konkrétní dotaz – pak by mělo smysl uvažovat o dvojúrovňový cache [table][md5(conditions)] kde to md5kovaní by se dalo zapnout jen pro produkční server…
a jak tahle knihovna resi omezeni vyberu zaznamu z tabulky jedne joinem dat z tabulky druhe?
Viz předchozí odpověď – řeší to pomocí poddotazů, které dokáže sestavovat.
Autor tejto urcite zaujimavej kniznice ma velku prax v tvorbe PHP kodu, ale to mu nepomoze urobit lepsi nastroj, ako priamu tvorbu dotazov. Neda si vysvetlit, ze subselecty su do urcitych verzii MySQL(stupnovite) neefektivne a mysli si, ze eleganciou to nahradi. Objektovejsie sa to bude pisat, ale neefektivnejsie to bude fungovat. Je to pekna hracka a tak to aj treba brat.
Kcem sa opýtať či NotORM obsahuje profiler/rozhranie (najlepšie prepojitelne s Nette 0.9), kde zistim počet rq a ich znenie. Poprosim ukážku kódu. THX
Nic takového zatím není, ale uvítám řešení.
A co použít dibi knihovnu a profiler v ní?
Jak předám NotORM informace jak se konektnout k db (driver, password, username …)
Nijak. Konstruktoru se předává již navázané připojení pomocí PDO (resp. Dibi), které NotORM využívá.
Zajímavé. Proč Dibi a ne přístup k mysql co mám PHP nativně? Vždyť to musí NotORM spomalovat.
Řeší NotORM zápis do tablulky (insert)?
Výchozí připojení je přes PDO, které je stejně nativní jako extenze MySQL. NotORM se dá použít s více databázovými systémy, takže je nějaká sjednocující vrstva potřeba. Kdo používá Dibi (nebo nepoužívá PDO), tak ho může použít i s NotORM.
Zápisy k dispozici volitelně jsou: http://www.notorm.com/#persistence
Mám tabulku dbtest v které jsou dva sloupce id (auto increment) a data
for cyklem to chi po jednom řádku číst, když je to formulováno takto, tak
$data = $dbtests->data[$i];
mi laděnka hází chybu Undefined variable: dbtests
nevíte někdo co s tím
Dobrý den, bohužel v celé diskusi bych našel příspěvků, které by Vám nepsali, že NotORM je nesmysl, hloupost a (špatná) hračka, které se dají spočítat na jedné ruce.
Přiznám se, že o existenci NotORM vím už delší čas, ale na první pohled se mi nelíbílo, že neni objektový, proto jsem jej nestudoval, spíše jsem se mu vyhýbal a zavíral jsem před ním oči.
Ale dnes jsem si přečetl tento článek a příjde mi, že to neni hračka, pokud bych pracoval na nějaké projektu, kdy by byl pro mě přínosný, určitě bych po něm sáhnul jako po užitečném nástroji.
Výborná práce.
PS: Určitě by mu slušelo i možnost psát inserty ve stejné syntaxi, představte si situaci, kdy při vytváření nové aplikace chci zrovna i přidat novou nálepku. Vytvořím aplikaci → získám její id → vytvořím nálepku → získam její id → spojim je… :)
Podpora vkládání záznamů je k dispozici v samostatné větvi.
tohle je vazne prasecina, tohle vetsinou potrebujeme v jednom selectu a pak s tim dal pracujeme, efektivnejsi je ,se sql serveru dotazovat co nejmene a rovnou si vracet hotovou datovou kostku. To ze lidi neumi sql pak resi takovejma jak to nazvat… no…fuj
To je omyl, jeden dotaz velmi často nejefektivnější není. Důvodem je, že se stejná data přenáší opakovaně. Pro příklad použijeme třeba výpis článků, kde u každého článku chci zobrazit do jaké kategorie patří (1) a které jsou u něj nálepky (N). Pokud jsou dva články ve stejné kategorii, tak se název kategorie (a všechny další případné informace, které ke kategorii potřebuji) přenáší znovu s každým článkem – to ještě nemusí být tak moc dat navíc. Hlavní problém způsobí nálepky, kdy se s každou nálepkou (jejichž názvy se také přenáší opakovaně) znovu přenáší kompletní informace článku – a to už je dat hodně.
Podrobně jsem to rozebíral v článku Srovnání dotazů do závislých tabulek, kde je z obrázků dobře patrné, jak náročná komunikace u jednotlivých řešení je.
Prasečina je pokládat lineární počet dotazů (při každém průchodu cyklem jeden). Konstantní počet dotazů je naopak asymptoticky ten nejefektivnější způsob. Někdy může být maličko horší než jeden dotaz, nikdy ale nebude řádově horší a naopak může být i řádově lepší.