Время выполнения SQL-запросов в debug информации и место их вызова
расширенная отладка SQL запросов в Joomla
рейтинг: 8.3/10, голосов: 7
Часто требуется узнать какие же SQL-запросы и как долго выполняются у нас на сайте, что за расширения дают нагрузку на базу данных, какие из них нужно удалить или оптимизировать.
Стандартная Joomla-отладка выдаёт только список выполненных SQL-запросов:
- SELECT *, RAND() AS ordering
FROM jos_banner
WHERE showBanner = 1
AND (imptotal = 0 OR impmade < imptotal)
AND cid = 1
AND catid = 33
ORDER BY sticky DESC, ordering
LIMIT 0, 1
- UPDATE jos_banner
SET impmade = impmade + 1
WHERE bid = 7
Эту ситуацию можно исправить, но придется использовать хак части ядра Joomla.
Добавим в debug информацию о времени выполнения каждого SQL-запроса и место вызова этого запроса. Для этого необходимо отредактировать файл
<корень сайта>/libraries/joomla/database/database/mysql.php : 206
либо для базы данных MySQLi
<корень сайта>/libraries/joomla/database/database/mysqli.php : 222
В оригинале функция выглядит примерно следующим образом:
/**
* Execute the query
*
* @access public
* @return mixed A database resource if successful, FALSE if not.
*/
function query()
{
if (!is_resource($this->_resource)) {
return false;
}
// Take a local copy so that we don't modify the original query and cause issues later
$sql = $this->_sql;
if ($this->_limit > 0 || $this->_offset > 0) {
$sql .= ' LIMIT ' . max($this->_offset, 0) . ', ' . max($this->_limit, 0);
}
if ($this->_debug) {
$this->_ticker++;
$this->_log[] = $sql;
}
$this->_errorNum = 0;
$this->_errorMsg = '';
$this->_cursor = mysql_query( $sql, $this->_resource );
if (!$this->_cursor)
{
$this->_errorNum = mysql_error( $this->_resource );
$this->_errorMsg = mysql_error( $this->_resource )." SQL=$sql";
if ($this->_debug) {
JError::raiseError(500, 'JDatabaseMySQL::query: '.$this->_errorNum.' - '.$this->_errorMsg );
}
return false;
}
return $this->_cursor;
}
Используя функцию debug_backtrace и стандартную функцию microtime() добавим необходимую нам информацию в
<?php
function query() {
if (!is_resource($this->_resource)) {
return false;
}
// Take a local copy so that we don't modify the original query and cause issues later
$sql = $this->_sql;
if ($this->_limit > 0 || $this->_offset > 0) {
$sql .= ' LIMIT '.$this->_offset.', '.$this->_limit;
}
$this->_errorNum = 0;
$this->_errorMsg = '';
if ($this->_debug) {
$sql_start = round(microtime(), 6);
};
$this->_cursor = mysql_query( $sql, $this->_resource );
if ($this->_debug) {
$sql_end = round(microtime(), 6);
$this->_ticker++;
$backtrace = debug_backtrace();
$bcktrc_add = '';
if (is_array($backtrace)) {
for ($i = 1; $i < 3; $i++) {
if (isset($backtrace[$i]) and is_array($backtrace[$i])) {
if (isset($backtrace[$i]['file']) and isset($backtrace[$i]['line'])) {
$bcktrc_add .= str_replace(JPATH_BASE, '', $backtrace[$i]['file']).':'.$backtrace[$i]['line']."\n";
}
}
}
}
$this->_log[] = $bcktrc_add.'Execute time:'.round(($sql_end - $sql_start), 6)." sec.\n".$sql;
}
if (!$this->_cursor) {
$this->_errorNum = mysql_error( $this->_resource );
$this->_errorMsg = mysql_error( $this->_resource )." SQL=$sql";
if ($this->_debug) {
JError::raiseError(500, 'JDatabaseMySQL::query: '.$this->_errorNum.' - '.$this->_errorMsg );
}
return false;
}
return $this->_cursor;
}
После данных изменений мы уже получим нужную нам информацию:
- /components/com_banners/models/banner.php:79
/modules/mod_banners/helper.php:39
Execute time:0.000818 sec.
SELECT *, RAND() AS ordering
FROM jos_banner
WHERE showBanner = 1
AND (imptotal = 0 OR impmade < imptotal)
AND cid = 1
AND catid = 33
ORDER BY sticky DESC, ordering
LIMIT 0, 1
- /modules/mod_banners/helper.php:40
/modules/mod_banners/mod_banners.php:23
Execute time:0.000117 sec.
UPDATE jos_banner
SET impmade = impmade + 1
WHERE bid = 7
Замечание: Иногда может потребоваться увеличить глубину вывода точек вызова функций (например Community Builder создаёт свой класс для работы с базой данных, поэтому потребуется заглянуть поглубже), для этого в нашей новой функции в строчке
for ($i = 1; $i < 3; $i++) {
цифру "3" увеличиваем например до "6", тогда будет выведено "5" ("6"-1) точек вызова.