使用 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 查询?的主要内容,如果未能解决你的问题,请参考以下文章

yii2 使用 ActiveRecord 批量插入

关于yii2框架活动记录activeRecord添加默认字段的问题

yii2 数据库和ActiveRecord

如何在 YII2 ActiveRecord 查询中说 (a AND b) OR (c AND d)?

如何将 DAO 查询转换为 Yii2 ActiveRecord。如何从连接表中选择和使用特定列

yii2 basic版 MVC 部分