You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用PHP与MySQL实现服务器在线率(Uptime)统计?

正确实现服务器在线率统计(PHP + MySQL)

我来帮你搞定这个在线率统计的问题!首先先纠正一下你提到的公式小偏差——在线率的正确计算应该是在线检测次数 ÷ 总检测次数 × 100%,如果用在线次数除以离线次数,遇到服务器全天在线的情况会直接触发除以0的错误。接下来我们一步步解决准确性和性能问题:

一、修正SQL语句(解决准确性与性能痛点)

你之前的SQL用了CROSS JOIN和DATE(created_at),前者会产生不必要的笛卡尔积拖慢查询,后者会让created_at字段的索引直接失效,这俩都是性能差的核心原因。下面是优化后的SQL:

1. 统计单台服务器当日在线率

SELECT 
    server_id,
    ROUND(
        (SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) / COUNT(*)) * 100,
        2
    ) AS uptime_percentage
FROM stats
WHERE 
    server_id = ? -- 替换为目标服务器ID
    AND created_at >= CURDATE() 
    AND created_at < CURDATE() + INTERVAL 1 DAY
GROUP BY server_id;

2. 统计所有服务器当日在线率

SELECT 
    server_id,
    ROUND(
        (SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) / COUNT(*)) * 100,
        2
    ) AS uptime_percentage
FROM stats
WHERE 
    created_at >= CURDATE() 
    AND created_at < CURDATE() + INTERVAL 1 DAY
GROUP BY server_id;

3. 扩展到7天/30天在线率

只需要修改WHERE条件的时间范围即可:

-- 7天在线率
WHERE 
    created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)
    AND created_at < NOW()

-- 30天在线率
WHERE 
    created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)
    AND created_at < NOW()

二、性能优化关键:添加联合索引

你的Cron每10分钟写入一条数据,数据量会快速增长,必须加索引才能保证查询速度。推荐创建这个联合索引:

CREATE INDEX idx_server_created_status ON stats(server_id, created_at, status);

这个索引能让数据库快速定位到指定服务器、指定时间范围的记录,同时直接从索引里获取status值,不需要回表查询,性能提升非常明显。

三、PHP代码实现示例

下面是一个简单的PHP示例,展示如何从数据库获取并展示服务器在线率:

<?php
// 数据库连接配置
$host = '你的数据库地址';
$dbname = '你的数据库名';
$username = '数据库用户名';
$password = '数据库密码';

try {
    $pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // 获取单台服务器当日在线率(替换410060为目标服务器ID)
    $serverId = 410060;
    $stmt = $pdo->prepare("
        SELECT 
            ROUND(
                IFNULL(
                    (SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) / NULLIF(COUNT(*), 0)) * 100,
                    0
                ),
                2
            ) AS uptime_percentage
        FROM stats
        WHERE 
            server_id = ?
            AND created_at >= CURDATE() 
            AND created_at < CURDATE() + INTERVAL 1 DAY
    ");
    $stmt->execute([$serverId]);
    $result = $stmt->fetch(PDO::FETCH_ASSOC);

    if ($result) {
        echo "服务器ID {$serverId} 当日在线率:{$result['uptime_percentage']}%";
    } else {
        echo "该服务器今日暂无检测数据";
    }

} catch(PDOException $e) {
    echo "数据库错误: " . $e->getMessage();
}
?>

四、额外优化建议

  • 避免全表扫描:永远不要用DATE(created_at) = CURDATE()这种写法,改用范围查询created_at >= CURDATE() AND created_at < CURDATE() + INTERVAL 1 DAY,这样才能利用索引。
  • 处理除数为0的情况:上面的SQL用了NULLIF(COUNT(*), 0)和IFNULL,避免了服务器无检测记录时的除以0错误。
  • 缓存统计结果:如果网站访问量较大,不要每次请求都实时计算,可以把在线率结果缓存到Redis或者本地文件中,比如每小时重新计算一次,进一步提升性能。

内容的提问来源于stack exchange,提问作者Dumitru

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:30:43