Главная / Zend Manual Core
Zend_Db_Statement

Zend_Db_Profiler

Введение

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

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

  1. $params = array(
  2.     'host'     => '127.0.0.1',
  3.     'username' => 'webuser',
  4.     'password' => 'xxxxxxxx',
  5.     'dbname'   => 'test'
  6.     'profiler' => true  // включение профилировщика;
  7.                         // для отключения устанавливайте в false
  8.                         // (значение по умолчанию)
  9. );
  10.  
  11. $db = Zend_Db::factory('PDO_MYSQL', $params);
  12.  
  13. // отключение профилировщика:
  14. $db->getProfiler()->setEnabled(false);
  15.  
  16. // включение профилировщика:
  17. $db->getProfiler()->setEnabled(true);

Значение опции 'profiler' является гибким. Оно интерпретируется по-разному в зависимости от его типа. В большинстве случаев достаточно использовать простое булево значение, но с помощью других типов можно управлять поведением профилировщика

Аргумент булевого типа включает профилировщик, если имеет значение TRUE, и выключает его, если имеет значение FALSE. По умолчанию адаптер использует класс профилировщика Zend_Db_Profiler.

  1. $params['profiler'] = true;
  2. $db = Zend_Db::factory('PDO_MYSQL', $params);

Передача объекта профилировщика заставляет адаптер использовать его. Объект должен принадлежать классу Zend_Db_Profiler или его производному.

  1. $profiler = MyProject_Db_Profiler();
  2. $profiler->setEnabled(true);
  3. $params['profiler'] = $profiler;
  4. $db = Zend_Db::factory('PDO_MYSQL', $params);

Аргумент может быть ассоциативным массивом, содержащим ключи 'enabled', 'instance' и 'class'. Ключи 'enabled' и 'instance' соответствуют булевому типу и объекту, описанным выше. Ключ 'class' используется для имени класса профилировщика, который требуется установить. Класс должен быть Zend_Db_Profiler или его производным. Класс инстанцируется конструктором без передачи аргументов. Опция 'class' игнорируется, если установлена опция 'instance'.

  1. $params['profiler'] = array(
  2.     'enabled' => true,
  3.     'class'   => 'MyProject_Db_Profiler'
  4. );
  5. $db = Zend_Db::factory('PDO_MYSQL', $params);

И наконец, аргумент может быть объектом типа Zend_Config, содержащим свойства, аналогичные ключам массива, описанного выше. К примеру, файл "config.ini" может содержать следующие данные:

  1. [main]
  2. db.profiler.class   = "MyProject_Db_Profiler"
  3. db.profiler.enabled = true
Эта конфигурация может быть применена так, как показано в коде ниже:
  1. $config = new Zend_Config_Ini('config.ini', 'main');
  2. $params['profiler'] = $config->db->profiler;
  3. $db = Zend_Db::factory('PDO_MYSQL', $params);
Свойство 'instance' может быть использовано следующим образом:
  1. $profiler = new MyProject_Db_Profiler();
  2. $profiler->setEnabled(true);
  3. $configData = array(
  4.     'instance' => $profiler
  5.     );
  6. $config = new Zend_Config($configData);
  7. $params['profiler'] = $config;
  8. $db = Zend_Db::factory('PDO_MYSQL', $params);

Использование профилировщика

Извлечение профилировщика производится в любой момент через метод getProfiler() адаптера:

  1. $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, полезна для выявления "узких мест" в приложениях и отладки запросов. Например, чтобы посмотреть, какой запрос выполнялся последним:

  1. $query = $profiler->getLastQueryProfile();
  2.  
  3. echo $query->getQuery();

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

  1. $totalTime    = $profiler->getTotalElapsedSecs();
  2. $queryCount   = $profiler->getTotalNumQueries();
  3. $longestTime  = 0;
  4. $longestQuery = null;
  5.  
  6. foreach ($profiler->getQueryProfiles() as $query) {
  7.     if ($query->getElapsedSecs() > $longestTime) {
  8.         $longestTime  = $query->getElapsedSecs();
  9.         $longestQuery = $query->getQuery();
  10.     }
  11. }
  12.  
  13. echo 'Executed ' . $queryCount . ' queries in ' . $totalTime .
  14.      ' seconds' . "\n";
  15. echo 'Average query length: ' . $totalTime / $queryCount .
  16.      ' seconds' . "\n";
  17. echo 'Queries per second: ' . $queryCount / $totalTime . "\n";
  18. echo 'Longest query length: ' . $longestTime . "\n";
  19. echo "Longest query: \n" . $longestQuery . "\n";

Расширенное использование профилировщика

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

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

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

  1. // Профилировать только те запросы, которые отнимают не менее 5 секунд:
  2. $profiler->setFilterElapsedSecs(5);
  3.  
  4. // Профилировать все запросы безотносительно времени выполнения:
  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 в качестве единственного аргумента.

  1. // профилирование только запросов SELECT
  2. $profiler->setFilterQueryType(Zend_Db_Profiler::SELECT);
  3.  
  4. // профилирование запросов SELECT, INSERT и UPDATE
  5. $profiler->setFilterQueryType(Zend_Db_Profiler::SELECT |
  6.                               Zend_Db_Profiler::INSERT |
  7.                               Zend_Db_Profiler::UPDATE);
  8.  
  9. // профилирование запросов DELETE
  10. $profiler->setFilterQueryType(Zend_Db_Profiler::DELETE);
  11.  
  12. // удалить все фильтры
  13. $profiler->setFilterQueryType(null);

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

Использование метода setFilterQueryType() может сократить количество генерируемых профилей. Тем не менее, иногда может быть полезным хранить все профили, но просматривать только те, которые нужны в данный момент. Другой метод getQueryProfiles() может производить такую фильтрацию "на лету", ему передается тип запроса (или логическая комбинация типов запросов) в качестве первого аргумента; список констант типов запросов см. Фильтрация по типу запроса.

  1. // Получение только профилей запросов SELECT
  2. $profiles = $profiler->getQueryProfiles(Zend_Db_Profiler::SELECT);
  3.  
  4. // Получение только профилей запросов SELECT, INSERT и UPDATE
  5. $profiles = $profiler->getQueryProfiles(Zend_Db_Profiler::SELECT |
  6.                                         Zend_Db_Profiler::INSERT |
  7.                                         Zend_Db_Profiler::UPDATE);
  8.  
  9. // Получение профилей запросов DELETE
  10. $profiles = $profiler->getQueryProfiles(Zend_Db_Profiler::DELETE);

Специализированные профилировщики

Специализированный профилировщик - это объект, который наследует от Zend_Db_Profiler. Специализированные профилировщики предназначены для специальной обработки данных профилирования.

Profiling with Firebug

Zend_Db_Profiler_Firebug sends profiling infomation to the » Firebug » Console.

All data is sent via the Zend_Wildfire_Channel_HttpHeaders component which uses HTTP headers to ensure the page content is not disturbed. Debugging AJAX requests that require clean JSON and XML responses is possible with this approach.

Requirements:

Example #1 DB Profiling with Zend_Controller_Front

  1. // In your bootstrap file
  2.  
  3. $profiler = new Zend_Db_Profiler_Firebug('All DB Queries');
  4. $profiler->setEnabled(true);
  5.  
  6. // Attach the profiler to your db adapter
  7. $db->setProfiler($profiler);
  8.  
  9. // Dispatch your front controller
  10.  
  11. // All DB queries in your model, view and controller
  12. // files will now be profiled and sent to Firebug

Example #2 DB Profiling without Zend_Controller_Front

  1. $profiler = new Zend_Db_Profiler_Firebug('All DB Queries');
  2. $profiler->setEnabled(true);
  3.  
  4. // Attach the profiler to your db adapter
  5. $db->setProfiler($profiler);
  6.  
  7. $request  = new Zend_Controller_Request_Http();
  8. $response = new Zend_Controller_Response_Http();
  9. $channel  = Zend_Wildfire_Channel_HttpHeaders::getInstance();
  10. $channel->setRequest($request);
  11. $channel->setResponse($response);
  12.  
  13. // Start output buffering
  14.  
  15. // Now you can run your DB queries to be profiled
  16.  
  17. // Flush profiling data to browser
  18. $channel->flush();
  19. $response->sendHeaders();

Zend_Db_Statement