Tak mnie ostatnio zastanawia w #laravel dlaczego relacje w ORM wywołują tyle zapytań. Wychodzi na to jakby zapytania były tworzone w pętli. W pracy na co dzień korzystamy z cake i tam też na niektórych podstronach potrafimy mieć po 100 zapytań, gdzie tak naprawdę mamy wywołanie jednej funkcji i podpięcie kilku relacji, potem to wyświetlenie w pętli foreach, ale w pętli nie wrzucamy żadnych zapytań, a przynajmniej ja. :) Kiedyś czytałem, że nie powinno tego się praktykować i ilość zapytań powinna być jak najmniejsza, ale obecne frameworki walą zapytań do bazy danych mnóstwo, więc jak to z tym jest? Już nieaktualne? Już hostingodawcy nie mają limitów zapytań do bazy?
@nophp: duża ilość zapytań wynika wyłącznie z nieprawidłowo napisanego kodu. Jest to błąd, problem wydajnościowy który powinien zostać naprawiony. To że serwer wytrzyma, to że nie ma żadnych limitów nie zmienia faktu, że da się to zrobić lepiej. Poczytaj o N+1 problem. W ORM pewnie leci jakiś lazy load w pętli.
@nophp: pewnie lazy loadujesz te relacje. Zainstaluj sobie https://github.com/itsgoingd/clockwork albo inny debugbar i podejrzyj co to za zapytania. Eager loadowane relacje nie generują więcej zapytań niż to konieczne, jedyna różnica, że Eloquent dociąga relacje dla kolekcji osobnymi zapytaniami, a Doctrine robi to za pomocą joinów.
@nophp: Trzeba optymalizować zapytania. Jak masz encję, która ma relacje z innymi obiektami, to w metodach takiego modelu bądź w repozytorium domyślne funkcje pobierają tylko podstawowe dane, bez danych powiązanych. Przekładając to czysty SQL, to po prostu bez "JOIN", a zamiast tego nawet i kilkaset zapytań. Im bardziej złożona struktura tym więcej.
Najlepiej samemu napisać zapytanie przy pomocy jakiegoś QueryBuilder'a, którego zwrotem będą encje zgodnie z ORM. Dobrze napisany kod potrafi
SELECT * from mirko_comments to przemiela ORM na 20 obiektów klasy MirkoComment
ale do każdego komentarza chcesz wyświetlić informacje o autorze
więc w czasie wyświetlania komentarza robisz $mirkoComment->getAuthor()->getGender() a ORM, w pętli, dla każdego tak wyświetlanego komentarza, robi nowe zapytanie do bazki o autora:
select * from authors where author_id = ? efekt: 21 zapytań: jedno o komentarze i 20 o autorów
rozwiązanie: do pierwszego zapytania dokleić autorów JOINem. tak, ORMem też da się.
@MacDada: w #laravel (bo o to pytał autor), a właściwie Eloquent nic nie musisz doklejać joinem. Metoda with() eager loaduje relacje, ale w przeciwieństwie do Dotrine dociąga je osobnym zapytaniem przy udziale whereIn po IDkach kolekcji.
@nowiutki o kurde mireczku, muszę obczaić tego debugera co podrzuciłes. Zazwyczaj korzystałem z debugbara od baryvdh, ale były straszne jazdy z zamulaniem. Dzięki!
@nowiutki: pod warunkiem że pobierasz obiekty głównego zapytania wszystkie na raz (za pomocą ->get()), bo jak zrobisz ->cursor() to się te relacje nie załadują
@Ysior: też go kiedyś używałem, ale clockwork lepszy bo możesz debugować również joby w kolejce. Oraz ma plugin pod Firefoxa więc żadnego cssowego/jsowego debugbara nie wciska w kod strony.
Już hostingodawcy nie mają limitów zapytań do bazy?
@nophp: dodatkowe zapytania to zawsze tragedia, które dodają niepotrzebnej roboty i mocno dodają latency do całego zapytania
dlaczego relacje w ORM wywołują tyle zapytań.
@nophp: bo ORMy takie są. Generyczne klocki poskładane w taki sposób, że robią to co maja robić, ale przy użyciu dużej ilości bazowych zapytań, gdzie pisząć takie zapytanie ręcznie możemy je uszyć na miarę
#programowanie #programista15k #php
Najlepiej samemu napisać zapytanie przy pomocy jakiegoś QueryBuilder'a, którego zwrotem będą encje zgodnie z ORM. Dobrze napisany kod potrafi
SELECT * from mirko_comments
to przemiela ORM na 20 obiektów klasy MirkoComment
ale do każdego komentarza chcesz wyświetlić informacje o autorze
więc w czasie wyświetlania komentarza robisz
$mirkoComment->getAuthor()->getGender()
a ORM, w pętli, dla każdego tak wyświetlanego komentarza, robi nowe zapytanie do bazki o autora:
select * from authors where author_id = ?
efekt: 21 zapytań: jedno o komentarze i 20 o autorów
rozwiązanie: do
@MacDada: w #laravel (bo o to pytał autor), a właściwie Eloquent nic nie musisz doklejać joinem. Metoda with() eager loaduje relacje, ale w przeciwieństwie do Dotrine dociąga je osobnym zapytaniem przy udziale whereIn po IDkach kolekcji.
Zazwyczaj korzystałem z debugbara od baryvdh, ale były straszne jazdy z zamulaniem.
Dzięki!
@nowiutki: pod warunkiem że pobierasz obiekty głównego zapytania wszystkie na raz (za pomocą ->get()), bo jak zrobisz ->cursor() to się te relacje nie załadują
Ile to ja się na męczyłem któregoś razu to masakra
@nophp: dodatkowe zapytania to zawsze tragedia, które dodają niepotrzebnej roboty i mocno dodają latency do całego zapytania
@nophp: bo ORMy takie są. Generyczne klocki poskładane w taki sposób, że robią to co maja robić, ale przy użyciu dużej ilości bazowych zapytań, gdzie pisząć takie zapytanie ręcznie możemy je uszyć na miarę