TP框架在调试模式下可以看到相关的SQL语句和耗时,在正常情况下记录sql也可以,但是个人感觉不太习惯(怪自己不够熟悉),所以简单修改了一下tp的数据库查询类think\db\Query新增了自定义时间内记录sql的功能,当然文末直接讲开启配置里面的sql_explain分析简单监听即可(推荐)。
因为tp的增改删查经过这个文件,在这里操作比较方便,查询和执行是两个独立的方法,分别是query和execute,所以针对这两个查询结果写入日志即可。
当然,利用tp的行为监控更好了,添加一个行为标签tag:listen_log(随便起的名字),在behavior目录的controller下新增Log.php类,写入简单的逻辑
<?php /** @author 小韦 * @link http://blog.alipay168.cn * @Date: 2021/8/12 20:02 */ namespace app\behavior\controller; use app\behavior\behaviorComm; use app\common\common; class Log extends behaviorComm { function run($params = []) { if (!empty($params['call'])) { if ($params['call'] == 'db_query' || $params['call'] == 'db_execute') { return $this->db_log($params); } } //common::add_log('abb', $params); } //数据库操作日志——慢查询 private function db_log($params = []) { $data = [ 'use_time' => $params['use_time'], 'sql' => $params['sql'], 'add_time' => time(), 'action_type' => ltrim($params['call'], 'db_'), ]; //跳过自己,防止死循环 if (stripos($params['sql'], 'core_db_log') !== false) { return; } //还是添加到数据库方便后台查询,所以上面要加个判断 common::data_add('core_db_log', $data);//用简单的方式插入到数据库去 } }
然后修改Query.php,大概是240~300行直接的两个方法execute和query
修改前:
/** * 执行查询 返回数据集 * @access public * @param string $sql sql指令 * @param array $bind 参数绑定 * @param boolean $master 是否在主服务器读操作 * @param bool|string $class 指定返回的数据集对象 * @return mixed * @throws BindParamException * @throws PDOException */ public function query($sql, $bind = [], $master = false, $class = false) { return $this->connection->query($sql, $bind, $master, $class); } /** * 执行语句 * @access public * @param string $sql sql指令 * @param array $bind 参数绑定 * @return int * @throws BindParamException * @throws PDOException */ public function execute($sql, $bind = []) { return $this->connection->execute($sql, $bind, $this); }
修改后:
/** * 执行语句 * @access public * @param string $sql sql指令 * @param array $bind 参数绑定 * @return int * @throws BindParamException * @throws PDOException */ public function execute($sql, $bind = []) { $stime = microtime(true); $res = $this->connection->execute($sql, $bind, $this); $etime = microtime(true); //如果时间过长并且行为存在就写入记录 if ($etime - $stime >= config('database.slow_time') && Hook::get('listen_log')) { $p = [ 'call' => 'db_execute', 'sql' => $this->connection->getRealSql($sql, $bind), 'use_time' => number_format($etime - $stime, 10), 'add_time' => time() ]; Hook::listen('listen_log', $p); } return $res; } /** * 执行查询 返回数据集 * @access public * @param string $sql sql指令 * @param array $bind 参数绑定 * @param boolean $master 是否在主服务器读操作 * @param bool|string $class 指定返回的数据集对象 * @return mixed * @throws BindParamException * @throws PDOException */ public function query($sql, $bind = [], $master = false, $class = false) { $stime = microtime(true); $res = $this->connection->query($sql, $bind, $master, $class); $etime = microtime(true); //如果时间过长并且行为存在就写入记录 if ($etime - $stime >= config('database.slow_time') && Hook::get('listen_log')) { $p = [ 'call' => 'db_query', 'sql' => $this->connection->getRealSql($sql, $bind), 'use_time' => number_format($etime - $stime, 10), ]; Hook::listen('listen_log', $p); } return $res; }
步骤三:给tag写入到config目录tag.php里面
<?php return array( 'app_init' => array(), 'app_begin' => array( ), 'module_init' => array(), 'action_begin' => array(), 'view_filter' => array(), 'log_write' => array(), 'app_end' => array(), //这里是新增的,只看这里就行了,系统自动加载进入,后面就listen就行了 'listen_log'=>[ 'app\\behavior\\controller\\Log' ], ) ?>
最后在config目录下面的database.php配置加上自定义的时间:
//慢查询的记录时间 'slow_time'=>'0.01',
改好了之后,可以测试了(数据库自己设计哈):
图片前面是设置时间为0的,后面是时间0.01测试的。
这样就完成了调整,在后台可以更方便查询日志和进行解释、优化操作了。
最简单的方式是开启database.php里面的sql_explain,这个改成true表示分析数据库,会记录日志哦。
开启语句解释后可以通过自带的监听实现回调(配置自己的监听后是不会自己写入日志的,都进入自己的监听了):
Db::listen(function($sql,$time,$explain){ // 记录SQL echo $sql. ' ['.$time.'s]'; // 查看性能分析结果 dump($explain); //这里可以根据$time时间进行判断是否数据超时查询 });