MySQL 优化之 Performance Schema
💽

MySQL 优化之 Performance Schema

Created
Mar 27, 2024 03:51 PM
Tags
在读《高性能MySQL》第三章遇到了很多新的东西,这里是对这部分知识的梳理。
正如书上所言
在高负载下调优数据库性能是一个迭代循环的过程。每次进行更改以调优数据库的性能时,都需要了解更改是否有什么影响。查询速度比以前快吗?锁是否会减慢应用程序的速度,或者是否已经完全消失了?内存使用情况改变了吗?等待磁盘的时间改变了吗?
Performance Schema 是一个存储回答上述问题所需数据的数据库。本章将帮助你了解Performance Schema的工作原理、局限性,以及如何更好地使用它和sys Schema来搞清楚MySQL内部的运行细节。

初识 Performance Schema

Performance Schema 作为 MySQL 中的一个组件,本质是一个存储引擎和一个数据库,通过它们提供了一种轻量级的方法来收集 MySQL 性能相关的信息,包括查询执行时间、锁等待情况、I/O 操作等,并存储在数据库中
Performance Schema 监视的是服务器事件,对于事件的定义,官方是这样解释的:
An “event” is anything the server does that takes time and has been instrumented so that timing information can be collected. In general, an event could be a function call, a wait for the operating system, a stage of an SQL statement execution such as parsing or sorting, or an entire statement or group of statements. Event collection provides access to information about synchronization calls (such as for mutexes) file and table I/O, table locks, and so forth for the server and for several storage engines.
Performance Schema events are distinct from events written to the server's binary log (which describe data modifications) and Event Scheduler events (which are a type of stored program).
用户可以可以通过查询 Performance Schema 中的数据表来获得详细的性能信息,用于定位性能瓶颈、优化性能
为了解释清楚 Performance Schema 的工作机制,先介绍两个概念。

instrument

第一个概念是程序插桩(instrument)。顾名思义,就是针对 MySQL 的一些活动插入探测代码,包括查询执行、锁等待、I/O 操作等。通过启用和配置不同的 instrument,可以捕获和记录数据库服务器中发生的各种事件,以便后续进行性能分析和优化。
在官方文档中:
The performance_schema storage engine collects event data using “instrumentation points” in server source code.
Collected events are stored in tables in the performance_schema database. These tables can be queried using SELECT statements like other tables.
在 Performance Schema 中,instrument 是通过事件+计数器来表示的。每个 instrument 对应于一种特定类型的数据库活动,而事件则是该活动发生时生成的记录。通过分析这些事件和计数器,可以了解数据库系统的运行情况,找出性能瓶颈并进行优化。
常见的 instrument 包括:
  1. Query Instrument:用于监控查询执行的活动,包括查询执行时间、扫描行数、索引使用情况等。
  1. Lock Instrument:用于监控锁的使用情况,包括锁等待时间、锁等待次数、锁类型等。
  1. File I/O Instrument:用于监控文件 I/O 操作,包括读取和写入文件的次数、字节数等。
  1. Table I/O Instrument:用于监控表的 I/O 操作,包括读取和写入表的次数、行数等。
例如,如果想收集关于元数据锁的使用情况,需要启用 wait/lock/meta-data/sql/mdl 这个插桩。

consumer

第二个概念是消费者表(consumer),指的是存储关于程序插桩代码信息的表。如果我们为查询模块添加插桩,相应的消费者表将记录诸如执行总数、未使用索引的次数、花费的时间等信息。大多数人都将消费者表与Performance Schema紧密联系在一起。也就是说,消费者表是插桩发送信息的目的地。测量结果存储在Performance Schema数据库的多个表中
基于它们的用途,可分为以下几个类别:
  • events_waits 底层服务器等待,例如获取互斥对象。
  • events_statements SQL查询语句。
  • events_stages 配置文件信息,例如创建临时表或发送数据。
  • events_transactions 事务。
存放事件的表名包含如下结尾:
*_current 当前服务器上进行中的事件。
*_history每个线程最近完成的10个事件。
*_history_long从全局来看,每个线程最近完成的10000个事件。
*_history和*_history_long表的大小是可配置的。
此外还有汇总表、摘要、设置表(Setup):
汇总表保存有关该表所建议的内容的聚合信息。例如,memory_summary_by_thread_by_event_name 表保存了用户连接或任何后台线程的每个MySQL线程的聚合内存使用情况。
而摘要是一种通过删除查询中的变量来聚合查询的方法。例如以下查询:
SELECT name, age FROM users WHERE user_id = 1; SELECT name, age FROM users WHERE user_id = 2; SELECT name, age FROM users WHERE user_id = 3;
它们的摘要是:
SELECT name, age FROM users WHERE user_id = ?;
这允许 Performance Schema 跟踪摘要的延迟等指标,而无须单独保留查询的每个变体。
最后,设置表 Setup 用于 performance_schema 的运行时设置。

资源消耗

关于这些表的存储,官方文档是这样描述的:
Tables in the Performance Schema are in-memory tables that use no persistent on-disk storage. The contents are repopulated beginning at server startup and discarded at server shutdown. Performance Schema 中的表是内存中的表,不使用持久的磁盘存储。内容在服务器启动时重新填充,在服务器关闭时丢弃。
Performance Schema 收集的数据保存在内存中。可以通过设置消费者表的最大大小来限制其使用的内存量。
performance_schema 中的一些表支持自动伸缩,这意味着它们在启动时分配最小数量的内存,并根据需要调整其大小。然而,一旦分配了内存,即使禁用了特定的插桩并截断了表,也不会再释放该内存。
而对于插桩,每个插桩指令的调用都会再添加两个宏调用,以将数据存储在performance_schema 中。这意味着插桩越多,CPU的使用率就越高。
对 CPU 使用率的实际影响取决于特定的插桩。例如,与 statement 相关的插桩在查询过程中只能被调用一次,而 wait 类插桩的被调用频率要高得多。例如,要扫描一个有一百万行的 InnoDB 表,引擎需要设置和释放一百万行锁。如果对锁使用 wait 类插桩,CPU使用率可能会显著增加。但是,这个查询只需要一次调用 statement/sql/select 插桩。因此,如果启用 statement 类插桩,你不会注意到CPU负载的任何增加。内存或元数据锁类型的插桩也是如此。

sys Schema

sys schema 是与 performance_schema 数据配套使用的,它基于 performance_schema 上的视图和存储例程组成。它的设计目的是让 performance_schema 体验更加流畅,本身并不存储任何数据

理解线程

MySQL服务端是多线程软件。它的每个组件都使用线程。可以是后台线程,例如,由主线程或存储引擎创建的,也可以是为用户连接创建的前台线程。
每个线程至少有两个唯一标识符:一个是操作系统线程 ID,另一个是 MySQL 内部线程ID
操作系统线程ID 可以通过相关工具查看,如在 Linux 系统中可使用 ps-eLf 命令查看。而 MySQL 内部线程 ID 在大多数 performance_schema 表中以 THREAD_ID 命名。此外,每个前台线程都有一个指定的 PROCESSLIST_ID:连接标识符,在 SHOW PROCESSLIST 命令输出中或在 MySQL 命令行客户端连接时在“Your MySQL connection id is”字符串中可以看到。
THREAD_ID 不等于 PROCESSLIST_ID!
performance_schema 中的 threads 表包含了服务器中存在的所有线程:
notion image
Performance Schema 到处使用 THREAD_ID,而 PROCESSLIST_ID 只在 threads 表中可用。如果需要获取 PROCESSLIST_ID,例如,要杀死持有锁的连接,则需要查询 threads 表来获取。

配置