5.2. Zend_Db_Profiler

5.2.1. Введение

Zend_Db_Profiler может быть включен для для того, чтобы сделать возможным профайлинг запросов. Профaйлы включают в себя запросы, обработанные адаптером, а также время, затраченное на обработку запроса. Это позволяет исследовать выполненные запросы без добавления дополнительного отладочного кода в классы. Расширенное использование также позволяет разработчикам указывать, для каких запросов создавать профайлы.

Включение профайлера производится либо передачей директивы конструктору адаптера, либо более поздним обращением к адаптеру для включения.

<?php
require_once 'Zend/Db.php';

$params = array (
    'host'     => '127.0.0.1',
    'username' => 'malory',
    'password' => '******',
    'dbname'   => 'camelot',
    'profiler' => true  // включение профайлера;
                        // для отключения используется false (значение по умолчанию)
);

$db = Zend_Db::factory('PDO_MYSQL', $params);

// отключение профайлера:
$db->getProfiler()->setEnabled(false);

// включение профайлера:
$db->getProfiler()->setEnabled(true);
?>

5.2.2. Использование профайлера

Получение профайлера производится в любой момент с помощью метода getProfiler() в адаптере БД:

<?php
$profiler = $db->getProfiler();
?>

Это вернет экземпляр класса Zend_Db_Profiler. С помощью этого экземпляра разработчик может изучать запросы, используя различные методы:

  • getTotalNumQueries() возвращает общее количество запросов, которые были обработаны профайлером.
  • getTotalElapsedSeconds() возвращает общее количество секунд, затраченное на все запросы, обработанные профайлером.
  • getQueryProfiles() возвращает массив всех профайлов запросов.
  • getLastQueryProfile() возвращает последний (самый недавний) профайл запроса, безотносительно того, был ли запрос завершен (Если не был завершен, то конечное время будет равно NULL).
  • clear() удаляет все профайлы прошлых запросов из стека.

Возвращаемое getLastQueryProfile() значение и отдельные элементы getQueryProfiles() являются объектами Zend_Db_Profiler_Query, которые дают возможность исследовать отдельные запросы:

  • getQuery() возвращает код SQL-запроса.
  • getElapsedSecs() возвращает время выполнения запроса в секундах.

Информация, предоставляемая Zend_Db_Profiler, полезна для выявления "узких мест" в приложениях и отладки запросов. Например, чтобы посмотреть, какой запрос выполнялся последним:

<?php
$query = $profiler->getLastQueryProfile();

echo $query->getQuery();
?>

Возможно, страница генерируется медленно. Используйте профайлер для того, чтобя сначала определить общее количество секунд для всех запросов, затем выполните обход всех запросов, чтобы найти тот, который выполняется дольше всех:

<?php
$totalTime    = $profiler->gettotalElapsedSeconds();
$queryCount   = $profiler->getTotalNumQueries();
$longestTime  = 0;
$longestQuery = null;

foreach ($profiler->getQueryProfiles() as $query) {
    if ($query->getElapsedSecs() > $longestTime) {
        $longestTime  = $query->getElapsedSecs();
        $longestQuery = $query->getQuery();
    }
}

echo 'Выполнено ' . $queryCount . ' запросов в ' . $totalTime . ' секунд' . "\n";
echo 'Среднее время выполнения запроса: ' . $queryCount / $totalTime . ' секунд' . "\n";
echo 'Наибольшее время выполнения запроса: ' . $longestTime . "\n";
echo "Запрос с наибольшим временем выполнения: \n" . $longestQuery . "\n";
?>

5.2.3. Расширенное использование профайлера

Кроме исследования запросов, профайлер также дает возможность разработчику фильтровать запросы, для которых создаются профайлы. Следующие методы работают на экземпляре Zend_Db_Profiler:

5.2.3.1. Фильтрация по времени выполнения запроса

setFilterElapsedSecs() дает возможность разработчику устанавливать минимальное время запроса, после которого будет проводиться профайлиг запросов. Для того, чтобы убрать фильтрацию, передайте методу значение NULL.

<?php
// Проводить профайлинг только тех запросы, которые отнимают по меньшей мере 5 секунд:
$profiler->setFilterElapsedSecs(5);

// Профайлировать все запросы безотносительно времени выполнения:
$profiler->setFilterElapsedSecs(null);
?>

5.2.3.2. Фильтрация по типу запроса

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);
?>

5.2.3.3. Получение профайлов по типу запроса

Использование setFilterQueryType() может сократить количество генерируемых профайлов. Тем не менее, иногда может быть полезным хранить все профайлы, но просматривать только те, которые нужны в данный момент. Другой метод getQueryProfiles() -- это то, что может делать такую фильтрацию "на лету", ему передается тип запроса (или логическая комбинация типов запросов) в качестве его первого аргумента; список констант типов запросов см. Раздел 5.2.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);
?>