在 Yii 開發中,Active Record 和 Query Builder 封裝了底層 SQL,雖然提高了開發效率,但也帶來了「黑盒」問題:生成的 SQL 是否高效?是否存在 N+1 查詢?參數綁定是否正確?掌握調試技巧對性能優化與問題排查至關重要。
在 index.php 入口文件中:
// 開啟調試模式(生產環境務必關閉)
defined('YII_DEBUG') or define('YII_DEBUG', true);
// 設置調用堆疊顯示層級(0-3,數值越大信息越詳盡)
defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL', 3);
在 protected/config/main.php 中:
'log' => array(
'class' => 'CLogRouter',
'routes' => array(
// 文件日誌:記錄錯誤與警告
array(
'class' => 'CFileLogRoute',
'levels' => 'error, warning',
'logFile' => 'application.log',
'maxFileSize' => 1024 * 1024 * 5, // 5MB
'maxLogFiles' => 10,
),
// 網頁顯示:實時查看 SQL 執行情況
array(
'class' => 'CWebLogRoute',
'levels' => 'trace',
'categories' => 'system.db.*', // 只顯示數據庫相關
'showInFireBug' => false, // 不在 FireBug 顯示
),
// 郵件告警:生產環境關鍵錯誤通知
array(
'class' => 'CEmailLogRoute',
'levels' => 'error, warning',
'emails' => 'admin@example.com',
),
),
),
'db' => array(
'connectionString' => 'mysql:host=localhost;dbname=test',
'username' => 'root',
'password' => '',
'enableProfiling' => true, // 啟用性能分析
'enableParamLogging' => true, // 記錄參數綁定詳情
'schemaCachingDuration' => 3600, // 緩存表結構
),
下載 yii-debug-toolbar 解壓至 protected/extensions/,在配置中添加:
'log' => array(
'class' => 'CLogRouter',
'routes' => array(
array(
'class' => 'ext.yii-debug-toolbar.YiiDebugToolbarRoute',
'ipFilters' => array('127.0.0.1', '192.168.*.*'), // 限制訪問 IP
'toolbarTheme' => 'dark', // 暗色主題
),
),
),
若與其他調試擴展衝突導致 SQL 不顯示,嘗試禁用其他路由:
'routes' => array(
// 暫時註釋掉 CWebLogRoute
// array('class' => 'CWebLogRoute', 'levels' => 'trace', 'categories' => 'system.db.*'),
array('class' => 'ext.yii-debug-toolbar.YiiDebugToolbarRoute', 'ipFilters' => array('127.0.0.1')),
),
// 方法一:CDbCommand::getText()
$command = Yii::app()->db->createCommand()
->select('*')
->from('user')
->where('status=:status', array(':status' => 1));
echo $command->getText(); // SELECT * FROM `user` WHERE `status`=:status
// 方法二:開啟單條 SQL 分析
$command->queryAll(); // 執行後
var_dump($command->getText(), $command->getParams());
class User extends CActiveRecord {
public function beforeFind() {
if (YII_DEBUG) {
Yii::trace('User query: ' . $this->getDbCriteria()->toString(), 'myapp.db');
}
return parent::beforeFind();
}
}
// 僅特定用戶/參數開啟
if (isset($_GET['sql_debug']) && Yii::app()->user->isAdmin()) {
Yii::app()->db->enableProfiling = true;
Yii::app()->db->enableParamLogging = true;
}
'db' => array(
'class' => 'CDbConnection',
'enableProfiling' => true,
'onAfterQuery' => function($event) {
$sql = $event->sender->getText();
$time = $event->sender->queryDuration;
if ($time > 1.0) { // 超過 1 秒記錄
Yii::log("Slow Query ($time s): $sql", 'warning', 'db.slow');
}
},
),
| 關鍵字段 | 含義 | 關注重點 |
|---|---|---|
| queryDuration | SQL 執行耗時(秒) | > 0.1s 需優化 |
| queryCount | 請求總查詢數 | > 50 疑似 N+1 |
| params | 參數綁定值 | 檢查類型/注入風險 |
| callStack | 調用堆疊 | 定位業務代碼位置 |