使用 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-&gt;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-&gt;user-&gt;...(后者返回 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 查询?的主要内容,如果未能解决你的问题,请参考以下文章