【问题标题】:Laravel 5: How to dump SQL query?Laravel 5:如何转储 SQL 查询?
【发布时间】:2017-05-09 19:04:13
【问题描述】:

Laravel 5 的内置解决方案

在 Laravel 5+ 中,我们可以使用 \DB::getQueryLog() 来检索所有已执行的查询。因为,查询日志是一项广泛的操作并会导致性能问题,因此它在 L5 中默认禁用,仅推荐用于开发环境。我们可以使用方法\DB::enableQueryLog() 启用查询日志记录,如 [Laravel 的文档][1] 中所述。

内置解决方案中的问题

DB::getQueryLog() 函数很棒,但有时我们希望以平面 SQL 格式转储它会很棒,因此我们可以将其复制/粘贴到我们最喜欢的 MySQL 应用程序中,例如 phpMyAdminSqlyog 来执行它并调试或优化它。

所以,我需要一个辅助函数来帮助我生成带有以下附加信息的转储:

  • 转储调用了哪个文件和行号。
  • 从查询中删除反引号。
  • 平面查询,因此不需要手动更新绑定参数,我可以在phpMyAdmin 中复制/粘贴SQL 等来调试/优化查询。

【问题讨论】:

    标签: mysql laravel logging dump


    【解决方案1】:

    我一直在寻找简单的解决方案,而下面的解决方案对我有用。

    DB::enableQueryLog();
    
    User::find(1); //Any Eloquent query
    
    // and then you can get query log
    
    dd(DB::getQueryLog());
    

    参考链接:

    【讨论】:

      【解决方案2】:

      对于 Laravel 8 应用程序,将以下内容放入 AppServiceProvider.php 文件可能会很有用:

      /**
       * Bootstrap any application services.
       *
       * @return void
       */
      public function boot()
      {
          // [...]
          // Dump SQL queries on demand **ONLY IN DEV**
          if (env('APP_ENV') === 'local') {
              DB::enableQueryLog();
              Event::listen(RequestHandled::class, function ($event) {
                  if ( $event->request->has('sql-debug') ) {
                      $queries = DB::getQueryLog();
                      Log::debug($queries);
                      dump($queries);
                  }
              });
          }
      
          // [...]
      }
      

      然后将&sql-debug=1 附加到 url 将转储查询。

      【讨论】:

        【解决方案3】:

        将此代码添加到您的路线文件的顶部。 Laravel 5.2 路由.php Laravel 5.3+ web.php

        <?php
        // Display all SQL executed in Eloquent
        
        Event::listen('Illuminate\Database\Events\QueryExecuted', function ($query) {
            var_dump($query->sql);
            var_dump($query->bindings);
            var_dump($query->time);
            echo "<br><br><br>";
        });
        

        【讨论】:

          【解决方案4】:
          • 转储在哪个文件和行号上 调用。

          我不明白你为什么需要这个,因为你总是知道你在哪里调用了转储函数,但没关系你有你的解决方案。

          • 从查询中删除 back-ticks

          您无需删除 back-ticks,因为查询也可以在 MySQL 中与它们一起使用。

          • 平面查询,因此不需要手动更新绑定参数,我可以在 phpMyAdmin 等中复制/粘贴 SQL 来调试/优化查询。

          您可以使用vsprintf 来绑定参数:

          $queries = DB::getQueryLog();
          
          foreach ($queries as $key => $query) {
              $queries[$key]['query'] = vsprintf(str_replace('?', '\'%s\'', $query['query']), $query['bindings']);
          }
          
          return $queries;
          

          我建议你查看这个 github repo squareboat/sql-doctor

          【讨论】:

          • 通过删除back-ticks,生成的SQL将易于阅读和调试,因为该函数的主要工作是调试。感谢vsprintf 功能,是的,它将帮助我减少代码。
          【解决方案5】:

          自定义解决方案

          第 1 步:启用查询日志记录

          复制/粘贴路由文件顶部的以下代码块:

          # File: app/Http/routes.php
          if (\App::environment( 'local' )) { 
             \DB::enableQueryLog();
          }
          

          第二步:添加辅助函数

          if (!function_exists( 'dump_query' )) {
          function dump_query( $last_query_only=true, $remove_back_ticks=true ) {
          
              // location and line
              $caller = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 1 );
              $info = count( $caller ) ? sprintf( "%s (%d)", $caller[0]['file'], $caller[0]['line'] ) : "*** Unable to parse location info. ***";
          
              // log of executed queries
              $logs = DB::getQueryLog();
              if ( empty($logs) || !is_array($logs) ) {
                  $logs = "No SQL query found. *** Make sure you have enabled DB::enableQueryLog() ***";
              } else {
                  $logs = $last_query_only ? array_pop($logs) : $logs;
              }
          
              // flatten bindings
              if (isset( $logs['query'] ) ) {
                  $logs['query'] = $remove_back_ticks ? preg_replace( "/`/", "", $logs['query'] ) : $logs['query'];
          
                  // updating bindings
                  $bindings = $logs['bindings'];
                  if ( !empty($bindings) ) {
                      $logs['query'] = preg_replace_callback('/\?/', function ( $match ) use (&$bindings) {
                          return "'". array_shift($bindings) . "'";
                      }, $logs['query']);
                  }
              }
              else foreach($logs as &$log) {
                  $log['query'] = $remove_back_ticks ? preg_replace( "/`/", "", $log['query'] ) : $log['query'];
          
                  // updating bindings
                  $bindings = $log['bindings'];
                  if (!empty( $bindings )) {
                      $log['query'] = preg_replace_callback(
                          '/\?/', function ( $match ) use ( &$bindings ) {
                          return "'" . array_shift( $bindings ) . "'";
                      }, $log['query']
                      );
                  }
              }
          
              // output
              $output = ["*FILE*" => $info,
                         '*SQL*' => $logs
              ];
          
              dump( $output );
          }
          

          }

          如何使用?

          获取上次执行查询的转储,在查询执行后使用:

          dump_query();
          

          转储所有已执行的查询使用:

          dump_query( false );
          

          【讨论】:

            猜你喜欢
            • 2017-01-05
            • 2021-10-11
            • 2019-09-23
            • 2020-07-14
            • 2016-06-01
            • 2016-06-14
            • 2016-08-14
            • 2016-02-14
            • 2017-12-29
            相关资源
            最近更新 更多