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

好的,下面我们来深入探讨 Performance Schema 中的 Events_waitsEvents_statementsEvents_transactions 这三个关键表的数据采集机制。

Performance Schema 简介

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

事件采集的总体框架

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

  1. 事件源 (Instrumentation):在 MySQL 服务器代码的关键位置插入 instrumentation,例如函数入口、出口、锁的获取和释放等。这些 instrumentation 点会触发事件的开始、结束等动作。
  2. 事件消费者 (Consumers):Performance Schema 提供了一系列的消费者,用于接收和处理 instrumentation 产生的事件数据。Events_waitsEvents_statementsEvents_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.cnfmy.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_waitsEvents_statementsEvents_transactions 三种事件的采集。它使用 time.sleep() 函数来模拟事件的持续时间,并使用 random 模块来生成随机数据。虽然这只是一个简单的模拟,但它可以帮助我们更好地理解 Performance Schema 的事件采集过程。

数据采集的原理与应用

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

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

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

实践是最好的学习方法

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

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注