使用 ActiveRecord 和 Yii2 记录实际的 SQL 查询?
Posted
技术标签:
【中文标题】使用 ActiveRecord 和 Yii2 记录实际的 SQL 查询?【英文标题】:Log the actual SQL query using ActiveRecord with Yii2? 【发布时间】:2015-02-07 22:44:12 【问题描述】:我正在这样做:
$students = Student::find()->all();
return $this->render('process', array('students' => $students));
然后在视图中显示:
foreach($students as $student)
echo $student->name . ', ';
echo $student->getQuizActivitiesCount(); ?> <br /> <?php
我想查看正在执行的 sql 查询。一个学生“有很多”测验活动,查询执行得很好,但我需要查看原始 SQL。这可能吗?
【问题讨论】:
【参考方案1】:如果您想在控制台应用程序中记录所有ActiveRecord
的关系查询,那么所有建议的方法都无济于事。它们仅在活动记录的表上显示主要 SQL,\yii\debug\Module
仅在浏览器中有效。
获取所有执行的 SQL 查询的另一种方法是通过在配置中添加特定的 FileTarget 来记录它们:
'log' => [
'targets' => [[
...
], [
'class' => 'yii\log\FileTarget',
'logFile' => '@runtime/logs/profile.log',
'logVars' => [],
'levels' => ['profile'],
'categories' => ['yii\db\Command::query'],
'prefix' => function($message)
return '';
]]
]
更新
为了记录插入/更新/删除查询,还应添加yii\db\Command::execute
类别:
'categories' => ['yii\db\Command::query', 'yii\db\Command::execute']
【讨论】:
很好的补充!但我认为出错的方法在 CLI 中仍然可以工作,会抛出异常并显示完整的查询, @arogachev,它只会向您显示发生错误的单个 SQL 查询。如果您使用许多急切加载的关系构建活动查询,则使用起来非常困难(几乎不可能),因为它要求您在串联的每个关系中都犯错误,并且它不能描述整个情况。您还可能会错过一些您不希望执行或忘记的查询。 是的,你是对的。在这种情况下,日志记录会更好。 @RobySottini,你应该把它添加到application's configuration file。 @RobySottini,这是config/web.php
文件,用于basic application template。【参考方案2】:
除了 arogachev 答案,当您已经使用 ActiveQuery
对象时,这是我搜索以查看 rawsql 的行。
/* @var $studentQuery ActiveQuery */
$studentQuery = Student::Find();
// Construct the query as you want it
$studentQuery->where("status=3")->orderBy("grade ASC");
// Get the rawsql
var_dump($studentQuery->prepare(Yii::$app->db->queryBuilder)->createCommand()->rawSql);
// Run the query
$studentQuery->all();
【讨论】:
这与我的回答有何不同?$model->getUser()
也是 ActiveQuery
实例。
在我的回答中添加了关于此的附加说明,但共同原则是相同的。【参考方案3】:
方法一
使用返回 yii\db\ActiveQuery
实例的关系,可以直接在代码中提取原始 SQL 查询,例如使用 var_dump()
。
例如,如果我们有user
关系:
/**
* @return \yii\db\ActiveQuery
*/
public function getUser()
return $this->hasOne(User::className(), ['id' => 'user_id']);
然后您可以像这样var_dump()
原始 SQL:
var_dump($model->getUser()->prepare(Yii::$app->db->queryBuilder)->createCommand()->rawSql);
exit();
请注意,您应该这样称呼它,而不是 $model->user->...
(后者返回 User
实例)。
但在你的情况下这是不可能的,因为count()
立即返回int
。不用count()
也可以var_dump()
部分查询,但是我觉得不太方便。
请注意,您可以使用此方法转储任何ActiveQuery
实例(不仅是关系返回的那些)生成的 SQL,例如:
$query = User::find()->where(['status' => User::STATUS_ACTIVE]);
var_dump($query->prepare(Yii::$app->db->queryBuilder)->createCommand()->rawSql);
exit();
方法二
这在我看来要简单得多,我个人在调试 SQL 查询时更喜欢这个。
Yii 2 有内置的调试模块。只需将其添加到您的配置中:
'modules' => [
'debug' => [
'class' => 'yii\debug\Module',
],
],
确保您仅在本地拥有它,而不是在生产环境中。如果需要,还可以更改 allowedIPs
属性。
这会在页面底部为您提供功能面板。找到DB
字并单击计数或时间。在此页面上,您可以查看所有已执行的查询并对其进行过滤。
我通常不在 Grid 中过滤它们,而是使用标准浏览器搜索来快速浏览并找到必要的查询(例如,使用表名作为关键字)。
方法3
只需在查询中出错,例如在列名中 - cityy
而不是 city
。这将导致数据库异常,然后您可以立即在错误消息中看到生成的查询。
【讨论】:
不幸的是,我无法在控制台应用程序中看到所有这些方法的关系查询。添加了一个显示我如何解决它的答案。 我将它添加到 common/config/main-local 的 components 数组中,但它不起作用:'modules' => [ 'debug' => [ 'class' => 'yii\debug \模块', ], ], $query = User::find()->where(['status' => User::STATUS_ACTIVE]); var_dump($query->prepare(Yii::$app->db->queryBuilder)->createCommand()->rawSql);出口();为我工作【参考方案4】:试试看,
$query = Yii::$app->db->createCommand()
->update('table_name', ['title' => 'MyTitle'],['id' => '1']);
var_dump($query->getRawSql()); die();
$query->execute();
输出:
string 'UPDATE `table_name`
SET `title`='MyTitle' WHERE `id`='1'
' (length=204)
【讨论】:
【参考方案5】:为了记录/跟踪每个/所有查询:
扩展 \yii\db\Connection
并覆盖 createCommand
方法,如下所示:
namespace app\base;
class Connection extends \yii\db\Connection
public function createCommand($sql = null, $params = array())
$createCommand = parent::createCommand($sql, $params);
$rawSql = $createCommand->getRawSql();
// ########### $rawSql -> LOG IT / OR DO ANYTHING YOU WANT WITH IT
return $createCommand;
然后,只需在您的数据库配置中更改您的数据库连接,如下所示:
'db' => [
'class' => 'app\base\Connection', // #### HERE
'dsn' => 'pgsql:host=localhost;dbname=dbname',
'username' => 'uname',
'password' => 'pwd',
'charset' => 'utf8',
],
现在,您可以跟踪/读取/...由db
连接执行的所有查询。
【讨论】:
【参考方案6】:你可以试试这个,假设你有这样的查询:
$query = new Books::find()->where('author=2');
echo $query->createCommand()->sql;
或获取包含所有参数的 SQL 尝试:
$query->createCommand()->getRawSql()
【讨论】:
【参考方案7】:当你有一个查询对象时,你也可以使用
$query->createCommand()->getRawSql()
返回包含参数的原始 SQL 或
$query->createCommand()->sql
这将分别输出带有参数的Sql。
【讨论】:
以上是关于使用 ActiveRecord 和 Yii2 记录实际的 SQL 查询?的主要内容,如果未能解决你的问题,请参考以下文章
关于yii2框架活动记录activeRecord添加默认字段的问题
如何在 YII2 ActiveRecord 查询中说 (a AND b) OR (c AND d)?