NOVINKA - Online rekvalifikační kurz Java programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!

Diskuze: Doctrine snížení počtu dotazu

V předchozím kvízu, Online test znalostí PHP, jsme si ověřili nabyté zkušenosti z kurzu.

Aktivity
Avatar
Neaktivní uživatel:24.11.2017 12:27

Hoj,

mate někdo zkušensti s Doctrine?
Mam entitu s self-referenced onetomany relations ship (strom kategorii) a když se snažím hledat ve všech child záznamech tak to generuje směšný počet dotatz.

Např mam tyto kategorie:

Laptot

  • Apple
  • Microsoft

Kdybych chtěl dostat veškere zboží ze všech kategorii(apple, microsoft) tak mi to generuje 14 dotazu...

Odpovědět
24.11.2017 12:27
Neaktivní uživatelský účet
Avatar
David Hartinger
Vlastník
Avatar
Odpovídá na Neaktivní uživatel
David Hartinger:24.11.2017 12:42

Rekurzi asi moc efektivně v databázi neuděláš, nestačilo by to jen cachovat? My tohle většinou řešíme tak, že se zacachují všechny položky a ten strom se potom prochází na serveru, aby se na to nemuselo ptát databáze.

Nahoru Odpovědět
24.11.2017 12:42
New kid back on the block with a R.I.P
Avatar
Odpovídá na David Hartinger
Neaktivní uživatel:24.11.2017 13:16

No, lámu si s tím hlavu už 2 dny a níž jak na 12 dotazu to nesnížím.

Jinak dobrej nápad s cachováním, aspoň to nebude zatěžovat DB. Díky

Nahoru Odpovědět
24.11.2017 13:16
Neaktivní uživatelský účet
Avatar
David Hartinger
Vlastník
Avatar
Odpovídá na Neaktivní uživatel
David Hartinger:24.11.2017 13:18

12 dotazů nějakými cykly nad polem v paměti je úplně v pohodě, to je hned. Na databázi je to horší :) Cachuj to už jako strom (pole polí polí...), aby to bylo rychlejší.

Nahoru Odpovědět
24.11.2017 13:18
New kid back on the block with a R.I.P
Avatar
Jirka Jr
Člen
Avatar
Odpovídá na Neaktivní uživatel
Jirka Jr:25.11.2017 14:55

koukam, ze se mi nekdo strefil do meho oblibeneho tematu :-)

tipuju, ze si u kazde polozky zbozi nebo kategorie ukladas id rodicovske kategorie

navrhuju uplne jiny model, ktery jsem zatim neimplementoval v doctrine, ale v obyc. SQL jsem v tom implemetoval stromecek kategorii v helpu jedne webove aplikace plus editor toho stromecku

misto id rodicovske kategorie si u kazde kategorie ukladej do jednoho varchar sloupce cestu
ale tak, aby kazda polozka cesty mela max. rekneme 4 znaky (tedy maximum 9999 kategorii v databazi)
muze se zvysit treba na 5 (potom je maximum kategorii 99999) a tak dal.

priklad:

id: 1
cesta: ''

id: 20
cesta: '0001'

id: 35
cesta: '0001/0020'

id: 36
cesta: '0001/0020'

1 - Všechno Zboží
20 - Laptop
35 - Apple
36 - Microsoft

sloupec cesta by mel byt varchar(255) a samozrejme tam existuje omezeni v hloubce stromu

v pripade 255 znaku a 4-mistneho id kategorie je to 255 / 5 = 51 (51 levelu stromu je dost na eshop :-) )
v pripade 255 znaku a 5-mistneho id kategorie je to 255 / 6 = 42.5 ~ 42 (42 levelu stromu je porad jeste az az )
v pripade 255 znaku a 6-mistneho id kategorie je to 255 / 7 = 36.43 ~ 36 (36 levelu stromu je furt vic nez dost )

v pripade implementace Amazonu s miliardami polozek zbozi by snad slo strom prohloubit pouzitim dvou sloupcu misto jednoho ;-) ale myslim, ze mozna ani Amazon by toto nevyuzil

samotne polozky zbozi uz muzou mit jen id rodicovske kategorie a veskere dotazy se vyresi joinem k patricnym kategoriim

diky pevne sirce id kategorie (4, 5 nebo 6) muzes vybrat vsechny laptopy Apple a Microsoft jednoduse nejak takto:

SELECT
    *
FROM
    kategorie as k,
    zbozi as z

WHERE
    (
        k.id IN (35,36)
        OR LEFT(k.cesta, 14) = '0001/0020/0035'
        OR LEFT(k.cesta, 14) = '0001/0020/0036'
    )
    AND
        z.kategorie_id=k.id

coz ti vybere vsechny kategorie, ktere jsou Apple a Microsoft a nebo maji Apple a Microsoft za rodice, prarodice, prapra... atd.

joinem se k tomu pripoji veskere zbozi ve vybranych kategoriich a mas vystarano :-)

otazka zni, jak na to v doctrine :-)

sloupec z. kategorie_id neni problem ... entita Zbozi proste obsahuje vztahovou property $kategorie

sloupec k.cesta ($cesta v entite Kategorie) ale doctrine nerika nic o vztahu kategorie a zbozi

muze se ale pouzit DQL, misto funkce LEFT pouzit SUBSTRING a tim kategorie vybrat a omezit jimi vyber zbozi nejak takto:

$query = $em->createQuery("SELECT z FROM Zbozi z JOIN z.kategorie k WHERE  k.id IN (35,36)
        OR SUBSTRING(k.cesta,0,14) = '0001/0020/0035'
        OR SUBSTRING(k.cesta,0,14) = '0001/0020/0036'");
$users = $query->getResult();

je to jen nastrel myslenky a potrebuje to poradne vychytat

ale vysledek usilovne prace muze byt pouhy jediny dotaz :-)

pokud budes implementovat aj editor toho stromu, tak se priprav na matematiku a debugging zahul v podobe prace s retezci v databazi

ale da se to, pokud te takove vyzvy bavi a pokud pouzijes mnou navrhovana cisla kategorii s pevnou sirkou s uvodnimi nulami

jenom pri te editaci stromu, pro jistotu pouzivat transakce/zamky nebo aspon zalohy kategorii&zbozi pred kazdou modifikaci stromu ... neni moc dobre v pripade bugu mit strom rozmrveny a majitele eshopu vytoceneho do bela ...

tady jsou slidy, ktere shrnuji praci se stromy v SQL, ruzne modely krome mnou zmineneho a zakladni operace v techto modelech

https://www.slideshare.net/…a-structures

dalsich takovych navodu je na webu spousta, staci vybrat model stromu, googlit a prevest SQL do Doctrine

 
Nahoru Odpovědět
25.11.2017 14:55
Avatar
David Hartinger
Vlastník
Avatar
Odpovídá na Jirka Jr
David Hartinger:25.11.2017 15:13

To mi přijde jako poněkud nešťastné řešení, jakou má přidanou hodnotu oproti cache všech kategorií, co jsem navrhoval výše? Kromě toho, že je vážně pracné, představ si, že přesuneš nějakou položku do jiné kategorie. Rázem máš nekonzistentní databázi, protože ten string se neaktualizuje, musí se to dělat zvlášť nebo přes triggery. To je zdroj chyb. Obecně ukládat čísla jako stringy je špatná praktika, IMHO je ten model antipattern, ta databáze by měla být navržená rozumně.

Nahoru Odpovědět
25.11.2017 15:13
New kid back on the block with a R.I.P
Avatar
Jirka Jr
Člen
Avatar
Odpovídá na David Hartinger
Jirka Jr:25.11.2017 15:52

nekonzistenci je samozrejme treba osetrit triggerem, jak pises nebo dvema dotazy v transakci jak rikas

co se tyce rychlosti ... editace stromu se dela jednou za cas ... pri cteni staci jedna rychla query s jednim joinem

navic cestu obsahuji jen kategorie, zbozi ma uz primo id kategorie, takze presuny zbozi mezi kategoriemi jsou otazkou jednoho dotazu

samozrejme php soubor s velkym oklicovanym polem kategorii nacachovany pomoci opcache bude rychlej jak vystrasenej pes oproti databazi ...

jenom si nejsem uplne jisty, jak zajistit 100% atomicitu operaci na dvema ulozisti zaraz (php cache, databaze) ... tedy treba odstraneni kategorie vcetne jejicho zbozi

tedy jak zajistim, aby v pripade nejakeho nenadaleho vypadku hw operace nezustala dokoncena jen v jednom z ulozist

nerikam ze to nejde, ale zatim, jedine , co me napada, je pouzit me reseni a pak po kazde modifikujici operaci udelat cache do php souboru

tim se spoji vyhoda atomicity databazovych operaci s rychlosti tveho reseni

ale jestli existuje zpusob, jak zajistit transakci nad databazi a tim php polem zaroven, bude mi i pro mou praxi velkym potesenim ...

 
Nahoru Odpovědět
25.11.2017 15:52
Avatar
David Hartinger
Vlastník
Avatar
Odpovídá na Jirka Jr
David Hartinger:25.11.2017 16:01

Opcache jsou jen k ukládání mezikódu PHP pokud vím, nedají se tam cachovat vlastní hodnoty. My tohle ukládáme normálně do souboru. Načtení všech kategorií z databáze není tak drahá operace, cache se může dát nějaký lifetime, třeba několik minut nebo hodin, záleží na projektu. Potom se nekonzistence vyřeší sama, když něco spadne a někdo by cache potom zapomněl smazat, tak tam bude jen chvíli neexistující kategorie, než sama zmizí. Nevím, jestli by se vůbec měla řešit nějaká "transakce", specifikum cache je, že to není trvalé úložiště a tam tolik nevadí, když to je nekonzistentní.

Nahoru Odpovědět
25.11.2017 16:01
New kid back on the block with a R.I.P
Avatar
Jirka Jr
Člen
Avatar
Odpovídá na David Hartinger
Jirka Jr:25.11.2017 16:21

jeste se nabizi partikularni reseni v podobe vynechani potencialne nebezpecnych operaci ... tedy tech, ktere potrebuji zaraz zapsat do obou ulozist

mam ale ted hroznej hlad, takze se nad tim zamyslim pozdejc, teda jestli me nekdo nepredbehne ... :-)

 
Nahoru Odpovědět
25.11.2017 16:21
Avatar
Jirka Jr
Člen
Avatar
Odpovídá na Jirka Jr
Jirka Jr:25.11.2017 16:23

jejda, nejak jsem nereloadoval a tudiz necetl posledni reakci ;-)

 
Nahoru Odpovědět
25.11.2017 16:23
Avatar
Jirka Jr
Člen
Avatar
Odpovídá na David Hartinger
Jirka Jr:25.11.2017 16:47

už to chápu ... takže v databazi to zůstane pomalé, ale snazší na implementaci

a rychlost se vyřeší pouze pomocí pravidelneho nacachovani v php souboru ...

jj, to je fikané a reálně funkční ...

jenom me irituje, že tam může bejt chvíli vidět něco, co tam už nemá bejt

spis bych tu cache obnovoval pouze po kazde modifikaci stromu v db ... tak casto se strom nemodifikuje v eshopech, co vim

pak by zmizel aj problem se zustavanim neceho, co uz neni

a to moje databazove rychlejsi reseni pak uz nebude potreba

 
Nahoru Odpovědět
25.11.2017 16:47
Avatar
Jirka Jr
Člen
Avatar
Odpovídá na David Hartinger
Jirka Jr:25.11.2017 16:55

jeste k te opcache .... ta si nahraje do RAMky kazdej php soubor, kterej php nacita/interpretuje

tedy aj ten s tema kategoriema

jenom v nejrychlejsi podobe konfigurace opcache nekontroluje data modifikaci souboru, aby je znovu nacetla do RAM

potom je treba pouzit na ten php soubor nasledujici funkci a reseni bude dokonale rychle :-)

http://php.net/…validate.php

 
Nahoru Odpovědět
25.11.2017 16:55
Avatar
David Hartinger
Vlastník
Avatar
Odpovídá na Jirka Jr
David Hartinger:25.11.2017 17:09

Ta cache se samozřejmě invaliduje někde v administračním rozhraní, kde se maže/mění/přidává kategorie. Výhodou toho řešení je, že i když se nesmaže (to se prostě stát může třeba výpadkem), tak stejně po nějaké době expiruje. O té opcache si nejsem jistý, jestli ti pomůže, IMHO to cachuje mezikód, tady by se spíš hodilo Memcached http://php.net/…emcached.php . My to serializujeme do souboru a funguje to skvěle, to je nejjednodušší řešení, jen se nesmí zapomenout správně zamknout.

Nahoru Odpovědět
25.11.2017 17:09
New kid back on the block with a R.I.P
Avatar
Jirka Jr
Člen
Avatar
Odpovídá na David Hartinger
Jirka Jr:25.11.2017 17:22

ta opcache pomuze pokud v tom souboru je php kod s tim polem ... nehlede na to, ze pro molochy typu symfony podstatne zrychli celou aplikaci

memcached je spis na vyplivnuti hotoveho predpocitaneho vystupu v html, txt apod

pokud je v te cache pole, ve kterem se kod hrabe pri vyhledavani, pak opcache

pokud je tam predrenderovany vypis, tak memcached

ale tazatel co vim chce vyhledavat v poli konkretni id kategorii a podle nich pak vytahnout polozky zbozi

takze tady pomuze mit zaplou opcache ... pro celou aplikaci vcetne tohoto souboru

jen je treba davat bacha na veskere php soubory co se sem tam prepisuji a po prepisu je invalidovat a nebo mit obecne zaplou kontrolu last modification time

 
Nahoru Odpovědět
25.11.2017 17:22
Avatar
TomasGlawaty
Člen
Avatar
Odpovídá na Jirka Jr
TomasGlawaty:26.11.2017 9:47

Na vše toto se hodí memcahe(d) :-)
Do memcached si to pole jednoduše uložíš také, pod nějakým klíčem. Následně daný záznam invaliduješ pomocí toho klíče v případě editace stromu. Není problém si tam serializovat klidně celé objekty (tam už záleží na velikosti vyhrazené RAM pro memcached a na mnonžství cachovaným objektů).
Opcache si můžeš nastavit tak či tak, ale pro tyto účely se hodí přímo nějaké storage (file/memcahce/mem­cached/redis.­..).

Btw. něco podobného jako je tvůj návrh s uloženou path (u mne ve formátu 1:2:3) používám pro vyhledávání v ElasticSearch, kde běžné asociace neexistují. V tomto "sloupci" pak hledám pomocí regexu záznamy, které potřebuji.

 
Nahoru Odpovědět
26.11.2017 9:47
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 15 zpráv z 15.