事件通过添加到服务器源代码中的检测来收集。检测计时事件,这就是性能模式提供事件持续时间概念的方式。也可以配置检测不收集计时信息。本节讨论可用的计时器及其特性,以及计时值在事件中的表示方式。
性能模式计时器在精度和开销方面有所不同。要查看可用的计时器及其特性,请查看 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
,则该计时器在您的平台上不支持。
列具有以下含义
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
,并且相关的使用者已启用。