引言
在高负载下调优数据库性能是一个迭代循环的过程。每次进行更改以调优数据库的性能时,都需要了解更改是否有什么影响。*查询速度比以前快吗?锁是否会减慢应用程序的速度,或者是否已经完全消失了?内存使用情况改变了吗?等待磁盘的时间改变了吗?*一旦理解了如何回答这些问题,你将能够更快地评估和应对日常情况。
Performance Schema 是一个存储回答上述问题所需数据的数据库。本章将帮助你了解 Performance Schema 的工作原理、局限性,以及如何更好地使用它和 sys Schema 来搞清楚 MySQL 内部的运行细节。
Performance Schema介绍
Performance Schema提供了有关MySQL服务器内部运行的操作上的底层指标。在解释其工作机制前,先了解两个概念
- 程序插桩(instrument)
第一个概念是程序插桩。程序插桩是在 MySQL 代码中插入探测代码,以获取我们想了解的信息。例如,如果想收集关于元数据锁(MDL 锁)的使用情况,需要启用 wait/lock/meta-data/sql/mdl 这个插桩。
简单理解的话,可以将其当做关键位置的监控,如果开启MDL锁的程序插桩,每当MySQL加MDL锁、等待或释放MDL锁时,就会被记录。若关闭,则不会被记录。
- 消费者表(consumer)
第二个概念是消费者表(consumer),指的是存储关于程序插桩代码信息的表。如果我们为查询模块添加插桩,相应的消费者表将记录诸如执行总数、未使用索引的次数、花费的时间等信息。大多数人都将消费者表与 Performance Schema 紧密联系在一起。
简单理解的话,可以将其当做存放程序插桩数据的记录表,监控(程序插桩)采集到的数据必须存储在某个地方,而这个地方就是Consumer,也就是 Performance Schema 里的各种表。
Consumer 决定:采集到的数据要不要存、存到哪张表、存当前还是历史
两者的关系:必须同时开才有用
Instrument 打开 + Consumer 打开 = Performance Schema 生效
- 只开 Instrument,不开 Consumer → 数据采集了但不存,等于白采。
- 只开 Consumer,不开 Instrument → 表是空的,没有数据进来。
这就是为什么 Performance Schema 有两张关键配置表:
setup_instruments(控制探头)setup_consumers(控制记录表)
启用插桩会调用额外的代码,将会消耗额外的CPU资源。
插桩元件
在performance_schema中,setup_instruments表包含所有支持的插桩的列表。所有插桩的名称都由用斜杆分割的部件组成。比如:
-
statement/sql/select
-
wait/synch/mutex/innodb/autoinc_mutex
插桩名称的最左边部分表示插桩的类型。因此,statement表示插桩类型是statement,wait表示插桩类型是wait,以此类推。
名称字段中的其余部分从左至右依次表示从通用到特定的子系统。继续以前面的例子说明:
-
select是sql子系统的一部分,属于statement类型。
-
autoinc_mutex属于innodb,它是更通用的插桩类mutex的一部分,而mutex又是更通用的插桩类型wait的sync插桩的一部分。
setup_instruments 表
performance_schema的setup_instruments表是MySQL Performance Schema里控制所有插桩(instrument)开关的核心配置表。
可以简单理解为:
-
每一行代表一个可监控的事件类型(比如 SQL 执行、锁等待、内存分配、网络包接收等)
-
每一列是这个插桩的属性配置,决定它要不要采集数据、要不要计时、有什么特性
各列的含义:
| 列名 | 作用 | 核心说明 |
|---|---|---|
| NAME | 插桩的唯一名称 | 用 / 分层命名,比如 statement/sql/error,一眼就能看出是「SQL 语句类 → SQL 执行 → 错误」相关的监控 |
| ENABLED | 插桩是否启用 | YES= 开启(采集数据),NO= 关闭(不采集,零开销) |
| TIMED | 是否记录耗时 | YES= 采集事件的执行时间(用于统计耗时、慢查询),NULL= 该插桩不支持计时(比如内存类插桩) |
| PROPERTIES | 插桩的属性标签 | 标注插桩的特性,比如 mutable(可动态修改)、global_statistics(全局统计类) |
| VOLATILITY | 插桩的稳定性 / 开销等级 | 0 = 稳定、低开销(默认开启);1 = 可能有额外开销 / 不稳定(按需开启) |
| DOCUMENTATION | 插桩的官方说明 | 用自然语言解释这个插桩到底监控什么,是理解插桩作用的关键 |
查询示例:
|
|
对于许多插桩而言,DOCUMENTATION列可能为空,需要靠自己来理解插桩的作用。
消费者表的组织
消费者表是插桩发送信息的目的地。程序插桩的采集结果存储在Performance Schema数据库的多个表中,在MySQL 8.0.25社区版的performance_schema中包含110个表。基于它们的用途,可分为以下几个类别。
当前和历史数据
存放事件的表名包含如下结尾:
-
*_current当前服务器上进行中的事件。 -
*_history每个线程最近完成的 10 个事件。 -
*_history_long从全局来看,每个线程最近完成的 10000 个事件。
*_history 和*_history_long 表的大小是可配置的。
总结:
| 后缀 | 全称 | 核心作用 | 存储范围 | 可配置性 |
|---|---|---|---|---|
*_current |
当前表 | 存储正在执行中的事件 | 仅记录当前服务器上「未完成」的操作,事件执行完成后会从该表移除 | 不可手动配置大小,由 MySQL 自动维护 |
*_history |
历史表 | 存储最近完成的短周期事件 | 每个线程最多保留最近完成的 10 个事件(默认值),新事件会覆盖旧事件 | 可配置,通过 performance_schema_events_waits_history_size 等参数调整每个线程的保留条数 |
*_history_long |
长历史表 | 存储长期留存的全量事件 | 全局维度,每个线程最多保留最近完成的 10000 个事件(默认值),适合做历史分析 | 可配置,通过 performance_schema_events_waits_history_long_size 等参数调整全局保留条数 |
比如(以 SQL 语句为例):
events_statements_current:记录当前正在执行的 SQL,比如一个慢查询还没跑完,就能在这个表里看到它的执行进度、耗时等信息。
events_statements_history:每个线程执行完 SQL 后,会把这条 SQL 存入这个表,最多保留 10 条,适合排查「刚执行完的操作」。
events_statements_history_long:全局保留每个线程最近 10000 条执行完的 SQL,适合做历史性能分析,比如统计一天内的慢 SQL 分布。
MySQL 把事件按业务维度分成了 4 大类,每一类对应一套 *_current/*_history/*_history_long 表:
-
events_waits 记录底层服务器等待,例如获取互斥对象。是排查性能瓶颈的核心表。
-
events_statements 记录所有SQL查询语句,是最常用的性能分析表。
-
events_stages 记录SQL执行的内部阶段(SQL执行的每一步过程),例如创建临时表或发送数据。用来拆解 SQL 执行的全流程耗时。
-
events_transactions 记录所有事务的生命周期,是排查事务问题的核心表。
汇总表和摘要
汇总表保存有关该表所建议的内容的聚合信息。例如,memory_summary_by_thread_by_event_name表保存了用户连接或任何后台线程的每个MySQL线程的聚合内存使用情况。
摘要是一种通过删除查询中的变量来聚合查询的方法。例如以下查询:
|
|
该查询的摘要是:
|
|
这允许Performance Schema跟踪摘要的延迟等指标,而无须单独保留查询的每个变体。
实例表(Instance)
Instance(实例)指 MySQL运行时创建的对象实体。例如,file_instances表包含文件名和访问这些文件的线程数。
原文对实例表的描述:实例是指对象实例,用于MySQL安装程序。例如,file_instances表包含文件名和访问这些文件的线程数。
这本书的翻译质量似乎有所争议,我看着也挺吃力,未来有缘再看吧…