当前位置: 首页> 最新文章列表> 如何用 getrusage() 检测数据库查询前后系统压力变化,提升性能?

如何用 getrusage() 检测数据库查询前后系统压力变化,提升性能?

M66 2025-06-11

什么是 getrusage()

getrusage() 是一个 PHP 原生函数,用于获取当前进程或其子进程的资源使用情况。它返回一个数组,包含了多个系统层面的数据,例如用户态/内核态 CPU 时间、内存页故障次数、上下文切换次数等。

$usage = getrusage();

常用的几个字段包括:

  • ru_utime.tv_secru_utime.tv_usec:用户态消耗的时间(秒和微秒)

  • ru_stime.tv_secru_stime.tv_usec:系统态消耗的时间(秒和微秒)

  • ru_minflt:无需从磁盘调入的页错误数量(软缺页)

  • ru_majflt:从磁盘调入的页错误数量(硬缺页)

  • ru_nvcswru_nivcsw:自愿和非自愿上下文切换次数


在数据库查询前后调用 getrusage()

要监控数据库查询对系统的影响,最直接的方式是:

  1. 在查询前记录一次 getrusage()

  2. 执行查询;

  3. 查询后再次记录一次 getrusage()

  4. 对比两次记录的差值。

示例代码如下:

function getResourceUsageDiff($start, $end) {
    $diff = [];
    foreach ($end as $key => $value) {
        if (isset($start[$key])) {
            $diff[$key] = $value - $start[$key];
        }
    }
    return $diff;
}

$before = getrusage();

// 模拟数据库查询
$mysqli = new mysqli("localhost", "user", "password", "database");
$result = $mysqli->query("SELECT * FROM users WHERE email LIKE '%@example.com'");

$after = getrusage();

$usageDiff = getResourceUsageDiff($before, $after);

echo "<pre>";
print_r($usageDiff);
echo "
";

此代码可以输出查询所产生的系统资源变化。例如,如果你看到 ru_stime.tv_usec 明显上升,则说明该查询引起了系统态 CPU 的增加,可能存在大量 I/O 操作。


更直观的展示:函数封装与日志记录

为了更实用,可以将测量过程封装成一个函数,支持自动记录查询语句和资源变化:

function profileQuery($query, $mysqli) {
    $before = getrusage();

    $result = $mysqli->query($query);

    $after = getrusage();
    $usageDiff = getResourceUsageDiff($before, $after);

    file_put_contents("/var/log/db_profile.log", json_encode([
        'query' => $query,
        'usage' => $usageDiff,
        'time'  => date('c')
    ]) . PHP_EOL, FILE_APPEND);

    return $result;
}

这种方式可以让你在不打扰正常逻辑的同时,持续收集查询对系统资源的影响,从而为后续优化提供依据。


实践中的应用建议

  1. 对比不同索引结构的影响
    使用相同条件、不同索引结构的查询,比较系统资源占用,可以直观评估索引调整是否有效。

  2. 监控批量查询或大数据分页性能
    当面对分页或批量查询时,观察 ru_majfltru_nvcsw 是否增长,可以判断查询是否触发了大量内存调页或上下文切换。

  3. 在压力测试中对比资源使用
    配合 Apache Benchmark、JMeter 等工具进行并发测试,记录资源占用变化,分析系统在高负载下的表现。


附加:美化输出(调试用)

如果你希望调试时在浏览器中更清晰地查看 getrusage() 的变化,可以使用如下代码格式化输出:

function formatUsage(array $usage) {
    return sprintf(
        "User CPU: %.4fs, System CPU: %.4fs, Major Faults: %d, Voluntary CS: %d",
        $usage['ru_utime.tv_sec'] + $usage['ru_utime.tv_usec'] / 1e6,
        $usage['ru_stime.tv_sec'] + $usage['ru_stime.tv_usec'] / 1e6,
        $usage['ru_majflt'] ?? 0,
        $usage['ru_nvcsw'] ?? 0
    );
}

echo formatUsage($usageDiff);