Zend_Db_Profiler
может быть включен
для профилирования запросов.
Профили включают в себя запросы, обработанные адаптером, а также
время, затраченное на обработку запроса. Это позволяет исследовать
выполненные запросы без добавления дополнительного отладочного
кода в классы. Расширенное использование также позволяет
разработчикам указывать, профилирование каких запросов
производить.
Включение профилировщика производится либо передачей директивы конструктору при создании адаптера, либо последующим обращением к адаптеру для включения.
<?php require_once 'Zend/Db.php'; $params = array( 'host' => '127.0.0.1', 'username' => 'webuser', 'password' => 'xxxxxxxx', 'dbname' => 'test' 'profiler' => true // включение профилировщика; // для отключения устанавливайте в false (значение по умолчанию) ); $db = Zend_Db::factory('PDO_MYSQL', $params); // отключение профилировщика: $db->getProfiler()->setEnabled(false); // включение профилировщика: $db->getProfiler()->setEnabled(true);
Значение опции 'profiler
' является гибким. Оно
интерпретируется по-разному в зависимости от его типа. В большинстве
случаев достаточно использовать простое булево значение, но с
помощью других типов можно управлять поведением профилировщика
Аргумент булевого типа включает профилировщик, если имеет значение
true
, и выключает его, если имеет значение
false
. По умолчанию адаптер использует класс
профилировщика Zend_Db_Profiler
.
$params['profiler'] = true; $db = Zend_Db::factory('PDO_MYSQL', $params);
Передача объекта профилировщика заставляет адаптер использовать его.
Объект должен принадлежать классу Zend_Db_Profiler
или
его производному.
$profiler = MyProject_Db_Profiler(); $profiler->setEnabled(true); $params['profiler'] = $profiler; $db = Zend_Db::factory('PDO_MYSQL', $params);
Аргумент может быть ассоциативным массивом, содержащим
ключи 'enabled
', 'instance
' и
'class
'. Ключи 'enabled
' и
'instance
' соответствуют булевому типу и объекту,
описанным выше. Ключ 'class
' используется для имени
класса профилировщика, который требуется установить. Класс должен
быть Zend_Db_Profiler
или его производным. Класс
инстанцируется конструктором без передачи аргументов. Опция
'class
' игнорируется, если установлена опция
'instance
'.
$params['profiler'] = array( 'enabled' => true, 'class' => 'MyProject_Db_Profiler' ); $db = Zend_Db::factory('PDO_MYSQL', $params);
И наконец, аргумент может быть объектом типа
Zend_Config
, содержащим свойства, аналогичные ключам
массива, описанного выше. К примеру, файл "config.ini" может
содержать следующие данные:
[main] db.profiler.class = "MyProject_Db_Profiler" db.profiler.enabled = true
Эта конфигурация может быть применена так, как показано в коде ниже:
$config = new Zend_Config_Ini('config.ini', 'main'); $params['profiler'] = $config->db->profiler; $db = Zend_Db::factory('PDO_MYSQL', $params);
Свойство 'instance
' может быть использовано следующим
образом:
$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);
Извлечение профилировщика производится в любой момент через
метод getProfiler()
адаптера:
<?php $profiler = $db->getProfiler();
Он вернет экземпляр класса Zend_Db_Profiler
.
С помощью этого экземпляра разработчик может изучать запросы,
используя различные методы:
getTotalNumQueries()
возвращает общее количество запросов, обработанных профилировщиком.getTotalElapsedSecs()
возвращает общее количество секунд, затраченное на все запросы, обработанные профилировщиком.getQueryProfiles()
возвращает массив всех профилей запросов.getLastQueryProfile()
возвращает последний созданный (самый недавний) профиль запроса, безотносительно того, был ли запрос завершен (если не был завершен, то конечное время будет равно null).clear()
удаляет все профили запросов из стека.
Возвращаемое getLastQueryProfile()
значение и
отдельные элементы getQueryProfiles()
являются
объектами Zend_Db_Profiler_Query
, которые дают
возможность исследовать запросы по отдельности:
getQuery()
возвращает SQL-текст запроса. SQL-текст подготовленного оператора с параметрами является текстом в то время, когда запрос подготавливается, поэтому он содержит метки заполнения, а не значения, используемые во время выполнения запроса.getQueryParams()
возвращает массив значений параметров, которые используются во время выполненения подготовленного запроса. Этот массив включает в себя как связанные параметры, так и аргументы для метода оператораexecute()
. Ключами массива являются позиционные (начинающиеся с 1) или именованные (строковые) индексы параметров.getElapsedSecs()
возвращает время выполнения запроса в секундах.
Информация, предоставляемая Zend_Db_Profiler
, полезна
для выявления "узких мест" в приложениях и отладки запросов.
Например, чтобы посмотреть, какой запрос выполнялся
последним:
<?php $query = $profiler->getLastQueryProfile(); echo $query->getQuery();
Возможно, страница генерируется медленно. Используйте профилировщик для того, чтобы сначала определить общее количество секунд для всех запросов, затем выполните обход всех запросов, чтобы найти тот, который выполняется дольше всех:
<?php $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 'Executed ' . $queryCount . ' queries in ' . $totalTime . ' seconds' . "\n"; echo 'Average query length: ' . $totalTime / $queryCount . ' seconds' . "\n"; echo 'Queries per second: ' . $queryCount / $totalTime . "\n"; echo 'Longest query length: ' . $longestTime . "\n"; echo "Longest query: \n" . $longestQuery . "\n";
Кроме исследования запросов, профилировщик также позволяет
фильтровать запросы, для которых
создаются профили. Следующие методы работают на экземпляре
Zend_Db_Profiler
:
setFilterElapsedSecs()
дает возможность
разработчику устанавливать минимальное время запроса, после
которого будет проводиться профилирование запросов.
Для того, чтобы убрать фильтрацию, передайте методу значение
null.
<?php // Профилировать только те запросы, которые отнимают по меньшей мере 5 секунд: $profiler->setFilterElapsedSecs(5); // Профилировать все запросы безотносительно времени выполнения: $profiler->setFilterElapsedSecs(null);
setFilterQueryType()
дает разработчику возможность
указывать, для каких типов запросов должны создаваться профили;
для обработки нескольких типов запросов используйте логическое
OR
. Типы запросов определены в следующих константах
Zend_Db_Profiler
:
Zend_Db_Profiler::CONNECT
: операции по установке соединения или выбора базы данных.Zend_Db_Profiler::QUERY
: общие запросы к базе данных, которые не соответствуют другим типам.Zend_Db_Profiler::INSERT
: любые запросы, через которые добавляются новые данные в базу данных, как правило, это команда INSERT.Zend_Db_Profiler::UPDATE
: любые запросы, которые обновляют существующие данные, обычно это команда UPDATE.Zend_Db_Profiler::DELETE
: любые запросы, которые удаляют существующие данные, обычно это команда DELETE.Zend_Db_Profiler::SELECT
: любые запросы, через которые извлекаются существующие данные, обычно это команда SELECT.Zend_Db_Profiler::TRANSACTION
: любые операции с транзакциями, такие, как начало транзакции, фиксация транзакции или откат.
Как и в случае setFilterElapsedSecs()
, вы можете
удалить все фильтры, передав null
в
качестве единственного аргумента.
<?php // профилирование только запросов SELECT $profiler->setFilterQueryType(Zend_Db_Profiler::SELECT); // профилирование запросов SELECT, INSERT и UPDATE $profiler->setFilterQueryType(Zend_Db_Profiler::SELECT | Zend_Db_Profiler::INSERT | Zend_Db_Profiler::UPDATE); // профилирование запросов DELETE (так мы можем определить, почему теряются данные) $profiler->setFilterQueryType(Zend_Db_Profiler::DELETE); // удалить все фильтры $profiler->setFilterQueryType(null);
Использование метода setFilterQueryType()
может
сократить количество генерируемых профилей. Тем не менее,
иногда может быть полезным хранить все профили, но просматривать
только те, которые нужны в данный момент. Другой метод
getQueryProfiles()
может производить
такую фильтрацию "на лету", ему передается тип запроса (или
логическая комбинация типов запросов) в качестве первого
аргумента; список констант типов запросов см.
Раздел 10.3.3.2, «Фильтрация по типу запроса».
<?php // Получение только профилей запросов SELECT $profiles = $profiler->getQueryProfiles(Zend_Db_Profiler::SELECT); // Получение только профилей запросов SELECT, INSERT и UPDATE $profiles = $profiler->getQueryProfiles(Zend_Db_Profiler::SELECT | Zend_Db_Profiler::INSERT | Zend_Db_Profiler::UPDATE); // Получение профилей запросов DELETE (так мы можем определить, почему теряются данные) $profiles = $profiler->getQueryProfiles(Zend_Db_Profiler::DELETE);