事件通过添加到服务器源代码中的仪器来收集。仪器计时事件,这就是性能模式提供事件持续时间概念的方式。还可以配置仪器,使其不收集计时信息。本节讨论可用的计时器及其特征,以及计时值在事件中的表示方式。
性能模式计时器的精度和开销各不相同。要查看可用的计时器及其特征,请查看 performance_timers
表
mysql> SELECT * FROM performance_schema.performance_timers;
+-------------+-----------------+------------------+----------------+
| TIMER_NAME | TIMER_FREQUENCY | TIMER_RESOLUTION | TIMER_OVERHEAD |
+-------------+-----------------+------------------+----------------+
| CYCLE | 2389029850 | 1 | 72 |
| NANOSECOND | 1000000000 | 1 | 112 |
| MICROSECOND | 1000000 | 1 | 136 |
| MILLISECOND | 1036 | 1 | 168 |
| THREAD_CPU | 339101694 | 1 | 798 |
+-------------+-----------------+------------------+----------------+
如果与给定计时器名称关联的值为 NULL
,则该计时器在您的平台上不受支持。
这些列具有以下含义
The
TIMER_NAME
列显示可用计时器的名称。CYCLE
指的是基于 CPU(处理器)周期计数器的计时器。TIMER_FREQUENCY
指示每秒的计时器单位数。对于周期计时器,频率通常与 CPU 速度相关。显示的值是在具有 2.4GHz 处理器的系统上获得的。其他计时器基于固定的秒分数。TIMER_RESOLUTION
指示计时器值每次增加的计时器单位数。如果计时器的分辨率为 10,则其值每次增加 10。TIMER_OVERHEAD
是使用给定计时器获得一次计时所需的最小开销周期数。每个事件的开销是显示值的兩倍,因为计时器在事件开始和结束时都会调用。
性能模式按以下方式分配计时器
等待计时器使用
CYCLE
。空闲、阶段、语句和事务计时器在平台上使用
NANOSECOND
(如果NANOSECOND
计时器可用),否则使用MICROSECOND
。
在服务器启动时,性能模式会验证在构建时关于计时器分配的假设是否正确,如果计时器不可用,则显示警告。
要计时等待事件,最重要的标准是减少开销,即使可能以计时器精度为代价,因此使用 CYCLE
计时器是最好的。
语句(或阶段)执行所需的时间通常比执行单个等待所需的时间大几个数量级。要计时语句,最重要的标准是获得一个不受处理器频率变化影响的精确度量,因此使用不基于周期的计时器是最好的。语句的默认计时器是 NANOSECOND
。与 CYCLE
计时器相比,额外的“开销”并不显着,因为调用计时器两次(一次在语句开始时,一次在语句结束时)造成的开销与执行语句本身所需的 CPU 时间相比要小几个数量级。在这里使用 CYCLE
计时器没有好处,只有缺点。
周期计数器提供的精度取决于处理器速度。如果处理器以 1 GHz(十亿个周期/秒)或更高的速度运行,则周期计数器提供亚纳秒精度。使用周期计数器比获取实际日期和时间要便宜得多。例如,标准 gettimeofday()
函数可能需要数百个周期,这对每秒可能发生数千或数百万次的數據收集来说是不可接受的开销。
周期计数器也有一些缺点
最终用户希望看到以挂钟单位(例如秒的分数)表示的计时。从周期转换为秒的分数可能很昂贵。因此,转换是一个快速且相当粗略的乘法运算。
处理器时钟频率可能会发生变化,例如笔记本电脑进入节能模式或 CPU 降低速度以减少热量产生时。如果处理器的时钟频率发生波动,从时钟周期转换为实时单位可能会出现误差。
根据处理器或操作系统,周期计数器可能不可靠或不可用。例如,在奔腾处理器上,指令是
RDTSC
(汇编语言指令,而不是 C 语言指令),理论上操作系统可以阻止用户模式程序使用它。一些与乱序执行或多处理器同步相关的处理器细节可能会导致计数器看起来快或慢,最多 1000 个周期。
MySQL 在 x386(Windows、macOS、Linux、Solaris 和其他 Unix 版本)、PowerPC 和 IA-64 上使用周期计数器。
性能模式表中存储当前事件和历史事件的行有三个列来表示计时信息:TIMER_START
和 TIMER_END
指示事件开始和结束的时间,TIMER_WAIT
指示事件持续时间。
setup_instruments
表有一个 ENABLED
列来指示要为其收集事件的仪器。该表还有一个 TIMED
列来指示哪些仪器进行计时。如果仪器未启用,则不会产生事件。如果启用的仪器未进行计时,则由该仪器产生的事件的 TIMER_START
、TIMER_END
和 TIMER_WAIT
计时器值为 NULL
。这反过来会导致在计算汇总表中的聚合时间值(总和、最小值、最大值和平均值)时忽略这些值。
在内部,事件中的时间以事件计时开始时有效的计时器的单位存储。当从性能模式表中检索事件时显示,时间以皮秒(万亿分之一秒)显示,以将它们规范化为标准单位,无论选择哪个计时器。
计时器基线(“时间零”)发生在服务器启动时性能模式初始化期间。事件中的 TIMER_START
和 TIMER_END
值表示自基线以来的皮秒数。TIMER_WAIT
值是皮秒持续时间。
事件中的皮秒值是近似值。它们的精度受到从一个单位转换为另一个单位的转换相关的常见误差形式的影响。如果使用 CYCLE
计时器且处理器速率发生变化,则可能会出现漂移。由于这些原因,将事件的 TIMER_START
值视为自服务器启动以来的准确时间度量是不合理的。另一方面,在 ORDER BY
子句中使用 TIMER_START
或 TIMER_WAIT
值来按开始时间或持续时间对事件进行排序是合理的。
在事件中选择皮秒而不是微秒等值具有性能基础。一个实现目标是在统一的时间单位中显示结果,而不管计时器如何。在理想情况下,这个时间单位看起来像一个挂钟单位,并且相当精确;换句话说,微秒。但是,要将周期或纳秒转换为微秒,有必要对每个仪器进行除法运算。除法在许多平台上都很昂贵。乘法并不昂贵,因此这就是使用的方法。因此,时间单位是最高可能 TIMER_FREQUENCY
值的整数倍,使用足够大的乘数以确保没有主要的精度损失。结果是时间单位是“皮秒。” 这种精度是虚假的,但这种决定使开销最小化。
当等待、阶段、语句或事务事件正在执行时,相应的当前事件表会显示当前事件计时信息
events_waits_current
events_stages_current
events_statements_current
events_transactions_current
为了能够确定尚未完成的事件运行了多长时间,计时器列设置如下
TIMER_START
已填充。TIMER_END
使用当前计时器值填充。TIMER_WAIT
使用迄今为止经过的时间填充 (TIMER_END
−TIMER_START
)。
尚未完成的事件的 END_EVENT_ID
值为 NULL
。要评估事件迄今为止经过的时间,请使用 TIMER_WAIT
列。因此,要识别尚未完成且迄今为止已运行超过 N
皮秒的事件,监控应用程序可以在查询中使用此表达式
WHERE END_EVENT_ID IS NULL AND TIMER_WAIT > N
正如上面所述的事件识别假设相应的仪器已将 ENABLED
和 TIMED
设置为 YES
并且相关的使用者已启用。