Yii 提供了一个设置,用每个 SQL 调用的执行时间(CProfileLogRoute)来描述所有的 SQL 调用。除非它不适用于 ajax 调用。我怎样才能访问这些数据?
我试图找到打开登录弹出窗口的 ajax 调用的瓶颈......
类似地,CProfileLogRoute 中显示的执行时间是否包括到 SQL 服务器的网络行程(如果有)?我的数据库由亚马逊的 RDS 托管,我想知道这是否是瓶颈所在(在本地似乎很好)。
Yii 提供了一个设置,用每个 SQL 调用的执行时间(CProfileLogRoute)来描述所有的 SQL 调用。除非它不适用于 ajax 调用。我怎样才能访问这些数据?
我试图找到打开登录弹出窗口的 ajax 调用的瓶颈......
类似地,CProfileLogRoute 中显示的执行时间是否包括到 SQL 服务器的网络行程(如果有)?我的数据库由亚马逊的 RDS 托管,我想知道这是否是瓶颈所在(在本地似乎很好)。
您可以尝试以下面建议的方式扩展CFileLogRoute并在应用程序的配置中启用它,如下所示:
'log'=>array(
'class'=>'CLogRouter',
'routes'=>array(
array(
'class'=>'ProfileLogRoute',
'levels' => "profile"
)
)
)
在这种情况下,所有已分析的查询都将写入位于protected/runtime
目录中的日志文件(方法的覆盖同样实现CProfileWebRouteprocessLogs
的摘要报告......不幸的是来自CWebLogRoute):CProfileWebRoute
<?php
class ProfileLogRoute extends CFileLogRoute
{
protected function processLogs($logs)
{
$logFile=$this->getLogPath().DIRECTORY_SEPARATOR.$this->getLogFile();
if(@filesize($logFile)>$this->getMaxFileSize()*1024)
$this->rotateFiles();
$fp=@fopen($logFile,'a');
@flock($fp,LOCK_EX);
$profileStack = array();
$profileResults = array();
foreach ($logs as $log)
{
if ($log[1] === CLogger::LEVEL_PROFILE)
{
$message = $log[0];
if (!strncasecmp($message, 'begin:', 6))
{
$log[0] = substr($message,6);
$profileStack[] = $log;
}
else if(!strncasecmp($message, 'end:', 4))
{
$token = substr($message,4);
if(($last = array_pop($profileStack)) !== null && $last[0] === $token)
{
$info = array(
'delta' => $log[3] - $last[3],
'category' => $last[2],
'time' => $last[3]
);
$this->aggregateResult($token, $info, $profileResults);
}
else
{
throw new CException(Yii::t('yii','CProfileLogRoute found a mismatching code block "{token}". Make sure the calls to Yii::beginProfile() and Yii::endProfile() be properly nested.',
array('{token}'=>$token)));
}
}
}
else
{
@fwrite($fp,$this->formatLogMessage($log[0],$log[1],$log[2],$log[3]));
}
}
if (!empty($profileResults))
{
$now = microtime(true);
while(($last = array_pop($profileStack)) !== null)
{
$info = array(
'delta' => $now - $last[3],
'category' => $last[2],
'time' => $last[3]
);
$token = $last[0];
$this->aggregateResult($token, $info, $profileResults);
}
$entries = array_values($profileResults);
$func = create_function('$a,$b','return $a["total"]<$b["total"]?1:0;');
usort($entries, $func);
foreach ($entries as $entry)
{
$message = sprintf("Min: % 11.8f Max: % 11.8f Total: % 11.8f Calls: % 3d %s", $entry['min'], $entry['max'], $entry['total'], $entry['calls'], $entry['token']);
@fwrite($fp, $this->formatLogMessage($message, CLogger::LEVEL_PROFILE, $entry['category'], $entry['time']));
}
}
@flock($fp,LOCK_UN);
@fclose($fp);
}
protected function aggregateResult($token, $info, &$results)
{
if (isset($results[$token]))
{
if ($info['delta'] < $results[$token]['min'])
$results[$token]['min'] = $info['delta'];
else if($info['delta'] > $results[$token]['max'])
$results[$token]['max'] = $info['delta'];
$results[$token]['calls']++;
$results[$token]['total'] += $info['delta'];
return;
}
$results[$token] = array(
'token' => $token,
'calls' => 1,
'min' => $info['delta'],
'max' => $info['delta'],
'total' => $info['delta'],
'category' => $info['category'],
'time' => $info['time']
);
}
}
如果你想知道 Yii 是如何测量 SQL 执行时间的,你可以查看CDbCommand类的源代码 -queryInternal
方法,更准确地说。分析介于Yii::beginProfile('system.db.CDbCommand.query...')
和Yii::endProfile('system.db.CDbCommand.query...')
调用之间。正如您所看到的,这两个调用都在同一个方法中,因此分析时间不包括网络传输。问题可能在于您的远程数据库服务器在巨大的负载下运行。
There is a property of the CProfileLogRoute class called ignoreAjaxInFireBug which defaults to "true" by setting it to false you can get your profiling info on ajax requests.
http://www.yiiframework.com/doc/api/1.1/CWebLogRoute#ignoreAjaxInFireBug-detail
'log'=>array(
'class'=>'CLogRouter',
'routes'=>array(
array(
'class'=>'CProfileLogRoute',
'ignoreAjaxInFireBug'=>false,
'levels'=>'error, warning, trace, info, profile',
),
),
I don't believe ou need to use firebug for that work (it's kind of a misnomer). If you do however, just download firefox and install firebug and then your problem is still solved.