【问题标题】:Log the actual SQL query using ActiveRecord with Yii2?使用 ActiveRecord 和 Yii2 记录实际的 SQL 查询?
【发布时间】: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。这可能吗?

【问题讨论】:

    标签: php sql activerecord logging yii2


    【解决方案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。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-01-23
            • 2023-02-14
            • 1970-01-01
            • 2017-10-09
            相关资源
            最近更新 更多