Szybkie serwisy, zoptymalizowane pod względem zużycia pamięci i ilości odwołań do bazy – czasami mogą być kluczowym elementem w powodzeniu naszego projektu. Chciałbym przedstawić jedną z takich możliwości, czyli użycie w Symfony widoków baz danych. Przykład można zastosować w bazach: PostgreSQL, MySQL, Oracle, itd. Najważniejszym elementem jest to, czy baza danych obsługuje widoki.
Dla przykładu użyję tabeli użytkownik i grupa.
schema.yml
propel:
groups:
id: { type: integer, required: true, primaryKey: true, autoincrement: true }
owner_id: { type: integer, foreignTable: users, foreignReference: id, index: true }
last_user_id: { type: integer, foreignTable: users, foreignReference: id, index: true }
name: { type: varchar, size: 80, index: true }
routing_name: { type: varchar, size: 80, index: true, uniq: true }
description: { type: varchar, size: 400 }
created_at: { type: timestamp }
user_count: { type: integer, index: true }
position_rank: { type: integer }
users:
id: { type: integer, required: true, primaryKey: true, autoincrement: true }
login: { type: varchar, size: 15, index: true, uniq: true }
password: { type: varchar, size: 255 }
name: { type: varchar, size: 255 }
created_at: { type: timestamp }
updated_at: { type: timestamp }
last_login_at: { type: timestamp }
last_request_at: { type: timestamp }
group_id: { type: integer, foreignTable: groups, foreignReference: id, index: true }
Załóżmy, że mamy template w którym pokazujemy 20 grup według ilości użytkowników, w której wyświetlamy: nazwę grupy wraz z linkiem do profilu grupy, właściciela grupy, ostatniego dodanego użytkownika do tej grupy i ilość użytkowników w grupie. Stosując klasyczne wykorzystanie modelów Propela, dostaniemy modele grup z zależnymi 2 modelami użytkowników – właściciel i ostatnio dodany użytkownik. Od razu widać że większość danych jest zbędna, a co z tym idzie wykorzystanie pamięci będzie większe i czas zwracania danych z bazy będzie dłuższy.
Definiowanie widoku (views) w schema
Aby rozdzielić pliki w którym są definicje tabel i widoki, warto utworzyć osobny plik w którym zapiszemy naszą definicje widoku.
config/views_schema.yml
propel:
groups_view:
_attributes: { skipSQL: true, readOnly: true }
id: { type: integer }
name: { type: varchar }
routing_name: { type: varchar }
user_count: { type: integer }
owner_name: { type: varchar }
last_user: { type: varchar }
Kolejnym krokiem jest przygotowanie SQL z definicją naszego vidoku. Dobrym rozwiązaniem jest by każdy widok umieszczać w osobnym pliku i dodawać do sqldb.map, w celu zbudowania widoku z automatu (nie musimy już ręcznie wywoływać SQL).
Tworzymy plik sql
data/sql/views/groups_view.sql
CREATE OR REPLACE VIEW groups_view AS
SELECT groups.id,
groups.name ,
groups.routing_name,
groups.user_count,
owner.login AS owner_name,
last.login AS last_user
FROM groups
JOIN users owner ON owner.id = groups.owner_id
JOIN users last ON last.id = groups.ast_user_id;
Dodajemy widok do sqldb.map
Edytujemy plik sqldb.map i dodajemy nową pozycję
data/sql/sdldb.map
views/groups_view.sql=propel
Kolejnym krokiem jest zbudowanie bazy danych, dla przykładu użyje polecenia, które tworzy modele, dodaje SQL do bazy i wczytuje przykładowe dane.
./symfony propel:build-all-load
Po wygenerowanie powstał model o nazwie GroupsView, teraz tylko nam zostaje dodanie metody, która będzie zwracać 20 grup z największą ilością użytkowników.
Edytujemy GroupsViewPeer.class.php
Dodajemy metodę
public static function getTopGroups( $limit = 20 )
{
$c = new Criteria();
$c->addDescendingOrderByColumn( GroupsViewPeer::USER_COUNT );
$c->setLimit( $limit );
return GroupsViewPeer::doSelect( $c );
}
Metoda ta zwraca 20 obiektów, w których mamy tylko i wyłącznie pola, które będą nam potrzebne do wyświetlenia.
Często na rożnych forach spotyka się opinie, że Symfony jest wolnym i zasobożernym frameworkiem, jeśli nie znamy możliwości, zasad jego działania jak i sposobów optymalizacji to niestety ale taka teoria dla pewnych osób jest prawdziwa. Wykorzystując możliwości baz, takie jak plsql, vidoki, triggery i funkcje można osiągnąć rewelacyjne efekty i obsługa milionowych tabel na “słabym” sprzęcie jest czymś realnym.