performance_schema的介绍
performance schema提供了MySQL服务器内部运行操作上的底层指标。
performance_schema相关的概念
- 程序插桩(instrument)
程序插桩是指在MySQL带代码中插入的探测代码,以监控获取我们想要在MySQL运行过程中一系列相关的性能指标。
在performance_schema中,Setup_instruments表中包含了所有MySQL支持的插桩列表,所有的插桩名称都由斜杠分割的组件组成。如:statement/sql/select。其中statement表示插桩的类型为会话,其余部分从左向右依次表示从通用到特定的子系统。上述插桩则表示一个select查询。更多的插桩类型参考上面数据表。如下:
- 消费者表(consumer)
消费者表是用于存储程序插桩代码信息的表,例如:我们为查询模块添加程序插桩,那么对应的消费者表就将记录如执行总数、未使用索引的次数、花费的时间等信息。
如上图: 当应用程序连接到MySQL并执行被开启程序插桩的命令时, performance schema将每个结果记录在对应的消费者表中,由于程序插桩会执行额外的代码,所以程序插桩是会消耗额外的CPU资源。
消费者表
消费者表是插桩放送信息的目的地,结果都是存储在performance_schema数据库中的多个表上,基于这些表的不同作用可以做出如下分类:
-
当前和历史数据
- *_current: 当前服务器上进行的时间
- *_history: 每个线程最近完成的10个事件(可配置)
- *_history_long: 每个线程最近完成的10000个事件(可配置)
- events_wait: 底层服务器等待,如果获取互斥对象
- events_statements: SQL查询语句
- events_stage: 配置文件信息,如创建临时表或发送数据
- events_transactions: 事务信息
-
汇总表和摘要:
汇总表保存的是该表所关注的内容的聚合信息,如果用户连接或者后台线程的每个MySQL线程的集合内存使用情况保存在:memory_summary_by_thread_by_event_name.
而摘要则是通过删除查询中的变量来聚合查询的方法:
-- 那么id参数则为查询语句的变量
select * from users where user_id = 19;
-- 对应查询的摘要为
select * from users where user_id = ?;
通过摘要可以追踪一类查询的延迟相关指标, 而无需根据每一条SQL单体进行计算。
- 实例表
指的是对象实例,用于MySQL安装程序。 如果file_instance表包含文件名和访问这些文件的线程数。
- 设置表
用于设置performance_schema运行时的配置。
Performance schema的资源消耗和局限性
-
资源消耗: Performance schema将收集的数据保存在内存中, 而performance_schema中的某些表同样支持自动伸缩, 这意味着它们在启动时会分配最小内存, 然后根据需求调整大小,一旦分配内存,即使禁用某些插桩也不会释放该内存。同时,每个插桩指令都会添加两个宏调用,并将数据存储在performance_schema中,这意味着插桩越多,CPU使用率就会越高。
-
使用Performance_schema存在着局限性
- 必须得到MySQL组件的支持, 使用的插桩必须被调用的组件支持才能生效
- 难以释放内存, 消费者表可以自动伸缩并使用内存, 但禁用插桩并不能释放对应的内存。
理解MySQL的线程
MySQL服务端是多线程软件, 它的每个组件都可以使用线程。在performance_schema中的threads表中包含了服务器中存在的所有线程。每个线程至少有两个唯一标识符, 一个是操作系统的线程ID,另一个MySQL内部线程ID。而每个前台线程都有一个指定的连接标识符PROCESSLIST_ID与之关联。
- 系统线程: 通过
ps -eLf命令查看 - MySQL内部线程: 通过performance_schema表中的
THEAD_ID字段查看
Performance schema的配置
启用和禁用
-
启用或者禁用Performance schema
在配置文件中或者MySQL服务器启动的时通过命令参数对
performance_schema变量进行设置。 -
启用或禁用插桩
有三个方法可以用于启用和禁用插桩
- 对
setup_instruments表执行update语句 - 调用
sys schema中的ps_setup_enable_instrument存储过程 - 使用
performance-schema-instrument启动参数
- 对
-
启用或禁用消费者表
同样有三种方式可以用于启用或禁用消费者表
- 使用
Performance shcema中的setup_consumers表 - 调用
sys schema中的ps_setup_enable_consumer或者ps_setup_disable_consuper存储过程 - 使用
performance-schema-consumer启动参数
- 使用
配置与优化
-
优化特定对象的监控
Performance schema可以针对特定的对象:
EVENT、FUNCTION、PROCEDURE、TABLE、TRIGGER单独配置是否启用监控, 同时更可以指定OBJECT_CHEMA和OBJECT_NAME;如-- 关闭test数据库中所有触发器的监控 insert into performance_schema.setup_objects (OBJECT_TYPE,OBJECT_SCHEMA,OBJECT_NAME,ENABLED) values ('TRIGGER', 'test', '%', 'NO') -
优化线程的监控
setup_threads表包含了可以后台监控的线程列表,ENABLED列只开是否启用特定线程的监控。 -
调整Performance schema内存大小 Performance schema会将记录的数据存储在
performance_schema数据库的相关表中, 同时某些表支持自动调整大小。可以通过修改变量来控制这项选项。而变量遵循统一的命名格式如下:performance_schema_object_[size|instances|classes|length|handles]。如
performance_schema_events_stages_history_size定义了performance_schema_events_stages_history将存储的每个线程的阶段数。
如何分析Performance schema
检查SQL语句
检查SQL语可以通过标准预处理语句和存储用例的插桩, 检查SQL中引起性能问题的查询和原因, 如果要启用语句监测, 则需要启用statement类型的插桩。
-- 通过查询setup_instruments获取支持的程序插桩
select * from `performance_schema`.setup_instruments where `NAME` like 'statement/%';
-
检查常规SQL语句
常规语句相关的插桩
- statement/sql
- statement/sp
- statement/scheduler
- statement/com
- statement/abstract
Performance schema将语句指标存储在
events_statements_current、events_statements_history、events_statements_history_long这三张表中, 这些表具有相同的结构。
该表中一些关键性的性能指标列如下:
| 列 | 描述 | 重要性 |
|---|---|---|
CREATED_TMP_DISK_TABLES | 查询创建的磁盘临时表数量, 通过优化查询或者增加内存临时表的大小可以解决 | 高 |
CREATED_TMP_TABLES | 查询创建的内存临时表数量, 如果内存临时表的数量太多,超过内存临时表的空间,可能会转换成磁盘临时表 | 中 |
SELECT_FULL_JOIN | 因为没有合适的索引,所以导致join执行了全表扫描,需要考虑索引的设计 | 高 |
SELECT_FULL_RANGE_JOIN | json操作是否使用了被引用表的范围搜索 | 中 |
SELECT_RANGE | join操作是否使用了范围搜索来解析第一个表中的行 | 低 |
SELECT_RANGE_CHECK | join操作中没有索引,则会检查每一行之后的键,如果大于0,则需要考虑索引的设计 | 高 |
SELECT_SCAN | join操作对一个表使用了全表扫描,如果第一个表比较大会存在性能问题 | 中 |
SORT_MERGE_PASSES | 排序必须执行合并过程数, 可以通过增加sort_buffer_size的值来优化 | 低 |
SORT_RANGE | 是否使用的是范围查询 | 低 |
SORT_ROWS | 排序的行数,如果排序的行笔返回的行多,则需要优化查询 | 中 |
SORT_SCAN | 排序是否通过扫描表完成,除非有意选择表中的所有行,否则建议优化 | 高 |
NO_INDEX_USED | 查询时没有使用索引 | 高 |
NO_GOOD_INDEX_USED | 查询时索引不是最合适的, 如果大于0, 则需要重新考虑表的索引 | 高 |
使用sys chema来简化排查过程: sys schema提供了可以用于查找有问题语句的视图,如statements_with_errors_or_warnings存在错误与警告的语句、statements_with_full_table_scans存在需要全表扫描的语句。
- 检查预处理语句
预处理语句相关的插桩
- statement/sql/prepare_sql
- statement/sql/execute_sql
- statement/com/Prepare
- statement/com/Execute
prepared_statements_instances表中包含了服务器中存在的所有预处理语句, 它和events_statements_相关的表有着相同的统计数据, 同时还有语句所属的线程和被执行了多少次COUNT_EXECTE的信息。
-
检查存储过程
存储过程相关的插桩
- statement/sp/%
使用Performance_schema可以检索和存储过程有关的执行信息,例如某个
IF...ELSE分支被选择,或者调用了错误的程序。 -
语句剖析
语句剖析相关的插桩
- stage/%
event_stages_[current|history|history_long]表包含了语句剖析的内容,如创面临时表, 锁等待的时间.
检查读写性能
Performance_schema中的statements类型插桩对于理解工作负载是受读还是写的限制是非常有用的。可以分别通过各类型的统计语句来分析。例如
- 通过统计
EVENT_NAME的数量,来分析各种事件的数量分布:
select EVENT_NAME, count(EVENT_NAME) from events_statements_history_long group by EVENT_NAME;
- 通过
LOCK_TIME聚合来统计语句执行的延迟
select EVENT_NAME, sum(LOCK_TIME/1000000) l from events_statements_history_long group by EVENT_NAME order by l;
检查元数据锁
元数据锁是用于保护数据库对象的定义不被修改。执行任何SQL语句都需要获取共享元数据锁(DML), 如SELECT,UPDATE。但不会影响其他需要获取共享元数据锁的语句。但是共享元数据锁会阻止修改数据库对象定义的语句(DDL),如ALTER TABLE,CREATE INDEX。这些语句会阻塞直到共享元数据锁被释放。
需要注意DDL语句会隐式提交事务, 而事务执行期间会一直持有元数据锁
元数据锁监控的插桩
- wait/lock/meta-data/sql/mdl
performance_schema数据库中的metadata_locks包含不同线程设置的锁的信息以及处于等待状态的锁的请求信息。
检查内存使用情况
如果需要在performance_schema中启用内存监测,需要启动对应的程序插桩。然后就可以在performance_schema和sys schema中获取内存统计信息的数据。
内存监控的插桩
- memory/%
performance_schema中内存相关的统计数据存在于摘要表中,摘要表的名称以memory_summary_开头,分别可以有以下维度:
| 聚合参数 | 描述 |
|---|---|
| global | 按事件名全局集合 |
| thread | 按线程聚合 |
| account | 按用户账号聚合 |
| host | 按主机聚合 |
| user | 按用户名聚合 |
sys schema中的视图可以更方便的获取内存统计的相关信息。聚合视图存在于memory_global_total中记录了一个全局的内存总量,而下图中的视图分别对其他维度进行集合并以bytes进行记录。
检查变量
Performance schema提供了服务器、状态变量、用户变量多个级别的变量监控。
-
全局变量
全局变量被存储在
global_variables中,当前的会话的变量被存储在session_variables中,这两个表均只有两列VARIABLE_NAME、VARIABLE_VALUE,而线程的变量存储在variable_by_thread表中,该表具有一个THREAD_ID表示该变量所属的线程。variables_info中记录了服务器变量起源的信息和其他文档,如变量默认的最大值和最小值, 更新变量的时间戳等。 -
状态变量
全局和当前会话的状态值被存储在
global_status和session_status中,该表也同样只有两列VARIABLE_NAME、VARIABLE_VALUE。而线程的状态变量存储在status_by_thread表中。同样具有一个THREAD_ID表示该变量所属的线程。 -
用户变量
用户变量被存储在user_variables_by_thread中。
检查常见错误
Performance schema提供了摘要表,可以按用户、主机、账户、线程、和错误号聚合错误信息,所有的聚合表名称都类似于events_errors_summary_global_by_error。
检查Performance schema自身
如果需要使用程序插桩来检查Performance schema本身(默认情况下performance_schema数据库为默认数据库,MySQL不会对其查询进行跟踪),则需要先更新setup_actors表。其统计数据也将可以同上述的方式一样被查询。