mita2 database life

主にMySQLに関するメモです

MySQL 8.0.28 で performance_schema に CPU_TIME が入った

MySQL 8.0.28 から performance_schemaCPU_TIME記録できるようになりました

これまでも実行時間は performance_schema から確認できていました。ただ、実行時間が長いだけでは、そのクエリが必ずしもCPUに負荷をかけているクエリとは言いきれませんでした。 今回の機能追加で、CPUに負荷をかけているクエリがバシっと performance_schema から確認できるようになったのは嬉しいですね(欲を言うと、CPU_TIME を スロークエリログにも出してほしいなぁ)。

デフォルトではOFFになっています。以下の設定を my.cnf に記述し、有効化します。

performance-schema-consumer-events-statements-cpu=ON

sys.statement_analysis にも cpu_latency が追加され、レスポンスタイムに占めるCPU時間が確認できます。 この例では total_time = cpu_latency になってます。テーブルが小さく、ほとんどIOの発生しないクエリだったため、このような結果になってます。

mysql> select * from sys.statement_analysis limit 1\G
*************************** 1. row ***************************
            query: SELECT SUM ( `salary` ) FROM `salaries`
               db: employees
        full_scan: *
       exec_count: 5
        err_count: 0
       warn_count: 0
    total_latency: 2.12 s
      max_latency: 523.29 ms
      avg_latency: 424.49 ms
     lock_latency: 17.00 us
      cpu_latency: 2.12 s
<snip>
1 row in set (0.00 sec)

total_letency != cpu_latency となりそうな、IOバウンドなクエリで試してみます*17.14 min のうち、cpu_latency15.80 s と IOに時間がかかったことが、しっかり読み取れました。

mysql> SELECT * FROM sbtest.sbtest1 WHERE c = 'X';
Empty set (7 min 5.33 sec)

mysql> select * from  sys.statement_analysis LIMIT 1\G
*************************** 1. row ***************************
            query: SELECT * FROM `sbtest` . `sbtest1` WHERE `c` = ?
               db: NULL
        full_scan: *
       exec_count: 2
        err_count: 1
       warn_count: 0
    total_latency: 7.14 min
      max_latency: 7.09 min
      avg_latency: 3.57 min
     lock_latency: 19.00 us
      cpu_latency: 15.80 s
<snip>

実装

CPU時間は clock_gettime() を利用して取得してる。

mysys/my_rdtsc.cc

/**
  THREAD_CPU timer.
  Expressed in nanoseconds.
*/
ulonglong my_timer_thread_cpu(void) {
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_THREAD_CPUTIME_ID)
  {
    struct timespec tp;
    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp);
    return (ulonglong)tp.tv_sec * 1000000000 + (ulonglong)tp.tv_nsec;
  }

*1:差が顕著に出るようにVMのIO帯域に制限かけました