本文目录导读:

在PHP项目中统计长短传比例,主要取决于你的业务场景,以下是几种常见场景的解决方案:
网络请求(HTTP请求)长短传统计
<?php
class RequestTimeStats {
private $db;
public function __construct($db) {
$this->db = $db;
}
// 记录请求耗时
public function logRequestTime($requestTime) {
$isLong = $requestTime > 1.0; // 1秒以上算长传
$stmt = $this->db->prepare(
"INSERT INTO request_stats (timestamp, duration, type)
VALUES (NOW(), ?, ?)"
);
$stmt->execute([
$requestTime,
$isLong ? 'long' : 'short'
]);
}
// 统计数据
public function getStats($timeRange = 'today') {
$where = '';
if ($timeRange == 'today') {
$where = "WHERE DATE(timestamp) = CURDATE()";
} elseif ($timeRange == 'week') {
$where = "WHERE timestamp >= DATE_SUB(NOW(), INTERVAL 7 DAY)";
}
$sql = "SELECT
type,
COUNT(*) as count,
AVG(duration) as avg_duration,
MIN(duration) as min_duration,
MAX(duration) as max_duration
FROM request_stats
$where
GROUP BY type";
return $this->db->query($sql)->fetchAll(PDO::FETCH_ASSOC);
}
}
?>
文件上传大小分布
<?php
class FileUploadStats {
// 文件大小分类
public function categorizeFiles($fileSize) {
$categories = [
'very_small' => 0, // 0-10KB
'small' => 1, // 10KB-100KB
'medium' => 2, // 100KB-1MB
'large' => 3, // 1MB-10MB
'very_large' => 4 // >10MB
];
if ($fileSize < 10240) {
return 'very_small';
} elseif ($fileSize < 102400) {
return 'small';
} elseif ($fileSize < 1048576) {
return 'medium';
} elseif ($fileSize < 10485760) {
return 'large';
} else {
return 'very_large';
}
}
// 统计上传文件分布
public function getUploadDistribution($startDate, $endDate) {
$sql = "SELECT
CASE
WHEN file_size < 10240 THEN '0-10KB'
WHEN file_size < 102400 THEN '10KB-100KB'
WHEN file_size < 1048576 THEN '100KB-1MB'
WHEN file_size < 10485760 THEN '1MB-10MB'
ELSE '>10MB'
END as size_range,
COUNT(*) as count,
SUM(file_size) as total_size
FROM uploads
WHERE created_at BETWEEN ? AND ?
GROUP BY size_range
ORDER BY MIN(file_size)";
return $this->db->query($sql, [$startDate, $endDate])->fetchAll();
}
}
?>
数据库查询长短耗时统计
<?php
class QueryPerformanceStats {
public function analyzeQueryPerformance() {
// 启用慢查询日志
$this->db->exec("SET GLOBAL slow_query_log = 'ON'");
$this->db->exec("SET GLOBAL long_query_time = 1"); // 1秒以上
// 从慢查询日志获取数据
$logFile = ini_get('slow_query_log_file');
$logs = file($logFile);
$stats = [
'long_queries' => 0,
'short_queries' => 0,
'total_queries' => 0,
'long_query_details' => []
];
foreach ($logs as $log) {
if (preg_match('/Query_time:\s*([0-9.]+)/', $log, $matches)) {
$stats['total_queries']++;
if ((float)$matches[1] > 1.0) {
$stats['long_queries']++;
$stats['long_query_details'][] = [
'query_time' => $matches[1],
'query' => extractQuery($log)
];
} else {
$stats['short_queries']++;
}
}
}
// 计算比例
$stats['long_ratio'] = $stats['total_queries'] > 0
? ($stats['long_queries'] / $stats['total_queries']) * 100
: 0;
return $stats;
}
private function extractQuery($logLine) {
// 解析查询语句
preg_match('/Query:\s*(.*)/', $logLine, $matches);
return isset($matches[1]) ? $matches[1] : '';
}
}
?>
API接口响应时间统计
<?php
class APIResponseStats {
// 中间件/拦截器统计
public function calculateResponseStats() {
$sql = "SELECT
DATE(created_at) as date,
route,
AVG(response_time) as avg_response,
MAX(response_time) as max_response,
MIN(response_time) as min_response,
SUM(CASE WHEN response_time > 2 THEN 1 ELSE 0 END) as long_requests,
SUM(CASE WHEN response_time <= 2 THEN 1 ELSE 0 END) as short_requests,
COUNT(*) as total_requests
FROM api_logs
GROUP BY DATE(created_at), route
ORDER BY date DESC, total_requests DESC";
return $this->db->query($sql)->fetchAll(PDO::FETCH_ASSOC);
}
// 生成统计报告
public function generateReport() {
$stats = $this->calculateResponseStats();
$report = [
'total_requests' => 0,
'long_requests' => 0,
'short_requests' => 0,
'long_ratio' => 0,
'by_route' => []
];
foreach ($stats as $stat) {
$report['total_requests'] += $stat['total_requests'];
$report['long_requests'] += $stat['long_requests'];
$report['short_requests'] += $stat['short_requests'];
// 按路由统计
if (!isset($report['by_route'][$stat['route']])) {
$report['by_route'][$stat['route']] = [
'total' => 0,
'long' => 0,
'short' => 0
];
}
$report['by_route'][$stat['route']]['total'] += $stat['total_requests'];
$report['by_route'][$stat['route']]['long'] += $stat['long_requests'];
$report['by_route'][$stat['route']]['short'] += $stat['short_requests'];
}
// 计算总比例
if ($report['total_requests'] > 0) {
$report['long_ratio'] = $report['long_requests'] / $report['total_requests'] * 100;
$report['short_ratio'] = 100 - $report['long_ratio'];
}
return $report;
}
}
?>
使用Redis实时统计
<?php
class RealTimeStats {
private $redis;
public function __construct($redis) {
$this->redis = $redis;
}
// 实时增加统计
public function incrementStats($type) {
$today = date('Y-m-d');
// 使用Hash存储每日数据
$key = "stats:request:{$today}";
$this->redis->hIncrBy($key, 'total', 1);
$this->redis->hIncrBy($key, $type, 1);
// 设置过期时间(保留30天)
$this->redis->expire($key, 86400 * 30);
}
// 获取实时统计
public function getCurrentStats() {
$today = date('Y-m-d');
$key = "stats:request:{$today}";
$data = $this->redis->hGetAll($key);
$total = isset($data['total']) ? $data['total'] : 0;
$long = isset($data['long']) ? $data['long'] : 0;
$short = isset($data['short']) ? $data['short'] : 0;
return [
'total' => $total,
'long' => $long,
'short' => $short,
'long_ratio' => $total > 0 ? ($long / $total) * 100 : 0,
'short_ratio' => $total > 0 ? ($short / $total) * 100 : 0,
'updated_at' => date('Y-m-d H:i:s')
];
}
}
?>
可视化展示
// 生成饼图/柱状图数据
public function getChartData() {
$stats = $this->getStats();
return [
'labels' => ['短传', '长传'],
'datasets' => [
[
'data' => [$stats['short'], $stats['long']],
'backgroundColor' => ['#36A2EB', '#FF6384'],
'hoverBackgroundColor' => ['#36A2EB', '#FF6384']
]
]
];
}
使用建议
- 阈值定义:根据业务需求定义“长传”的标准(如超过1秒、超过1MB等)
- 存储方案:可以使用数据库、Redis或日志文件
- 实时监控:建议配合监控系统(如Prometheus + Grafana)
- 优化建议:根据统计结果优化相关代码或配置
这样可以根据实际需求选择合适的方法来统计长短传比例,你需要哪种具体场景的实现?