30
Сен
Отладка и оптимизация SQL запросов в NetCat
Категории: CMS NetCat создание сайта | Комментарии (1)В CMS NetCat (как и в любой другой CMS) за вас уже все продумали програмисты и вам остается только пользоватся готовыми решениями и специалными документированными функциями. Например, если вам нужно вывести последние новости в какой-то части сайта, то вы просто вставляете в макет фунцию ".s_list_class(xx,yy,"recNum=zz").", указывете из какого раздела брать новости (xx), номер компенента в разделе (yy) и кол-во выводимых новостей (zz) и все готово. Таким образом можно вывести любую информацию из любого раздела. Но за универсальностью скрывается повышеная нагрузка на систему.
Для вывода этого блока новостей функцией s_list_class() требуется выполнить 3 sql запроса: получение шаблона для вывода новостей, получение полей в таблице новостей и выборка самих новостей. Если у новостей есть поля типа файл, куда можно загрузить картинку, то прибавляется еще по одному запросу на каждое поле. Если на странице набирается несколько таких блоков (контакты, популярные товары, корзина и тп) то по нагрузке получается как будто вы открывете страницу 2-3 раза. При знании языка запросов SQL подобный вывод можно сделать одним запросом, тк мы уже знаем какие поля нужно выбирать и напишем шаблон по которому нужно выводть результат запроса. В связи с этим было бы неплохо знать какие запросы выполняются в системе и за какое время. Для этого в системе есть специальный функцонал
в файле /netcat/require/e404.php нужно раскомментировать строки
/*
///////////////////////
require("Benchmark/Timer.php");
$nccttimer = new Benchmark_Timer();
$nccttimer->start();
///////////////////////
$db->debug_all = true;
$db->benchmark = true;
///////////////////////////////////
*/
после чего вам будет показан каждый запрос, результат его выполнения и время выполнения запроса. Но на мой взгляд это очень не удобо тк каждый запрос выводится в том месте хтмл где он непосредственно выполняется и нет возможности как-то настроить вывод. Поэтому я использую свое решение.
Для подсчета времени выполнения запроса и сохранения списка запросов делаем следующие изменения в файле /netcat/sql_mysql.php:
//засекаем время перед выполнением запроса
$microtime=explode(' ',microtime());
$start=$microtime[1].substr($microtime[0],1);
// Perform the query via std mysql_query function..
$this->result = @mysql_query($query,$this->dbh);
$this->num_queries++;
//и после его выполнения
$microtime=explode(' ',microtime());
$stop=$microtime[1].substr($microtime[0],1);
В предыдущем посте про неткат мы создавали ключ по которому нам будет отображаться отладочная информация. Тут мы тоже его используем. Далее добавляем такой код:
if($_COOKIE['debugkey'])
{
// следующие 3 строки показывают путь откуда был выполнен запрос
if($GLOBALS['backtrace'])
{
$bt=debug_backtrace();
$caller="\n";
foreach($bt as $trace) $caller.=$trace['file'].":".$trace['line'].":".$trace['function']."()\n";
}
// считаем общее время выполнения sql запросов
$this->sql_time+=$stop-$start;
// записываем запрос в массив с указанием номера и временем выполнения
$this->q[sprintf("%02d",$this->num_queries)." ".sprintf("%0.4lf",$stop-$start)]=preg_replace("/\s+/s"," ",$query).$caller;
}
Если у нас установлен специалный ключ, то будет собираться история sql запросов и время их выполнеия в массив $db->q, в переменной $db->sql_time будет время выполнения всех sql запросов.
Также в этом файле необходимо сделать запись в файл, sql запросов, в которых произошла ошибка.В этом случае если у пользователя возникнет ошибка, то мы будем знать в каком месте она произошла и по каким причинам.
// If there is an error then take note of it..
if ( $str = @mysql_error($this->dbh) )
{
$bt=debug_backtrace();
$caller="\n";
foreach($bt as $trace) $caller.="\t\t".$trace['file'].":".$trace['line'].":".$trace['function']."()\n";
$fo=@fopen($GLOBALS['sql_error_log'],"a");
$msg=date("Y-m-d H:i:s")." $_SERVER[REMOTE_ADDR] $_SERVER[REQUEST_URI]\n";
$msg.="\t$query\n\t\t$str\n";
$msg.=$caller;
@fwrite($fo,$msg);
@fclose($fo);
$this->register_error($str);
$this->show_errors ? trigger_error($str,E_USER_WARNING) : null;
return false;
}
Теперь нам нужно сделать вывод этой информации, добавим общее время создания страницы и определим путь для сохранения sql лога. В файл vars.inc.php добавляем следующий код:
// засекаем время запуска скрипта
$microtime=explode(' ',microtime());
$GLOBALS['start']=$microtime[1].substr($microtime[0],1);
// регистрируем функцию которая будет выполнена при завершении работы скрипта
if($_COOKIE['debugkey']) register_shutdown_function("shutdown");
// создаем эту функцию которая будет выводить нужную нам информацию
function shutdown()
{
global $db;
$microtime=explode(' ',microtime());
$stop=$microtime[1].substr($microtime[0],1);
echo "<center>Page generated in ";
echo "".sprintf("%0.4lf",$stop-$GLOBALS['start'])." seconds";
echo " with ".$db->num_queries." queries (".sprintf("%0.4lf",$db->sql_time)." seconds of sql) ";
echo "Memory usage: ".round(memory_get_usage()/1024)." Kb</center>";
echo "<pre>";
print_r($db->q);
}
В результате внизу страницы мы получим следующие данные:
Page generated in 0.2001 seconds with 143 queries (0.0664 seconds of sql) Memory usage: 1327 Kb
Из-за большого кол-ва блоков на главной странице демо макета NetCat Extra мы имеем 143 запроса к bd, что очень много...
--
Стальные двери компании Сезам защитят вашу квартиру от взлома также, как следующий пост защитит от взлома старые версии NetCat.
Кеширование динамических блоков в NetCat | Блогнот, 2008-10-16 @ 06:36
[...] спобов вывода таких блоков - функция s_list_class, но как я уже писал, она слишком ресуркоемкая для простых операций. [...]