深入 `Performance Schema`：`Events_waits`、`Events_statements` 和 `Events_transactions` 的`数据`采集机制。

admin
Fri, 05 Sep 2025 07:55:34 +0000
Mysql, events, performance, schema

好的，下面我们来深入探讨 Performance Schema 中的 Events_waits、Events_statements 和 Events_transactions 这三个关键表的数据采集机制。 Performance Schema 简介 Performance Schema 是 MySQL 服务器中一个用于监控服务器执行活动的特性。它通过收集各种事件的统计信息，帮助 DBA 和开发人员诊断性能问题，了解服务器内部的运行状况。Performance Schema 的数据采集机制围绕着 "事件" 展开，而 Events_waits、Events_statements 和 Events_transactions 这三个表分别记录了等待事件、语句事件和事务事件的信息。 事件采集的总体框架 Performance Schema 的事件采集过程大致如下： 事件源 (Instrumentation)：在 MySQL 服务器代码的关键位置插入 instrumentation，例如函数入口、出口、锁的获取和释放等。这些 instrumentation 点会触发事件的开始、 …

继续阅读“深入 `Performance Schema`：`Events_waits`、`Events_statements` 和 `Events_transactions` 的`数据`采集机制。”

The post 深入 `Performance Schema`：`Events_waits`、`Events_statements` 和 `Events_transactions` 的`数据`采集机制。 first appeared on 智猿学院-前后端，数据库，人工智能，云计算等领域前沿技术讲座.

好的，下面我们来深入探讨 Performance Schema 中的 Events_waits、Events_statements 和 Events_transactions 这三个关键表的数据采集机制。

Performance Schema 简介

Performance Schema 是 MySQL 服务器中一个用于监控服务器执行活动的特性。它通过收集各种事件的统计信息，帮助 DBA 和开发人员诊断性能问题，了解服务器内部的运行状况。Performance Schema 的数据采集机制围绕着 "事件" 展开，而 Events_waits、Events_statements 和 Events_transactions 这三个表分别记录了等待事件、语句事件和事务事件的信息。

事件采集的总体框架

Performance Schema 的事件采集过程大致如下：

1. 事件源 (Instrumentation)：在 MySQL 服务器代码的关键位置插入 instrumentation，例如函数入口、出口、锁的获取和释放等。这些 instrumentation 点会触发事件的开始、结束等动作。

2. 事件消费者 (Consumers)：Performance Schema 提供了一系列的消费者，用于接收和处理 instrumentation 产生的事件数据。Events_waits、Events_statements 和 Events_transactions 可以看作是不同类型的事件消费者。

3. 事件存储 (Storage)：消费者会将事件数据存储到相应的 Performance Schema 表中。这些表通常是内存表，以提高查询效率。

Events_waits：等待事件的数据采集

Events_waits 表记录了线程在执行过程中发生的等待事件。等待事件是指线程在等待某个资源或条件满足时发生的事件，例如等待锁、I/O 操作完成等。

Instrumentation 点：

锁等待： 当线程尝试获取锁但被阻塞时，会记录锁等待事件的开始。当线程成功获取锁时，会记录锁等待事件的结束。

I/O 等待： 当线程发起 I/O 请求后，会记录 I/O 等待事件的开始。当 I/O 请求完成时，会记录 I/O 等待事件的结束。

其他等待： 线程等待其他资源或条件时，例如等待网络连接、等待内存分配等，也会记录相应的等待事件。

数据采集流程：

1. 当线程进入等待状态时，相应的 instrumentation 点会调用 Performance Schema 的 API，记录等待事件的开始时间、等待的资源类型、等待的资源名称等信息。

2. 当线程结束等待状态时，相应的 instrumentation 点会再次调用 Performance Schema 的 API，记录等待事件的结束时间。

3. Performance Schema 会将等待事件的信息存储到 Events_waits 表中。

Events_waits 表结构示例：

Column Name | Data Type | Description
THREAD_ID | BIGINT UNSIGNED | 线程 ID
EVENT_ID | BIGINT UNSIGNED | 事件 ID
END_EVENT_ID | BIGINT UNSIGNED | 事件结束 ID
EVENT_NAME | VARCHAR(128) | 事件名称，例如 wait/synch/mutex/sql/TC_LOG_wait_commit
SOURCE | VARCHAR(64) | 触发事件的源代码位置
TIMER_START | BIGINT UNSIGNED | 事件开始时间 (皮秒)
TIMER_END | BIGINT UNSIGNED | 事件结束时间 (皮秒)
DURATION | BIGINT UNSIGNED | 事件持续时间 (皮秒)
WAIT_CLASS | VARCHAR(64) | 等待事件的类别，例如 idle, io, lock
WAIT_CLASS_NAME | VARCHAR(128) | 等待事件类别的名称
OBJECT_TYPE | VARCHAR(64) | 等待对象类型，例如 MUTEX, FILE
OBJECT_SCHEMA | VARCHAR(64) | 等待对象所属的 Schema
OBJECT_NAME | VARCHAR(512) | 等待对象名称，例如锁名称、文件名
NESTING_EVENT_ID | BIGINT UNSIGNED | 嵌套事件 ID
NESTING_EVENT_TYPE | ENUM | 嵌套事件类型，例如 STATEMENT, TRANSACTION, STAGE, WAIT, MUTEX_LOCK
INSTRUMENTED | ENUM | 指示该事件是否被 instrumented
MISSING_INSTRUMENT | ENUM | 指示该事件是否缺少 instrumentation

示例查询：

SELECT
    EVENT_NAME,
    COUNT(*) AS event_count,
    SUM(DURATION) AS total_duration,
    AVG(DURATION) AS avg_duration
FROM performance_schema.events_waits_summary_global_by_event_name
ORDER BY total_duration DESC
LIMIT 10;

这个查询会显示全局范围内，等待事件按总耗时排序的前 10 个事件。

Events_statements：语句事件的数据采集

Events_statements 表记录了 SQL 语句的执行信息，包括执行时间、锁等待时间、扫描的行数等。

Instrumentation 点：

语句开始： 当服务器开始执行一个 SQL 语句时，会记录语句事件的开始。

语句结束： 当服务器完成执行一个 SQL 语句时，会记录语句事件的结束。

锁等待： 在语句执行过程中，如果发生锁等待，会记录锁等待事件。

行扫描： 在语句执行过程中，如果需要扫描表中的行，会记录扫描的行数。

临时表创建/删除： 在语句执行过程中，创建或者删除临时表，会记录相关事件。

数据采集流程：

1. 当服务器开始执行一个 SQL 语句时，相应的 instrumentation 点会调用 Performance Schema 的 API，记录语句事件的开始时间、SQL 语句的内容、连接信息等。

2. 在语句执行过程中，如果发生锁等待、行扫描等事件，也会通过 Performance Schema 的 API 记录相关信息。

3. 当服务器完成执行一个 SQL 语句时，相应的 instrumentation 点会再次调用 Performance Schema 的 API，记录语句事件的结束时间、执行状态、错误信息等。

4. Performance Schema 会将语句事件的信息存储到 Events_statements 表中。

Events_statements 表结构示例：

Column Name | Data Type | Description
THREAD_ID | BIGINT UNSIGNED | 线程 ID
EVENT_ID | BIGINT UNSIGNED | 事件 ID
END_EVENT_ID | BIGINT UNSIGNED | 事件结束 ID
EVENT_NAME | VARCHAR(128) | 事件名称，通常为 statement/sql/<SQL command>
SOURCE | VARCHAR(64) | 触发事件的源代码位置
TIMER_START | BIGINT UNSIGNED | 事件开始时间 (皮秒)
TIMER_END | BIGINT UNSIGNED | 事件结束时间 (皮秒)
DURATION | BIGINT UNSIGNED | 事件持续时间 (皮秒)
LOCK_TIME | BIGINT UNSIGNED | 语句执行期间的锁等待时间 (皮秒)
ROWS_EXAMINED | BIGINT UNSIGNED | 语句执行期间扫描的行数
ROWS_SENT | BIGINT UNSIGNED | 语句执行期间发送的行数
ROWS_AFFECTED | BIGINT UNSIGNED | 语句执行期间影响的行数
DIGEST | VARCHAR(32) | SQL 语句的摘要，用于聚合相似的语句
DIGEST_TEXT | LONGTEXT | SQL 语句的文本，可能被截断
CURRENT_SCHEMA | VARCHAR(64) | 当前 Schema
OBJECT_TYPE | VARCHAR(64) | 对象类型
OBJECT_SCHEMA | VARCHAR(64) | 对象 Schema
OBJECT_NAME | VARCHAR(512) | 对象名称
NESTING_EVENT_ID | BIGINT UNSIGNED | 嵌套事件 ID
NESTING_EVENT_TYPE | ENUM | 嵌套事件类型，例如 STATEMENT, TRANSACTION, STAGE, WAIT, MUTEX_LOCK
INSTRUMENTED | ENUM | 指示该事件是否被 instrumented
MISSING_INSTRUMENT | ENUM | 指示该事件是否缺少 instrumentation
MYSQL_ERRNO | INT UNSIGNED | MySQL 错误码，如果发生错误
RETURNED_SQLSTATE | VARCHAR(5) | SQLSTATE 错误码，如果发生错误
MESSAGE_TEXT | TEXT | 错误信息，如果发生错误
ERRORS | BIGINT UNSIGNED | 错误计数
WARNINGS | BIGINT UNSIGNED | 警告计数
FIRST_SEEN | TIMESTAMP | 首次执行时间
LAST_SEEN | TIMESTAMP | 最近一次执行时间
EXECUTION_ENGINE | VARCHAR(64) | 执行引擎
VIEW_DEFINITION | LONGTEXT | 如果是 VIEW, 则包含 VIEW 的定义
TRACE | ENUM | 是否开启了 trace

示例查询：

SELECT
    DIGEST_TEXT,
    COUNT(*) AS exec_count,
    SUM(DURATION) AS total_duration,
    AVG(DURATION) AS avg_duration,
    SUM(ROWS_EXAMINED) AS total_rows_examined
FROM performance_schema.events_statements_summary_global_by_digest
ORDER BY total_duration DESC
LIMIT 10;

这个查询会显示全局范围内，SQL 语句按总执行时间排序的前 10 个语句。

Events_transactions：事务事件的数据采集

Events_transactions 表记录了事务的执行信息，包括事务的开始时间、结束时间、隔离级别等。

Instrumentation 点：

事务开始： 当服务器开始一个事务时 (例如执行 START TRANSACTION 语句)，会记录事务事件的开始。

事务提交： 当服务器提交一个事务时 (例如执行 COMMIT 语句)，会记录事务事件的提交。

事务回滚： 当服务器回滚一个事务时 (例如执行 ROLLBACK 语句)，会记录事务事件的回滚。

保存点设置/释放/回滚： 如果事务中使用了保存点，设置、释放、回滚保存点时会记录相关事件。

数据采集流程：

1. 当服务器开始一个事务时，相应的 instrumentation 点会调用 Performance Schema 的 API，记录事务事件的开始时间、连接信息、隔离级别等。

2. 当事务提交或回滚时，相应的 instrumentation 点会再次调用 Performance Schema 的 API，记录事务事件的结束时间、事务状态等。

3. Performance Schema 会将事务事件的信息存储到 Events_transactions 表中。

Events_transactions 表结构示例：

Column Name | Data Type | Description
THREAD_ID | BIGINT UNSIGNED | 线程 ID
EVENT_ID | BIGINT UNSIGNED | 事件 ID
END_EVENT_ID | BIGINT UNSIGNED | 事件结束 ID
EVENT_NAME | VARCHAR(128) | 事件名称，例如 transaction
SOURCE | VARCHAR(64) | 触发事件的源代码位置
TIMER_START | BIGINT UNSIGNED | 事件开始时间 (皮秒)
TIMER_END | BIGINT UNSIGNED | 事件结束时间 (皮秒)
DURATION | BIGINT UNSIGNED | 事件持续时间 (皮秒)
GTID | VARCHAR(64) | 全局事务ID
NESTING_EVENT_ID | BIGINT UNSIGNED | 嵌套事件 ID
NESTING_EVENT_TYPE | ENUM | 嵌套事件类型，例如 STATEMENT, TRANSACTION, STAGE, WAIT, MUTEX_LOCK
INSTRUMENTED | ENUM | 指示该事件是否被 instrumented
MISSING_INSTRUMENT | ENUM | 指示该事件是否缺少 instrumentation
MYSQL_ERRNO | INT UNSIGNED | MySQL 错误码，如果发生错误
RETURNED_SQLSTATE | VARCHAR(5) | SQLSTATE 错误码，如果发生错误
MESSAGE_TEXT | TEXT | 错误信息，如果发生错误

示例查询：

SELECT
    COUNT(*) AS transaction_count,
    SUM(DURATION) AS total_duration,
    AVG(DURATION) AS avg_duration
FROM performance_schema.events_transactions_summary_global;

这个查询会显示全局范围内，事务的总数、总执行时间和平均执行时间。

开启 Performance Schema

Performance Schema 默认情况下可能未启用。可以通过修改 MySQL 配置文件 (例如 my.cnf 或 my.ini) 来启用它。

performance_schema=ON
performance_schema_instrument='wait/%=ON'
performance_schema_instrument='statement/%=ON'
performance_schema_instrument='transaction/%=ON'

然后重启 MySQL 服务器。

调整 Performance Schema 的大小

Performance Schema 使用内存来存储事件数据。如果服务器上有大量的并发活动，可能需要增加 Performance Schema 的内存大小。可以通过以下参数进行调整：

performance_schema_events_waits_history_size：控制 Events_waits 表中保存的事件数量。

performance_schema_events_statements_history_size：控制 Events_statements 表中保存的事件数量。

performance_schema_events_transactions_history_size：控制 Events_transactions 表中保存的事件数量。

performance_schema_events_stages_history_size：控制 Events_stages 表中保存的事件数量。

可以在 MySQL 配置文件中设置这些参数，例如：

performance_schema_events_waits_history_size=10000
performance_schema_events_statements_history_size=10000
performance_schema_events_transactions_history_size=1000
performance_schema_events_stages_history_size=1000

重启 MySQL 服务器后，这些更改才会生效。请根据服务器的硬件资源和实际负载情况，合理设置这些参数。

使用建议和注意事项

性能开销： 启用 Performance Schema 会带来一定的性能开销，因为它需要收集和存储事件数据。在生产环境中，应该根据实际情况评估性能开销，并进行适当的调整。

数据清理： Performance Schema 的数据是存储在内存中的，服务器重启后会丢失。如果需要持久化存储事件数据，可以使用 MySQL 企业版提供的 Performance Schema 历史记录功能，或者将数据导出到其他存储介质中。

数据过滤： 可以通过配置 Performance Schema 的 instrument 和 consumers，来过滤掉不需要收集的事件，从而减少性能开销。

权限控制： 只有具有足够权限的用户才能访问 Performance Schema 的数据。应该合理控制用户权限，防止敏感数据泄露。

通过示例代码模拟事件采集

虽然我们不能直接修改 MySQL 服务器的代码来插入 instrumentation，但可以通过一个简单的 Python 示例来模拟事件采集的过程。

import time
import random

class Event:
    def __init__(self, event_type, start_time, duration, details=None):
        self.event_type = event_type
        self.start_time = start_time
        self.duration = duration
        self.end_time = start_time + duration
        self.details = details or {}

    def __repr__(self):
        return f"Event(type={self.event_type}, start={self.start_time}, duration={self.duration}, details={self.details})"

def simulate_wait_event():
    start_time = time.time()
    duration = random.uniform(0.01, 0.1) # 模拟 10ms - 100ms 的等待
    time.sleep(duration)
    return Event("wait", start_time, duration, {"wait_resource": "disk_io"})

def simulate_statement_event(sql_query):
    start_time = time.time()
    duration = random.uniform(0.05, 0.5) # 模拟 50ms - 500ms 的语句执行
    time.sleep(duration)
    rows_examined = random.randint(100, 1000)
    return Event("statement", start_time, duration, {"sql": sql_query, "rows_examined": rows_examined})

def simulate_transaction_event():
    start_time = time.time()
    duration = random.uniform(0.1, 1.0) # 模拟 100ms - 1s 的事务执行
    time.sleep(duration)
    return Event("transaction", start_time, duration)

# 模拟事件采集
for i in range(5):
    wait_event = simulate_wait_event()
    print(f"Collected wait event: {wait_event}")

    sql_query = f"SELECT * FROM users WHERE id = {random.randint(1, 1000)}"
    statement_event = simulate_statement_event(sql_query)
    print(f"Collected statement event: {statement_event}")

    if i % 2 == 0:
        transaction_event = simulate_transaction_event()
        print(f"Collected transaction event: {transaction_event}")

这个示例代码模拟了 Events_waits、Events_statements 和 Events_transactions 三种事件的采集。它使用 time.sleep() 函数来模拟事件的持续时间，并使用 random 模块来生成随机数据。虽然这只是一个简单的模拟，但它可以帮助我们更好地理解 Performance Schema 的事件采集过程。

数据采集的原理与应用

总而言之，Events_waits、Events_statements 和 Events_transactions 表的数据采集依赖于 MySQL 服务器代码中精心设计的 instrumentation。这些 instrumentation 点在关键时刻触发事件的开始和结束，Performance Schema 消费者负责接收和处理这些事件数据，并将其存储到相应的表中。通过查询这些表，我们可以深入了解服务器的性能瓶颈，优化 SQL 语句，并提高数据库的整体性能。

Performance Schema 是强大的性能分析工具

Performance Schema 提供了强大的性能分析功能，通过 Events_waits、Events_statements 和 Events_transactions 等表，可以深入了解 MySQL 服务器的运行状况。了解其数据采集机制，能更好的利用 Performance Schema 进行性能诊断和优化。

实践是最好的学习方法

建议在实际环境中启用 Performance Schema，并尝试使用各种查询来分析性能数据。通过实践，可以更深入地理解 Performance Schema 的功能和使用方法。