Zend_Db_Profiler
może być włączony aby pozwolić na
profilowanie zapytań. Profilowanie umożliwia zbadanie czasu trwania
zapytań pozwalając na inspekcję przeprowadzonych zapytań bez potrzeby
dodawania nadmiarowego kodu do klas. Zaawansowane użycie pozwala także
programiście decydować o tym, jakich typów zapytania mają być profilowane.
Włącz profiler przekazując odpowiednią dyrektywę do konstruktora adaptera lub wywołując później metodę adaptera.
$params = array ( 'host' => '127.0.0.1', 'username' => 'webuser', 'password' => 'xxxxxxxx', 'dbname' => 'test', 'profiler' => true // włącz profiler; ustaw false aby wyłączyć (domyślne wyłączony) ); $db = Zend_Db::factory('PDO_MYSQL', $params); // wyłącz profiler: $db->getProfiler()->setEnabled(false); // włącz profiler: $db->getProfiler()->setEnabled(true);
Wartość opcji 'profiler
' jest dość elastyczna. Jest
ona interpretowana zależnie id jej typu. W większości przypadków
powinieneś użyć wartości logicznej, ale inne typy pozwalają na
dostosowanie zachowania profilera do własnych potrzeb.
Parametr logiczny włącza profiler jeśli ma wartość
TRUE
lub wyłącza jeśli ma wartość FALSE
.
Klasą profilera domyślnie jest klasa Zend_Db_Profiler
.
$params['profiler'] = true; $db = Zend_Db::factory('PDO_MYSQL', $params);
Przekazanie instancji obiektu profilera powoduje jej użycie przez
adapter bazy danych. Musi to być obiekt klasy
Zend_Db_Profiler
lub klasy ją rozszerzającej. Aktywacja
profilera odbywa się osobno.
$profiler = MyProject_Db_Profiler(); $profiler->setEnabled(true); $params['profiler'] = $profiler; $db = Zend_Db::factory('PDO_MYSQL', $params);
Argument może być tablicą asocjacyjną zawierającą wszystkie lub
jeden z kluczy 'enabled
', 'instance
', oraz
'class
'. Klucz 'enabled
' odpowiada wartości
logicznej, a 'instance
' wartości instancji, obie są
opisane powyżej. Klucz 'class
' jest używany do podania
nazwy klasy jaka ma być użyta we własnym profilerze. Musi być to
obiekt klasy Zend_Db_Profiler
lub klasy ją rozszerzającej.
Instancja klasy jest tworzona bez żadnych argumentów. Opcja
'class
' jest ingorowana jeśli podana jest opcja
'instance
'.
$params['profiler'] = array( 'enabled' => true, 'class' => 'MyProject_Db_Profiler' ); $db = Zend_Db::factory('PDO_MYSQL', $params);
Ostatecznie, argument może być obiektem klasy Zend_Config
zawierającym właściwości, które są traktowane jako klucze tablicy
opisane powyżej. Przykładowo plik "config.ini" może zawierać
następujące dane:
[main] db.profiler.class = "MyProject_Db_Profiler" db.profiler.enabled = true
Konfiguracja może być przekazana za pomocą takiego kodu PHP:
$config = new Zend_Config_Ini('config.ini', 'main'); $params['profiler'] = $config->db->profiler; $db = Zend_Db::factory('PDO_MYSQL', $params);
Właściwość 'instance
' może być użyta w następujący sposób:
$profiler = new MyProject_Db_Profiler(); $profiler->setEnabled(true); $configData = array( 'instance' => $profiler ); $config = new Zend_Config($configData); $params['profiler'] = $config; $db = Zend_Db::factory('PDO_MYSQL', $params);
W dowolnym momencie możesz pobrać profiler używając metody
adaptera getProfiler()
:
$profiler = $db->getProfiler();
Zwraca to instancję Zend_Db_Profiler
. Używając tej
instancji programista może zbadać zapytania używając rozmaitych
metod:
-
getTotalNumQueries()
zwraca liczbę wszystkich zapytań które były profilowane. -
getTotalElapsedSecs()
zwraca całkowity czas trwania profilowanych zapytań. -
getQueryProfiles()
zwraca tablicę wszystkich profilów zapytań. -
getLastQueryProfile()
zwraca ostatni (najnowszy) profil zapytania, niezależnie od tego czy zostało ono zakończone czy nie (jeśli nie zostało, to czas zakończenia będzie miał wartośćNULL
) -
clear()
czyści wszystkie poprzednie profile zapytań ze stosu.
Wartość zwracana przez getLastQueryProfile()
oraz
pojedyncze elementy tablicy zwracanej przez getQueryProfiles()
są obiektami Zend_Db_Profiler_Query
, które dają możliwość
sprawdzenia osobno każdego zapytania.
-
Metoda
getQuery()
zwraca tekst SQL zapytania. Tekst przygotowanego zapytania SQL z parametrami jest tekstem w takiej postaci w jakiej był on przygotowany, więc zawiera on etykiety, a nie wartości użyte podczas wykonania zapytania. -
Metoda
getQueryParams()
zwraca tablicę wartości parametrów użytych podczas wykonania przygotowanego zapytania. Odnosi się to do parametrów oraz do argumentów metodyexecute()
. Klucze tablicy są oparte na pozycji (od 1 w górę) lub nazwane (łańcuchy znaków). -
Metoda
getElapsedSecs()
zwraca czas trwania zapytania
Informacja której dostarcza Zend_Db_Profiler
jest
użyteczna przy profilowaniu wąskich gardeł w aplikacjach oraz
do szukania błędów w wykonanych zapytaniach. Na przykład aby
zobaczyć ostatnie zapytanie jakie było wykonane:
$query = $profiler->getLastQueryProfile(); echo $query->getQuery();
Możliwe, że strona generuje się powoli; użyj profilera aby ustalić czas wykonania wszystkich zapytań, a następnie przejść poprzez zapytania aby znaleść te, które trwało najdłużej:
$totalTime = $profiler->getTotalElapsedSecs(); $queryCount = $profiler->getTotalNumQueries(); $longestTime = 0; $longestQuery = null; foreach ($profiler->getQueryProfiles() as $query) { if ($query->getElapsedSecs() > $longestTime) { $longestTime = $query->getElapsedSecs(); $longestQuery = $query->getQuery(); } } echo 'Wykonano ' . $queryCount . ' zapytań w czasie ' . $totalTime . ' sekund' . "\n"; echo 'Średni czas trwania zapytania: ' . $totalTime / $queryCount . ' sekund' . "\n"; echo 'Zapytań na sekundę:: ' . $queryCount / $totalTime . "\n"; echo 'Czas trwania najdłuższego zapytania: ' . $longestTime . "\n"; echo "Najdłuższe zapytanie: \n" . $longestQuery . "\n";
Oprócz sprawdzania zapytań, profiler pozwala także programiście na
określenie typów zapytań które mają być profilowane. Poniższe
metody operują na instancji Zend_Db_Profiler
:
setFilterElapsedSecs()
pozwala programiście ustalić
minimalny czas trwania zapytania jaki jest potrzebny do tego by
zostało ono profilowane. Aby usunąć filtr, wywołaj metodę z
wartością null w parametrze.
// Profiluj tylko zapytania które trwają przynajmniej 5 sekund: $profiler->setFilterElapsedSecs(5); // Profiluj wszystkie zapytania, niezależnie od czasu ich trwania: $profiler->setFilterElapsedSecs(null);
setFilterQueryType()
pozwala programiście określić,
które typy zapytań powinny być profilowane; aby profilować
zapytania wielu typów użyj logicznego operatora OR. Typy zapytań
są zdefiniowane jako stałe w Zend_Db_Profiler
:
-
Zend_Db_Profiler::CONNECT
: operacje połączenia lub wybierania bazy danych. -
Zend_Db_Profiler::QUERY
: ogólne zapytania które nie pasują do pozostałych typów. -
Zend_Db_Profiler::INSERT
: każde zapytanie które wstawia nowe dane do bazy, generalnie SQL INSERT. -
Zend_Db_Profiler::UPDATE
: każde zapytanie ktore uaktualnia dane w bazie, najczęściej SQL UPDATE. -
Zend_Db_Profiler::DELETE
: każde zapytanie które usuwa istnięjące dane, najczęściej SQL DELETE. -
Zend_Db_Profiler::SELECT
: każde zapytanie które pobiera istnięjące dane, najczęściej SQL SELECT. -
Zend_Db_Profiler::TRANSACTION
: każda operacja transakcyjna, taka jak start transakcji, potwierdzenie zmian czy ich cofnięcie.
Analogicznie jak w metodzie setFilterElapsedSecs()
,
możesz usunąć wszystkie istniejące filtry przekazując metodzie
pusty parametr null
.
// profiluj tylko zapytania SELECT $profiler->setFilterQueryType(Zend_Db_Profiler::SELECT); // profiluj zapytania SELECT, INSERT, oraz UPDATE $profiler->setFilterQueryType(Zend_Db_Profiler::SELECT | Zend_Db_Profiler::INSERT | Zend_Db_Profiler::UPDATE); // profiluj zapytania DELETE $profiler->setFilterQueryType(Zend_Db_Profiler::DELETE); // Usuń wszystkie filtry $profiler->setFilterQueryType(null);
Użycie metody setFilterQueryType()
może zmniejszyć
ilość wygenerowanych profili. Jakkolwiek, czasem bardziej użyteczne
jest przechowywanie wszystkich profili i wyświetlanie tylko
tych których potrzebujesz w danym momencie. Inną funkcjonalnością
metody getQueryProfiles()
jest to, że może ona
przeprowadzić te filtrowanie w locie, po przekazaniu typu
zapytań (lub logicznej kombinacji typów zapytań) jako pierwszego
argumentu; przejdź do „Filtrowanie ze względu na typ zapytania”
aby zobaczyć listę stałych określających typy zapytań.
// Pobierz jedynie profile zapytań SELECT $profiles = $profiler->getQueryProfiles(Zend_Db_Profiler::SELECT); // Pobierz jedynie profile zapytań SELECT, INSERT, oraz UPDATE $profiles = $profiler->getQueryProfiles(Zend_Db_Profiler::SELECT | Zend_Db_Profiler::INSERT | Zend_Db_Profiler::UPDATE); // Pobierz jedynie profile zapytań DELETE $profiles = $profiler->getQueryProfiles(Zend_Db_Profiler::DELETE);
Wyspecjalizowany profiler jest obiektem klasy dziedziczącej po
klasie Zend_Db_Profiler
. Wyspecjalizowane profilery
traktują profilowane informacje w szczególny sposób.
Zend_Db_Profiler_Firebug
przesyła informacje dotyczące
sesji profilera do konsoli
Firebug.
Wszelkie dane przesyłane są za pomocą komponentu
Zend_Wildfire_Channel_HttpHeaders
używającego nagłówków
HTTP co powoduje, iż zawartość strony pozostaje niezmieniona.
Dzięki temu również, możliwe jest debugowanie żądań AJAX wymagających
czystych notacji JSON oraz XML.
Wymagania:
-
Przeglądarka Firefox co najmniej w wersji 2.0
-
Rozszerzenie Firebug, które można pobrać z https://addons.mozilla.org/en-US/firefox/addon/1843.
-
Rozszerzenie FirePHP, które można pobrać z https://addons.mozilla.org/en-US/firefox/addon/6149.
Przykład 230. Profilowanie zapytań do bazy danych z użyciem Zend_Controller_Front
// W pliku bootstrap $profiler = new Zend_Db_Profiler_Firebug('All DB Queries'); $profiler->setEnabled(true); // Połącz profiler z adapterem bazy danych $db->setProfiler($profiler); // Uruchom front kontroler // Wszystkie zapytania w modelach, widokach i kontrolerach // będą teraz profilowane a dane - wysłane do Firebuga
Przykład 231. Profilowanie zapytań do bazy danych bez użycia Zend_Controller_Front
$profiler = new Zend_Db_Profiler_Firebug('All DB Queries'); $profiler->setEnabled(true); // Połącz profiler z adapterem bazy danych $db->setProfiler($profiler); $request = new Zend_Controller_Request_Http(); $response = new Zend_Controller_Response_Http(); $channel = Zend_Wildfire_Channel_HttpHeaders::getInstance(); $channel->setRequest($request); $channel->setResponse($response); // Rozpocznij buforowanie wyjścia ob_start(); // Teraz można profilować zapytania // Zrzucenie danych profilera do przeglądarki $channel->flush(); $response->sendHeaders();