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时间进行判断是否数据超时查询
});