Symfony admin generator – optymalizacja zapytań do bazy dla Doctrine
2009-02-17Ostatnio w projekcie Symfony 1.1 z użyciem Doctrine, dzięki webdebug toolbarowi, dostrzegłem czegoś, co mnie przeraziło. Otóż, jeśli w wygenerowanym przez Symfony adminie mamy klucze obce na liście, to wywoła on tyle zapytań ile elementów * ilość kluczy obcych.
Załóżmy, że mamy następujący schemat:
Kategoria: columns: nazwa: string(255) Produkt: columns: nazwa: string(255) kategoria_id: integer relations: kategoria: class: Kategoria
Natomiast w generator.yml mamy zdefiniowane:
generator: class: sfDoctrineAdminGenerator param: model_class: Produkt theme: default list: display: [nazwa,kategoria]
To w przypadku kategoria, generator będzie wywoływał zapytanie w stylu
select * from kategoria where id = ?
co przy domyślnych 20 rekordach na stronę i przykładowo 3 kluczach obcych wygeneruje ponad 60 zapytań. Tego prawdopodobnie nie chcemy.
Rozwiązaniem w tej sytuacji jest zastosowanie parametru peer_method (znanego mi jeszcze z czasów używania Propela), znajdujące się w sekcji list.
Występuje tu jednak kilka założeń, o których warto wiedzieć. Po pierwsze: metoda którą określamy w peer_method musi znajdować się w klasie wskazanej w model_class (w naszym przypadku Produkt) i nie może być to metoda statyczna. Po drugie: metoda ta musi zwracać instancję klasy Doctrine_Query. Po trzecie, metoda ta musi mieć zakończenie nazwy pod postacią TableProxy. Po czwarte (tu tkwi największy trick): w złączeniach DQL nie możemy używać własnych aliasów, tylko aliasować pełnymi nazwami klas.
Oto przykład:
plik /lib/model/doctrine/Produkt.class.php
class Produkt extends BaseProdukt { public function polaczZKategoriamiTableProxy() { return Doctrine_Query::create()->from('Produkt')->innerJoin('Produkt.kategoria'); //->from('Produkt p')->innerJoin('p.kategoria') jest błędne! } }
plik /apps/backend/modules/produkty/config/generator.yml
generator: class: sfDoctrineAdminGenerator param: model_class: Produkt theme: default list: peer_method: polaczZKategoriami display: [nazwa,kategoria]
Dzięki temu w znaczynym stopniu ograniczymy zapytania do bazy 🙂
edit: już wkrótce to rozwiązanie tego samego problemu dla Symfony 1.2 (tam niestety zrezygnowano z peer_method).