MySQL学习系列
1. 什么是 performance_schema
MySQL 的 performance_schema 是运行在较低级别的用于监控 MySQL Server运行过程中的资源消耗、 资源等待等情况的一个功能特性, 它具有以下特点。
2. performance_schema 使用
通过上面介绍, 相信你对于什么是 performance_schema 这个问题了解得更清晰了。 下面开始介绍 performance_schema 的使用。
检查当前数据库版本是否支持
performance_schema 被视为存储引擎, 如果该引擎可用, 则应该在INFORMATION_SCHEMA.ENGINES 表或 show engines 语句的输出中可以看到它的 Support 字段值为 YES, 如下所示。
mysql> show engines;
当我们看到 performance_schema 对应的 Support 字段值为 YES 时, 就表示当前的数据库版本是支持 performance_schema 的。 但确认了数据库实例支持performance_schema 存储引擎就可以使用了吗? NO, 很遗憾,performance_schema 在 MySQL 5.6 及之前的版本中默认没有启用, 在 MySQL 5.7及之后的版本中才修改为默认启用。
启用 performance_schema,如果要显式启用或关闭 performance_schema, 则需要使用参数performance_schema=ON|OFF 来设置, 并在 my.cnf 中进行配置。 注意:该参数为只读参数, 需要在实例启动之前设置才生效
mysqld 启动之后, 通过如下语句查看 performance_schema 启用是否生效(值为 ON 表示 performance_schema 已初始化成功且可以使用了; 值为 OFF 表示在启用 performance_schema 时发生某些错误, 可以查看错误日志进行排查) 。
show variables like 'performance_schema';
现在, 可以通过查询 INFORMATION_SCHEMA.TABLES 表中与performance_schema 存储引擎相关的元数据, 或者在 performance_schema 库下使用 show tables 语句来了解其存在哪些表。
使用 show tables 语句来查询有哪些 performance_schema 引擎表。
use performance_schema;
show tables;
mysql> use performance_schema;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+------------------------------------------------------+
| Tables_in_performance_schema |
+------------------------------------------------------+
| accounts |
| cond_instances |
| events_stages_current |
| events_stages_history |
| events_stages_history_long |
| events_stages_summary_by_account_by_event_name |
| events_stages_summary_by_host_by_event_name |
| events_stages_summary_by_thread_by_event_name |
| events_stages_summary_by_user_by_event_name |
| events_stages_summary_global_by_event_name |
| events_statements_current |
| events_statements_history |
| events_statements_history_long |
| events_statements_summary_by_account_by_event_name |
| events_statements_summary_by_digest |
| events_statements_summary_by_host_by_event_name |
| events_statements_summary_by_program |
| events_statements_summary_by_thread_by_event_name |
| events_statements_summary_by_user_by_event_name |
| events_statements_summary_global_by_event_name |
| events_transactions_current |
| events_transactions_history |
| events_transactions_history_long |
| events_transactions_summary_by_account_by_event_name |
| events_transactions_summary_by_host_by_event_name |
| events_transactions_summary_by_thread_by_event_name |
| events_transactions_summary_by_user_by_event_name |
| events_transactions_summary_global_by_event_name |
| events_waits_current |
| events_waits_history |
| events_waits_history_long |
| events_waits_summary_by_account_by_event_name |
| events_waits_summary_by_host_by_event_name |
| events_waits_summary_by_instance |
| events_waits_summary_by_thread_by_event_name |
| events_waits_summary_by_user_by_event_name |
| events_waits_summary_global_by_event_name |
| file_instances |
| file_summary_by_event_name |
| file_summary_by_instance |
| global_status |
| global_variables |
| host_cache |
| hosts |
| memory_summary_by_account_by_event_name |
| memory_summary_by_host_by_event_name |
| memory_summary_by_thread_by_event_name |
| memory_summary_by_user_by_event_name |
| memory_summary_global_by_event_name |
| metadata_locks |
| mutex_instances |
| objects_summary_global_by_type |
| performance_timers |
| prepared_statements_instances |
| replication_applier_configuration |
| replication_applier_status |
| replication_applier_status_by_coordinator |
| replication_applier_status_by_worker |
| replication_connection_configuration |
| replication_connection_status |
| replication_group_member_stats |
| replication_group_members |
| rwlock_instances |
| session_account_connect_attrs |
| session_connect_attrs |
| session_status |
| session_variables |
| setup_actors |
| setup_consumers |
| setup_instruments |
| setup_objects |
| setup_timers |
| socket_instances |
| socket_summary_by_event_name |
| socket_summary_by_instance |
| status_by_account |
| status_by_host |
| status_by_thread |
| status_by_user |
| table_handles |
| table_io_waits_summary_by_index_usage |
| table_io_waits_summary_by_table |
| table_lock_waits_summary_by_table |
| threads |
| user_variables_by_thread |
| users |
| variables_by_thread |
+------------------------------------------------------+
87 rows in set (0.00 sec)
mysql>
现在, 我们知道了在当前版本中, performance_schema 库下一共有 87 个表,那么这些表都用于存放什么数据呢? 我们如何使用它们来查询数据呢? 先来看看这些表是如何分类的。
3. performance_schema 表的分类
performance_schema 库下的表可以按照监视的不同维度进行分组, 例如:按照不同的数据库对象进行分组、 按照不同的事件类型进行分组, 或者按照事件类型分组之后, 再进一步按照账号、 主机、 程序、 线程、 用户等进行细分。
下面介绍按照事件类型分组记录性能事件数据的表
show tables like 'events_statement%';
show tables like 'events_wait%';
show tables like 'events_stage%';
show tables like 'events_transaction%';
show tables like '%file%';
show tables like '%memory%';
show tables like '%setup%';
现在, 我们已经大概知道了 performance_schema 中主要表的分类, 但如何使用这些表来提供性能事件数据呢?
4. performance_schema 简单配置与使用
当数据库初始化完成并启动时, 并非所有的 instruments( 在采集配置项的配置表中, 每一项都有一个开关字段, 或为 YES, 或为 NO) 和 consumers( 与采集配置项类似, 也有一个对应的事件类型保存表配置项, 为 YES 表示对应的表保存性能数据, 为 NO 表示对应的表不保存性能数据) 都启用了, 所以默认不会收集所有的事件。
可能你想检测的事件并没有打开, 需要进行设置。 可以使用如下两条语句打开对应的 instruments 和 consumers, 我们以配置监测等待事件数据为例进行说明。打开等待事件的采集器配置项开关, 需要修改 setup_instruments 配置表中对应的采集器配置项。
update setup_instruments set enabled='yes',timed='yes' where name like 'wait%';
打开等待事件的保存表配置项开关, 修改 setup_consumers 配置表中对应的配置项。
update setup_consumers set enabled='yes' where name like 'wait%';
配置好之后, 我们就可以查看 Server 当前正在做什么了。 可以通过查询events_waits_current 表来得知, 该表中每个线程只包含一行数据, 用于显示每个线程的最新监视事件(正在做的事情)。
mysql> select * from events_waits_current;
*_current 表中每个线程只保留一条记录, 且一旦线程完成工作, 该表中就不会再记录该线程的事件信息了。 *_history 表中记录每个线程已经执行完成的事件信息, 但每个线程的事件信息只记录 10 条, 再多就会被覆盖掉。 *_history_long表中记录所有线程的事件信息, 但总记录数量是 10000 行, 超过会被覆盖掉。summary 表提供所有事件的汇总信息。 该组中的表以不同的方式汇总事件数据(如: 按用户、 按主机、 按线程等汇总)。
查看最近执行失败的 SQL 语句
使用代码对数据库的某些操作(比如: 使用 Java 的 ORM 框架操作数据库)报出语法错误, 但是代码并没有记录 SQL 语句文本的功能, 在 MySQL 数据库层能否查看到具体的 SQL 语句文本, 看看是否哪里写错了? 这个时候, 大多数人首先想到的就是去查看错误日志。 很遗憾, 对于 SQL 语句的语法错误, 错误日志并不会记录。
实际上, 在 performance_schema 的语句事件记录表中针对每一条语句的执行状态都记录了较为详细的信息, 例如: events_statements_表和events_statements_summary_by_digest 表(events_statements_表记录了语句所有的执行错误信息, 而 events_statements_summary_by_digest 表只记录了语句在执行过程中发生错误的语句记录统计信息, 不记录具体的错误类型, 例如: 不记录语法错误类的信息)。 下面看看如何使用这两个表查询语句发生错误的语句信息。
首先, 我们模拟一条语法错误的 SQL 语句, 使用events_statements_history_long 表或者 events_statements_history 表查询发生语法错误的 SQL 语句:
select * from events_statements_history where mysql_errno=1064\G
mysql> select * from;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
mysql> select * from events_statements_history where mysql_errno=1064\G
*************************** 1. row ***************************
THREAD_ID: 40
EVENT_ID: 103
END_EVENT_ID: 103
EVENT_NAME: statement/sql/error
SOURCE:
TIMER_START: 37302918840295000
TIMER_END: 37302919128294000
TIMER_WAIT: 287999000
LOCK_TIME: 0
SQL_TEXT: select * from
DIGEST: NULL
DIGEST_TEXT: NULL
CURRENT_SCHEMA: performance_schema
OBJECT_TYPE: NULL
OBJECT_SCHEMA: NULL
OBJECT_NAME: NULL
OBJECT_INSTANCE_BEGIN: NULL
MYSQL_ERRNO: 1064
RETURNED_SQLSTATE: 42000
MESSAGE_TEXT: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use
ERRORS: 1
WARNINGS: 0
ROWS_AFFECTED: 0
ROWS_SENT: 0
ROWS_EXAMINED: 0
CREATED_TMP_DISK_TABLES: 0
CREATED_TMP_TABLES: 0
SELECT_FULL_JOIN: 0
SELECT_FULL_RANGE_JOIN: 0
SELECT_RANGE: 0
SELECT_RANGE_CHECK: 0
SELECT_SCAN: 0
SORT_MERGE_PASSES: 0
SORT_RANGE: 0
SORT_ROWS: 0
SORT_SCAN: 0
NO_INDEX_USED: 0
NO_GOOD_INDEX_USED: 0
NESTING_EVENT_ID: NULL
NESTING_EVENT_TYPE: NULL
NESTING_EVENT_LEVEL: 0
1 row in set (0.00 sec)
不知道错误号是多少, 可以查询发生错误次数不为 0 的语句记录, 在里边找到 SQL_TEXT 和 MESSAGE_TEXT 字段(提示信息为语法错误的就是它)
查看最近的事务执行信息
我们可以通过慢查询日志查询到一条语句的执行总时长, 但是如果数据库中存在着一些大事务在执行过程中回滚了, 或者在执行过程中异常中止, 这个时候慢查询日志就爱莫能助了, 这时我们可以借助 performance_schema 的events_transactions_*表来查看与事务相关的记录, 在这些表中详细记录了是否有事务被回滚、 活跃(长时间未提交的事务也属于活跃事务) 或已提交等信息。
首先需要进行配置启用, 事务事件默认并未启用
update setup_instruments set enabled='yes',timed='yes' where name like 'transaction%';
update setup_consumers set enabled='yes' where name like '%transaction%';
开启一个新会话(会话 2) 用于执行事务, 并模拟事务回滚。
查询活跃事务, 活跃事务表示当前正在执行的事务事件, 需要从events_transactions_current 表中查询。
SELECT * FROM performance_schema.events_transactions_current
mysql> SELECT * FROM events_transactions_current\G
*************************** 1. row ***************************
THREAD_ID: 40
EVENT_ID: 119
END_EVENT_ID: NULL
EVENT_NAME: transaction
STATE: ACTIVE
TRX_ID: NULL
GTID: AUTOMATIC
XID_FORMAT_ID: NULL
XID_GTRID: NULL
XID_BQUAL: NULL
XA_STATE: NULL
SOURCE:
TIMER_START: 37702351140472000
TIMER_END: 37990687037226000
TIMER_WAIT: 288335896754000
ACCESS_MODE: READ WRITE
ISOLATION_LEVEL: REPEATABLE READ
AUTOCOMMIT: NO
NUMBER_OF_SAVEPOINTS: 0
NUMBER_OF_ROLLBACK_TO_SAVEPOINT: 0
NUMBER_OF_RELEASE_SAVEPOINT: 0
OBJECT_INSTANCE_BEGIN: NULL
NESTING_EVENT_ID: 118
NESTING_EVENT_TYPE: STATEMENT
会话 2 中回滚事务:
查询事务事件当前表和事务事件历史记录表, 可以看到在两表中都记录了一行事务事件信息, 线程ID为40的线程执行了一个事务, 事务状态为ROLLED BACK。
mysql> SELECT * FROM events_transactions_current\G
*************************** 1. row ***************************
THREAD_ID: 40
EVENT_ID: 119
END_EVENT_ID: 121
EVENT_NAME: transaction
STATE: ROLLED BACK
TRX_ID: NULL
GTID: AUTOMATIC
XID_FORMAT_ID: NULL
XID_GTRID: NULL
XID_BQUAL: NULL
XA_STATE: NULL
SOURCE:
TIMER_START: 37702351140472000
TIMER_END: 38061121151922000
TIMER_WAIT: 358770011450000
ACCESS_MODE: READ WRITE
ISOLATION_LEVEL: REPEATABLE READ
AUTOCOMMIT: NO
NUMBER_OF_SAVEPOINTS: 0
NUMBER_OF_ROLLBACK_TO_SAVEPOINT: 0
NUMBER_OF_RELEASE_SAVEPOINT: 0
OBJECT_INSTANCE_BEGIN: NULL
NESTING_EVENT_ID: 118
NESTING_EVENT_TYPE: STATEMENT
但是当我们关闭会话 2 以后, 事务事件当前表中的记录就消失了。