Použijte DB konečně naplno - zapomeňte na DB layer

U spousty PHP projektů se člověk setká s databázovým layerem. Na tom není v zásadě nic špatného, objektový layer nad sadou funkcí je nutná věc. Špatné je, že většina těchto layerů "podporuje" více různých DB (ano, to je špatné), a to pochopitelně na úrovni nejnižšího společného jmenovatele. Takže se přes layer umíte připojit k DB, provést SELECT či INSERT, získat další záznam, případně chybové hlášení, a ... to je vlastně všechno.

Neuvěřitelná primitivnost. Jenže dnešní databáze toho umí mnohem více.

Problém je, že pokud se dostanete za hranice primitivního ANSI-92 SQL, 16 let stará věc, tak podobnost databází končí. Pokud definujete uloženou proceduru či funkci v T-SQL, nebude fungovat na Oracle s PL-SQL a už vůbec ne v primitivním MySQL.

Dokonce i trivialita jako je vynucení použití určitých indexů, nebo i návrh VIEW nebude všude fungovat stejně. Definice pro cizí klíče je odlišná. Ani datové typy nejsou stejné. LIMIT x není stejný. Nad Oraclem namísto IDENTITY či AUTOINCREMENT polí budete muset dělat sekvence a triggery pro BEFORE INSERT na daných tabulkách.

Databázové layery, které pracují s více typy databází, mají smysl pro některé open-source projekty. Tam je rychlost nadřazena nad výkon a spolehlivost. Jejich programátoři se poté omezují na nejprimitivnější SQL, "aby to fungovalo všude". Osobně ovšem ze všech projektů, kde jde o výkon, databázový layer pro model více databází odstraňuji (pokud tam je), ponechávám jen DB jedinou a optimalizované objekty pro ni, a snažím se vyždímat z této konkrétní použité databáze maximum.

Pro jeden velký portálový projekt (stovky tisíc pageviews denně) používám SQL Server 2008 a IIS7 právě proto, že T-SQL je mocný nástroj, a to i při propojení na PHP jako back-end. Na výkonu "skriptovaného" PHP zde tak v podstatě nezáleží, použije se jen pro prezentační část, a na to je PHP velice dobré.

Databázový layer pro více DB není znakem pokroku, u projektů postavených pro jeden konkrétní systém je často naopak znakem toho, že daný vývojář zná jen základy SQL a nic víc. Vše ostatní "prasí" na aplikační úrovni, přestože zpracování na serveru bývá rychlejší a výhodnější.

Asi založím "Ligu proti databázovým layerům" s podtitulem "Použijte vaši DB konečně naplno a nativně (a nejenom na primitivní SELECT a INSERT)" 🙂

Dnešní rychlokvašná "MySQL generace" totiž vůbec neví, že databáze jsou určené k tomu, aby se v nich programovalo.

Komentáře 27

  1. #1 Jakub Fojtl

    Pod to se ti klidně podepíšu nebo se rozdělím o náklady na provoz domény 🙂 Nicméně model je stále dobrá věc, jen je potřeba na něj potřeba nahlížet trošku jinak, než jako na implementaci ActiveRecordu, ORM či něčeho podobného.

  2. #2 Daniel Tlach

    Já nějak nevím ale vždycky mi stačilo používat právě jen ten SELECT, INSERT atd. K čemu cokoliv jiného? Právě proto, že si udělám maximum na straně DB pak nepotřebuji vyrábět a posílat nějaké šílené dotazy z front/backendu.

    Na straně DB si vytvořím například proceduru na ověření uživatele a tu pak jen zavolám s příslušnými parametry. Pak už je IMO jedno čím jí volám (třeba u PHP je volání MSSQL procedur blbě vymyšlené). Layer se pak stará jen o správné a bezpečné předání dotazu, vše ostatní už je na úrovni databáze.

    IMO layery nenesou vinu na tom, že mnoho lidí nepoužívá pokročilé možnosti databází. U MySQL je chyba v databázi, protože tam ty možnosti prostě nejsou ale u jiných databází je to spíš o tom, že manuály čte málokdo a nějakých školení nebo alespoň článků na téma pokročilé práce s databázemi je jako šafránu.

    Třeba bys mohl tady na blogu nějaký takový seriál rozjet. Těm z nás, co už nějaké základy a informace mají to rozšíří obzory, ti ostatní se dozví, že databáze skrývají víc než se na první pohled zdá. Sám bych něco takového napsal ale na to myslím nemám dost znalostí.

  3. #3 Hmm.. Trochu drze ziadat skutocne meno, nie? ▲2 ▼2

    1. Vies nam uvies nejaky prakticky priklad, na ktorom si robil, ktory vyuziva nove veci v T-SQL ?

    2. Ty pises formulare rucne? A ked chcem pridat pole, tak zakazdym pridavas <input name="telefonne_cislo"> do view, a do model pridavas INSERT INTO (..., telefonne_cislo) VALUES (..., $_POST["telefonne_cislo"])

    No tak neviem mne pride @zakaznik.update_attributes params[:zakaznik] o dost jednoduchsie (ruby)..

    A napriklad PHP Symfony generuje formulare automaticky, teda cely kod je <?php echo $form ?> Ty to vazne pises rucne?

  4. #4 Radek Hulán autor webu ▲10 ▼1

    [3] nechápu proč do článku o DB pleteš formuláře. Máš problém s chápáním psaného textu?

    Upozornění pro méně chápavé: v článku se nepíše o používání přímo DB funkcí či nepoužívání DB layeru vůbec, ale o tom, že tento layer nemá být používán jako "nejnižší společná množina" pro veškeré možné databáze (typická vlastnost DB layerů) a fukčnost tomuto primitivnímu pojetí uzpůsobena (pokud člověk nevyžaduje podporu více DB, což v 99% není nutné).

  5. #5 Hmm.. Trochu drze ziadat skutocne meno, nie?

    Prosim ta nebud ofenzivny. Ja sa ta to pytam, pretoze ma zaujima akym sposobom programujes, a mojim cielom nie je ta urazit alebo ponizit. Chcem iba diskutovat, a zistit ako to robis.

  6. #6 David Grudl ▲0 ▼1

    Běžný programátor si sice vystačí s primitivním neobjektovým driverem jako je SQL Server 2008, ale profík potřebuje pořádný nástroj, kvalitní objektovou vrstvu.

  7. #7 Radek Hulán autor webu ▲11 ▼1

    [6] to je opět nepochopeno 😉 Nad sqlsrv() se samozřejmě postaví objektová vrstva, ale dedikovaná pro tento konkrétní server.

    Opakuji to podruhé: píšu zde o layerech, které implementují pár základních a stejných funkcí pro veškeré (velice rozdílné) DB, s tím že většina autorů se poté omezuje jen na jejich používání, namísto aby 100% programovala pro danou DB. Výsledkem je naprosto neefektivní kód, není to LINQ, ale jen obal na pár funkcí. Sám programátor se musí starat o optimalizace pro danou konkrétní DB. To, že volám $db->fetch() a ne sqlsrv_fetch_array() mě opravdu nevytrhne. Ani Zend DB Adapter není řešení.

    V tomto smyslu je DB layer doslova škodlivá věc (a v desítkách open-source projektů co jsem viděl v podstatě jen takto používaná - k databázi se přistupuje tak "aby to fungovalo všude", tedy neoptimálně).

    Ukaž mi DB layer pro PHP, co dokonale a 100% převádí T-SQL na PL-SQL a na uložené procedury v MySQL, to samé pro relace, typy v tabulkách (včetně autoincrement), indexy, nakonec i obyčejné (složitější) SELECTy a VIEWs a začnu jej používat 😉

    Neber to prosím zle, vážím si moc tvé práce na Nette, ale třeba Dibi je pouze obal na pár jiných funkcí, který nic z tohoto neřeší. Pokud člověk má 100% používat danou DB, takový layer mu vůbec nepomůže při migraci na jinou DB (ani při 100% využití té jedné zvolené). Vše je najednou zcela jinak.

  8. #8 David Grudl ▲0 ▼1

    Databázový layer přeci není od toho, aby pomohl při migraci na jinou DB. Tobě vadí Database Abstraction Layer (mně také http://latrine.dgx.cz/zlo-si-rika-database-abstraction-layer...), ale to je něco jako odmítat trabanta slovy, že automobily jsou nesmysl.

    Třeba zrovna u dibi jsem zdůrazňoval, že v žádném případě neřeší:
    - zajištění kompatibility SQL příkazů
    - emulace funkcí chybějících některým databázím

    přesto je to stále databázový layer.

    Dále - ačkoliv se všechny databáze značným způsobem liší (což je vynikající, nejen pro konkurenční prostředí), mají určité části téměř identické - například výsledky dotazu jsou tabulkou, tedy sérií polí skalárních hodnot. Zapouzdření a zpracování result setu pak může řešit společný kód. Pokud nechci do každého layeru pro každou databázi kopírovat stejné třídy, mohu efektivněji spojit více layerů a sdílet společné knihovny. Výsledkem je pak databázový layer podporující více databázových serverů.

    Výsledkem je stále efektvní nástroj. Při migraci těžko pomůže, ale k tomu nikdy určen nebyl.

  9. #9 Radek Hulán autor webu ▲10 ▼1

    [8] nejedná se (jen) o migraci. Jedná se o to, že pokud chci výkonnou aplikaci, MUSÍM ji napsat pro konkrétní DB na míru. V tomto mi Dibi rozhodně nepomůže. Otázkou tedy je, proč tam mít layer pro 10 databází, když ten kód stejně nebude fungovat na ničem jiném než té zvolené.

    Na toto stačí malý tenký objekt, který zapoudří klasické funkce PHP a přidá k nim to, co potřebuji pro danou DB.

    Když se podíváš na jakoukoliv open-source aplikaci kolem, tak na optimalizaci pro jednotlivé DB se zcela rezignuje a "prasí" se to, právě díky DB layerům pro více DB, jen v nejzákladnějších SQL příkazech. I obyčejné phpBB fórum by mohlo být několikrát výkonnější kdyby rezignovalo na podporu hromady databází.

    Naivní lidé si pak myslí, že "více je lépe", ale ono to v případě DB rozhodně neplatí 🙂

  10. #10 David Grudl ▲1 ▼1

    [9] Zcela souhlasím, aplikace také píšu na míru konkrétní databázi a na zapouzdření mi stačít tenká mini-vrstva (mini + DB = dibi) a Dibi je mi tedy obrovským pomocníkem.

    Stále ale nerozumím, proč když budu distribuovat takových sedm tenkých vrstev pro různé DB v jednom archívu, tak je to najednou škodlivá věc.

    Už vůbec nerozumím příkladu s phpBB fórem. Předpokládám, že toto fórum bylo od počátku také psáno na míru konkrétním databázím (množné číslo) a k zapouzdření také použili tenké vrstvy. Proč by to mělo být v tomto případě prasení?

  11. #11 Radek Hulán autor webu ▲10 ▼1

    [10] předpokládáš špatně. Stáhni si phpBB. V SQL příkazech uvidíš jen CREATE TABLE, žádné VIEWs, uložené procedury či funkce, žádné triggery, ba ani žádná referenční integrita a CASCADE při DELETE. Typická open-source aplikace používá DB layeru jako jediné možné funkčnosti. Optimalizace pro jednotlivé DB nulová.

    A to je průser, na tom se shodneme snadno 🙂

    Dej lidem DB layer (nutně umějící tak 10% funkcí dané DB, aby to fungovalo i v jiných), a oni přestanou přemýšlet, co je mimo něj...

  12. #12 David Grudl ▲1 ▼1

    [11] "žádné VIEWs, uložené procedury či funkce, žádné trigger" - to je přece optimalizace, konkrétně pro nejrozšířenější databázový stroj MySQL 4.1. Fórum phpBB se nestalo populární proto, že by fungovalo jen s nejnovější verzí Oracle, ale proto, že funguje na nejširším spektru hostingů.

  13. #13 Arleth Pavel

    Hlásíme se z druhého břehu - mimo svět PHP a MySQL🙂

    Zcela vážně - tentokrát s Radkem musím souhlasit, což nebývá vždy. Pokud chcete slušně psát interakce s databází, na DB layerech pro webové aplikace se to nikdy nenaučíte.

    Naprosto souhlasím s tím, že vše, co manipuluje s daty patří do databáze, zvláště kritické operace. A protože jsou databáze rostě rodílné, nelze napsat jakýkoliv rozumný universální DB layer, jak to nazýváte. Enormní to je pak na vyspělejších databázích s vnitřním programovacím jádrem a jejich rozšířeníma - typicky Oracle, MSSQL a z OS PSQL, Firebird.
    A to mluvíme jen o možnostech interního kodu typu T-SQL nebo P-SQL. A kde máte rozšíření přímo pro DB stroj (Oracle - Java, MSSQL - SP přímo v .NET) ? A kde máte využití databázových farem ? A jak zpracováváte cross link query mezi databázemi ? To jako vše natáhnete na aplikační vrstvu a pak výsledky odešlete zpět ?

    Pokud již cítíte nutnost layeru nebo wrapperu, tak zásadou je vždy 1 typ DB stroje, maximální využití možností dané DB (kaskádová referenční integrita, optimalizované indexy pro daný stroj, uložené procedury pro řízení update, výchozí hodnoty polí, transakce, updatable views, triggers) a pokud možno využít middleware (aplikační server), tam, kde se to vyplatí.

    Jedinou omluvou budiž layer pro konkrétní aplikaci, která ŘÍZENĚ předpokládá běžné přepínámí mezi několika typy databází za chodu aplikace - ale to jsou výjimky.

    Nicméně nenapadám ani Davida Grundla, protože vlastní DB layer pro projekty které si píše sám nepatří tak ani do katagorie obecných DB layerů, ale do pokusu o middleware.

    Radek H. spíše napadá bezhlavé používání předžvýkaných knihoven, o nichž ti, co je používají, nic nevědí a jsou na hony vzdáleni skutečnému programování v databázích. Bohužel má pravdu v tom, že to je běžný jev právě u webových aplikací.

  14. #14 SpinGee ▲1 ▼1

    Já znám a umím pracovat s jedinou databází - MSSQL, s Radkem proto souhlasím😉Ale Radku vyprdni se už na to PHP a začni psát články o ASP.NET, LINQ ,WPF ... což jsou jediné pokrokové a funknční technologie.

  15. #15 Jiří Komoň

    Proti tomu, že společné headery oklešťují možnosti při prgání na minimum, nemám ani čárku, s tím nelze než souhlasit. Jen ale v rychlosti bleskněte nad tím, proč u opensource projektů layery pro tolik druhů DB jsou. Jde právě o to, že je to opensource aplikace, která už je autorem hotová (resp. základ), a už jako jakýsi produkt nabízena masám - širokému spektru uživatelů, kteří nedisponují stejným základem jako je typ DB. Proto se to píše "primitivně", aby to fungovalo všude.

    Naproti tomu je něco jiného masivní aplikace stavěná na míru zákazníkovi (či sobě, etc.), kde jsou dopředu jasně daná specifika, technologie, a je možné už při jeho vývoji počítat právě se známými dispozicemi, a vytěžit z nabízené funkcionality maximum. Souhlas tedy i s tím "proč se omezovat", ale nesrovnával bych to s opensrc.

  16. #16 Petr Charvat

    Hlásím se ze světa Javy. Tam máme bubíčka (ORM)jménem Hibernate, který má odstiňovat programátora od různých dialektů databází. Na několika aplikačních projektech se ukázalo, jak kontraproduktivní tento přístup je a to nemluvě o projektech na DWH a to i tehdy, kdy od začátku je jasné že nikde jinde než na Oraclu to nepoběží. Takže musím s Radkem jen souhlasit. Mnohem lepší je přístup knihovny iBatis, jejíž klon je i pro .NET.
    Dle mého názoru je migrace na jinou databázi čistě obchodně marketingový trik, jak obalamutit manažery, kteří drží budget.

  17. #17 Daniel Tlach

    [16] Podpora více DB rozšiřuje potenciální klientelu. Nikdy nevíte, kdy za Vámi přijde klient, který má zájem o Váš produkt ale místo MySQL má na serveru například PostgreSQL nebo MSSQL.

    Buď vyhovíte (máte podporu pro více DB nebo připravíte verzi pro tu jeho) nebo se omluvíte - což pro Vás může (a samozřejmě nemusí) mít nepříjemné následky. Z vlastní zkušenosti vím, jací dokáží být především čeští klienti zmr*i, když není po jejich 🙂

    Ale to s layery asi příliš nesouvisí.

  18. #18 lf ty

    [16] hibernate rozhodně nemá (alespoň ne prvoplánově) odstiňovat programátora od různých dialektů sql, ale poskytovat objektově relační mapping. V tom je rozdíl. (Tím nijak neobhajuju hibernate, jsou projekty, kdy se může hodit, stejně jako existuje spousta scénářů, kdy je díky své těžkopádnosti nepoužitelný)

  19. #19 Zdenek

    Použijte DB konečně naplno - zapomeňte na relační DB a přejděte na ODBMS

    😉

  20. #20 Petr ▲2 ▼1

    Nedávno jsem zaslechl i v celku rozumný argument proč se pro komunikaci s DB v aplikaci omezit jen na základní a nejjednodušší SQL příkazy a vše ostatní provádět v aplikačním kódu:
    Databáze, není-li distribuovaná (což ovšem přináší řadu potíží), nemůže svůj výkon zvyšovat do nekonečna. HW možnosti jsou stále ještě omezené, než aby jeden server dokázal obsloužit miliony požadavků současně. Proto, ty opravdu veliké aplikace mají vlastní, co nejnabušenější, DB server, kde je jen konzolový OS a databázový systém. Aplikace samotná je pak nahrána na více dalších serverech v síti (webové farmě) a na databázi má jen co nejjednodušší SQL dotazy, aby ji zatěžovala co nejméně. Data tedy jen přečte a zpracuje si je už sama (seřadí, propojí, seskupí atd.). Když nedostačuje výkon, přidá se jen další aplikační server do farmy, což s databázovým bohužel udělat nejde. V tomto přístupu je pak jakýkoli aplikační kód v databázi celkem kontraproduktivní.
    Nicméně DB layery nejsou vždy vhodné ani pro tento přístup, protože se ne zcela snadno kontroluje, jaké SQL dotazy do databáze nakonec pošlou. Nicméně nemuset v kódu slepovat vlastní SQL je velmi vítané...