使用 group + date_format 可按小时聚合日志数据,需基于 request_log 表的 create_time 字段,用 date_format 格式化为“%y-%m-%d %h:00:00”后分组统计,并注意索引、时区、兼容性及性能优化。

用 group + date_format 按小时聚合日志数据
ThinkPHP 本身不内置访问统计功能,得靠你自己记录请求日志(比如写进数据库表),再基于该表做聚合查询。最直接的方式是用数据库原生函数格式化时间字段,然后分组统计。
假设你有个 request_log 表,含 create_time(datetime 类型)字段,要统计最近 24 小时每小时的请求数:
$logs = Db::name('request_log')
->where('create_time', '>=', date('Y-m-d H:i:s', time() - 86400))
->field('DATE_FORMAT(create_time, "%Y-%m-%d %H:00:00") as hour, count(*) as cnt')
->group('hour')
->order('hour asc')
->select();
注意:DATE_FORMAT 是 MySQL 函数,SQLite 或 PostgreSQL 不兼容;TP6 的 Db 支持原生 SQL 片段,但别在 where 里滥用函数导致索引失效。
避免 DATE_FORMAT 兼容性问题的替代写法
如果换数据库或想更可控,改用 from_unixtime + unix_timestamp 截断到小时级时间戳,再转回可读格式:
$logs = Db::name('request_log')
->where('create_time', '>=', date('Y-m-d H:i:s', time() - 86400))
->field('FROM_UNIXTIME(UNIX_TIMESTAMP(create_time) - UNIX_TIMESTAMP(create_time) % 3600, "%Y-%m-%d %H:00:00") as hour, count(*) as cnt')
->group('hour')
->order('hour asc')
->select();
- 这个写法在 MySQL、MariaDB、PostgreSQL(需微调函数名)都较稳妥
-
% 3600是关键:把秒级时间戳对齐到整点 - TP 不会自动给这种表达式加反引号,字段别名
hour必须显式声明,否则group会报错
在控制器里封装成可复用的统计方法
别每次都在控制器里拼 SQL,抽成模型方法更干净。比如在 app\model\RequestLog.php 里加:
public static function getHourlyCount($hours = 24)
{
$cutoff = date('Y-m-d H:i:s', time() - $hours * 3600);
return self::where('create_time', '>=', $cutoff)
->field('DATE_FORMAT(create_time, "%Y-%m-%d %H:00:00") as hour, count(*) as cnt')
->group('hour')
->order('hour asc')
->select()
->toArray();
}
调用时就简单了:
$data = RequestLog::getHourlyCount(48); // 获取最近 48 小时
- 传参控制时间范围,比硬编码灵活
- 返回数组而非 Collection,前端渲染或 API 输出更省事
- 没做异常兜底,生产环境建议加
try/catch和空结果判断
真实场景下必须考虑的性能与精度问题
直接查原始日志表在高并发下容易慢,尤其 create_time 没索引或数据量超 10 万行时:
- 务必给
create_time字段加 B-tree 索引:ALTER TABLE request_log ADD INDEX idx_create_time (create_time); - 如果只是看趋势,可预计算:用定时任务(如 Linux cron)每小时跑一次,把结果存到
stat_hourly表,查的时候只读这张轻量表 - 注意时区:TP 默认用系统时区,但数据库可能设为 UTC,
DATE_FORMAT输出的时间可能和你预期差 8 小时,统一用date_default_timezone_set('Asia/Shanghai')并确认 MySQL 的time_zone设置
小时级统计看着简单,但时间对齐方式、索引、时区、存储策略这四点漏掉任一个,上线后都可能出偏差。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











