5

Yii は、すべての SQL 呼び出しをそれぞれの実行時間でプロファイリングする設定を提供します (CProfileLogRoute)。ただし、ajax 呼び出しでは機能しません。このデータにアクセスするにはどうすればよいですか?

ログインポップアップを開くajax呼び出しのボトルネックを見つけようとしています...

同様に、CProfileLogRoute に表示される実行時間には、SQL サーバーへのネットワーク トリップが含まれていますか? 私のデータベースは Amazon の RDS によってホストされています。ボトルネックがどこにあるかを知りたいです (ローカルでは問題ないようです)。

4

2 に答える 2

1

以下に提案されている方法で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...')呼び出しの間です。ご覧のとおり、これらの呼び出しは両方とも同じメソッド内にあるため、プロファイリングの時間にはネットワーク転送が含まれていません。おそらく問題は、リモート データベース サーバーが大きな負荷の下で実行されていることです。

于 2012-11-14T16:33:34.520 に答える
0

CProfileLogRoute クラスにはignoreAjaxInFireBugと呼ばれるプロパティがあり、これをfalseに設定するとデフォルトで「true」になり、ajax リクエストでプロファイリング情報を取得できます。

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',
                    ),
        ),

その作業にfirebugを使用する必要があるとは思いません(一種の誤称です)。ただし、Firefox をダウンロードして Firebug をインストールするだけで問題は解決します。

于 2013-07-10T20:16:48.713 に答える