### 27.4.1 性能模式事件时序

事件是通过添加到服务器源代码的工具来收集的。检测时间事件，这就是 Performance Schema 如何提供事件需要多长时间的概念。也可以将仪器配置为不收集计时信息。本节讨论可用的计时器及其特性，以及计时值如何在事件中表示。

#### 性能模式计时器

性能模式计时器的精度和开销量各不相同。要查看可用的计时器及其特性，请查看[`性能计时器`](performance-schema-performance-timers-table.html)桌子：

```
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 |
+-------------+-----------------+------------------+----------------+
```

如果与给定计时器名称关联的值是`空值`，您的平台不支持该计时器。

这些列具有以下含义：

-   这`TIMER_NAME`列显示可用计时器的名称。`循环`指基于 CPU（处理器）周期计数器的定时器。

-   `TIMER_FREQUENCY`表示每秒的定时器单元数。对于循环定时器，频率一般与 CPU 速度有关。显示的值是在具有 2.4GHz 处理器的系统上获得的。其他计时器基于固定的秒数。

-   `TIMER_RESOLUTION`表示定时器值一次增加的定时器单位数。如果计时器的分辨率为 10，则其值每次增加 10。

-   `TIMER_OVERHEAD`是使用给定计时器获得一个计时的最小开销周期数。每个事件的开销是显示值的两倍，因为在事件开始和结束时调用了计时器。

    性能模式分配计时器如下：

-   等待计时器使用`循环`.

-   空闲、阶段、语句和事务计时器使用`纳秒`在平台上`纳秒`计时器可用，`微秒`否则。

    在服务器启动时，Performance Schema 验证在构建时所做的关于计时器分配的假设是否正确，并在计时器不可用时显示警告。

    对于等待事件的计时，最重要的标准是减少开销，但可能会牺牲计时器的准确性，因此使用`循环`计时器是最好的。

    执行语句（或阶段）所花费的时间通常比执行单个等待所花费的时间大几个数量级。对于时间语句，最重要的标准是有一个准确的度量，不受处理器频率变化的影响，因此使用不基于周期的计时器是最好的。语句的默认计时器是`纳秒`.与`循环`timer 并不重要，因为与执行语句本身所用的 CPU 时间相比，两次调用计时器（语句开始时一次，结束时一次）引起的开销要小几个数量级。使用`循环`计时器在这里没有好处，只有缺点。

    循环计数器提供的精度取决于处理器速度。如果处理器以 1 GHz（十亿周期/秒）或更高的频率运行，则周期计数器可提供亚纳秒精度。使用周期计数器比获取一天中的实际时间要便宜得多。例如，标准`gettimeofday()`函数可能需要数百个周期，这对于每秒可能发生数千或数百万次的数据收集来说是不可接受的开销。

    循环计数器也有缺点：

-   最终用户希望看到以挂钟为单位的计时，例如几分之一秒。从周期转换为几分之一秒可能会很昂贵。因此，转换是一种快速且相当粗略的乘法运算。

-   处理器循环率可能会发生变化，例如笔记本电脑进入省电模式或 CPU 减速以减少热量产生时。如果处理器的周期率波动，从周期到实时单位的转换会出错。

-   周期计数器可能不可靠或不可用，具体取决于处理器或操作系统。例如，在 Pentium 上，指令是`RDTSC`（一种汇编语言而不是 C 指令），理论上操作系统可以阻止用户模式程序使用它。

-   一些与乱序执行或多处理器同步相关的处理器细节可能会导致计数器看起来快或慢多达 1000 个周期。

    MySQL 在 x386（Windows、macOS、Linux、Solaris 和其他 Unix 风格）、PowerPC 和 IA-64 上使用循环计数器。

#### 事件中的性能模式计时器表示

存储当前事件和历史事件的 Performance Schema 表中的行具有三列来表示时序信息：`TIMER_START`和`TIMER_END`指示事件何时开始和结束，以及`TIMER_WAIT`表示事件持续时间。

这[`setup_instruments`](performance-schema-setup-instruments-table.html)表有一个`已启用`列以指示要为其收集事件的工具。该表还有一个`定时`列来指示哪些仪器是计时的。如果仪器未启用，则不会产生任何事件。如果启用的仪器没有计时，则仪器产生的事件有`空值`为了`TIMER_START`,`TIMER_END`， 和`TIMER_WAIT`定时器值。这反过来会导致在计算汇总表中的聚合时间值（总和、最小值、最大值和平均值）时忽略这些值。

在内部，事件内的时间以事件计时开始时有效的计时器给定的单位存储。为了在从性能模式表中检索事件时显示，时间以皮秒（万亿分之一秒）为单位显示，以将它们标准化为标准单位，而不管选择了哪个计时器。

计时器基线（“时间零点”）发生在服务器启动期间的性能模式初始化时。`定时器启动`和`计时器结束`事件中的值表示自基线起的皮秒。`等等`值是以皮秒为单位的持续时间。

事件中的皮秒值是近似值。它们的准确度取决于从一个单位转换到另一个单位的常见误差形式。如果`周期`如果使用定时器，处理器速率会发生变化，可能会出现漂移。基于这些原因，不合理的做法是`定时器启动`事件的值，作为服务器启动后经过的时间的精确度量。另一方面，使用`定时器启动`或`等等`价值观`订购人`子句按开始时间或持续时间对事件进行排序。

在事件中选择皮秒而不是微秒等值是基于性能的。一个实现目标是以统一的时间单位显示结果，而不考虑计时器。在一个理想的世界里，这个时间单位看起来像一个挂钟，而且相当精确；换句话说，微秒。但要将周期或纳秒转换为微秒，需要对每个仪器进行除法。在许多平台上，部门成本很高。乘法并不昂贵，所以使用乘法。因此，时间单位是最高可能值的整数倍`定时器频率`值，使用足够大的乘数，以确保没有重大精度损失。结果是时间单位为“皮秒”这种精度是虚假的，但这个决定可以使开销最小化。

在执行等待、阶段、语句或事务事件时，相应的当前事件表显示当前事件计时信息：

```
events_waits_current
events_stages_current
events_statements_current
events_transactions_current
```

为了确定尚未完成的事件已经运行了多长时间，计时器列设置如下：

-   `定时器启动`人口稠密。

-   `计时器结束`用当前计时器值填充。

-   `等等`填充了到目前为止经过的时间(`计时器结束` − `定时器启动`).

    尚未完成的事件具有`结束事件ID`价值`无效的`。要评估事件迄今为止所用的时间，请使用`等等`柱因此，要确定尚未完成且耗时超过*`N`*皮秒到目前为止，监控应用程序可以在查询中使用此表达式：


```
WHERE END_EVENT_ID IS NULL AND TIMER_WAIT > N
```

如上所述的事件识别假设相应的仪器`启用`和`定时的`开始`对`并且相关的消费者被启用。
