當前位置: 首頁> 最新文章列表> 如何用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_majfl t 、 ru_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);