事件统计 | performance_schema全方位介绍

2020-09-18 18:15:52 浏览数 (3)

|  导语

在上一篇 《事件记录 | performance_schema全方位介绍"》中,我们详细介绍了performance_schema的事件记录表,恭喜大家在学习performance_schema的路上度过了两个最困难的时期。现在,相信大家已经比较清楚什么是事件了,但有时候我们不需要知道每时每刻产生的每一条事件记录信息, 例如:我们希望了解数据库运行以来一段时间的事件统计数据,这个时候就需要查看事件统计表了。今天将带领大家一起踏上系列第四篇的征程(全系共7个篇章),在这一期里,我们将为大家全面讲解performance_schema中事件统计表。统计事件表分为5个类别,分别为等待事件、阶段事件、语句事件、事务事件、内存事件。下面,请跟随我们一起开始performance_schema系统的学习之旅吧。

|  等待事件统计表

performance_schema把等待事件统计表按照不同的分组列(不同纬度)对等待事件相关的数据进行聚合(聚合统计数据列包括:事件发生次数,总等待时间,最小、最大、平均等待时间),注意:等待事件的采集功能有一部分默认是禁用的,需要的时候可以通过setup_instruments和setup_objects表动态开启,等待事件统计表包含如下几张表:

代码语言:javascript复制
admin@localhost : performance_schema 06:17:11> show tables like '%events_waits_summary%';
 ------------------------------------------------------- 
| Tables_in_performance_schema (%events_waits_summary%) |
 ------------------------------------------------------- 
| 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            |
 ------------------------------------------------------- 
6 rows in set (0.00 sec)

我们先来看看这些表中记录的统计信息是什么样子的。

代码语言:javascript复制
# events_waits_summary_by_account_by_event_name表
root@localhost : performance_schema 11:07:09> select * from events_waits_summary_by_account_by_event_name limit 1G
*************************** 1. row ***************************
      USER: NULL
      HOST: NULL
EVENT_NAME: wait/synch/mutex/sql/TC_LOG_MMAP::LOCK_tc
COUNT_STAR: 0
SUM_TIMER_WAIT: 0
MIN_TIMER_WAIT: 0
AVG_TIMER_WAIT: 0
MAX_TIMER_WAIT: 0
1 row in set (0.00 sec)
# events_waits_summary_by_host_by_event_name表
root@localhost : performance_schema 11:07:14> select * from events_waits_summary_by_host_by_event_name limit 1G
*************************** 1. row ***************************
      HOST: NULL
EVENT_NAME: wait/synch/mutex/sql/TC_LOG_MMAP::LOCK_tc
COUNT_STAR: 0
SUM_TIMER_WAIT: 0
MIN_TIMER_WAIT: 0
AVG_TIMER_WAIT: 0
MAX_TIMER_WAIT: 0
1 row in set (0.00 sec)
# events_waits_summary_by_instance表
root@localhost : performance_schema 11:08:05> select * from events_waits_summary_by_instance limit 1G
*************************** 1. row ***************************
       EVENT_NAME: wait/synch/mutex/mysys/THR_LOCK_heap
OBJECT_INSTANCE_BEGIN: 32492032
       COUNT_STAR: 0
   SUM_TIMER_WAIT: 0
   MIN_TIMER_WAIT: 0
   AVG_TIMER_WAIT: 0
   MAX_TIMER_WAIT: 0
1 row in set (0.00 sec)
# events_waits_summary_by_thread_by_event_name表
root@localhost : performance_schema 11:08:23> select * from events_waits_summary_by_thread_by_event_name limit 1G
*************************** 1. row ***************************
 THREAD_ID: 1
EVENT_NAME: wait/synch/mutex/sql/TC_LOG_MMAP::LOCK_tc
COUNT_STAR: 0
SUM_TIMER_WAIT: 0
MIN_TIMER_WAIT: 0
AVG_TIMER_WAIT: 0
MAX_TIMER_WAIT: 0
1 row in set (0.00 sec)
# events_waits_summary_by_user_by_event_name表
root@localhost : performance_schema 11:08:36> select * from events_waits_summary_by_user_by_event_name limit 1G
*************************** 1. row ***************************
      USER: NULL
EVENT_NAME: wait/synch/mutex/sql/TC_LOG_MMAP::LOCK_tc
COUNT_STAR: 0
SUM_TIMER_WAIT: 0
MIN_TIMER_WAIT: 0
AVG_TIMER_WAIT: 0
MAX_TIMER_WAIT: 0
1 row in set (0.00 sec)
# events_waits_summary_global_by_event_name表
root@localhost : performance_schema 11:08:53> select * from events_waits_summary_global_by_event_name limit 1G
*************************** 1. row ***************************
EVENT_NAME: wait/synch/mutex/sql/TC_LOG_MMAP::LOCK_tc
COUNT_STAR: 0
SUM_TIMER_WAIT: 0
MIN_TIMER_WAIT: 0
AVG_TIMER_WAIT: 0
MAX_TIMER_WAIT: 0
1 row in set (0.00 sec)

从上面表中的示例记录信息中,我们可以看到:

每个表都有各自的一个或多个分组列,以确定如何聚合事件信息(所有表都有EVENT_NAME列,列值与setup_instruments表中NAME列值对应),如下: 

events_waits_summary_by_account_by_event_name表:按照列EVENT_NAME、USER、HOST进行分组事件信息 

events_waits_summary_by_host_by_event_name表:按照列EVENT_NAME、HOST进行分组事件信息 

events_waits_summary_by_instance表:按照列EVENT_NAME、OBJECT_INSTANCE_BEGIN进行分组事件信息。如果一个instruments(event_name)创建有多个实例,则每个实例都具有唯一的OBJECT_INSTANCE_BEGIN值,因此每个实例会进行单独分组 

events_waits_summary_by_thread_by_event_name表:按照列THREAD_ID、EVENT_NAME进行分组事件信息 

events_waits_summary_by_user_by_event_name表:按照列EVENT_NAME、USER进行分组事件信息 

events_waits_summary_global_by_event_name表:按照EVENT_NAME列进行分组事件信息

所有表的统计列(数值型)都为如下几个:

COUNT_STAR:事件被执行的数量。此值包括所有事件的执行次数,需要启用等待事件的instruments 

SUM_TIMER_WAIT:统计给定计时事件的总等待时间。此值仅针对有计时功能的事件instruments或开启了计时功能事件的instruments,如果某事件的instruments不支持计时或者没有开启计时功能,则该字段为NULL。其他xxx_TIMER_WAIT字段值类似 

MIN_TIMER_WAIT:给定计时事件的最小等待时间 

AVG_TIMER_WAIT:给定计时事件的平均等待时间 

MAX_TIMER_WAIT:给定计时事件的最大等待时间

PS:等待事件统计表允许使用TRUNCATE TABLE语句。

执行该语句时有如下行为:

对于未按照帐户、主机、用户聚合的统计表,truncate语句会将统计列值重置为零,而不是删除行。

对于按照帐户、主机、用户聚合的统计表,truncate语句会删除已开端连接的帐户,主机或用户对应的行,并将其他有连接的行的统计列值重置为零(实测跟未按照帐号、主机、用户聚合的统计表一样,只会被重置不会被删除)。

此外,按照帐户、主机、用户、线程聚合的每个等待事件统计表或者events_waits_summary_global_by_event_name表,如果依赖的连接表(accounts、hosts、users表)执行truncate时,那么依赖的这些表中的统计数据也会同时被隐式truncate 。

注意:这些表只针对等待事件信息进行统计,即包含setup_instruments表中的wait/%开头的采集器 idle空闲采集器,每个等待事件在每个表中的统计记录行数需要看如何分组(例如:按照用户分组统计的表中,有多少个活跃用户,表中就会有多少条相同采集器的记录),另外,统计计数器是否生效还需要看setup_instruments表中相应的等待事件采集器是否启用。

|  阶段事件统计表

performance_schema把阶段事件统计表也按照与等待事件统计表类似的规则进行分类聚合,阶段事件也有一部分是默认禁用的,一部分是开启的,阶段事件统计表包含如下几张表:

代码语言:javascript复制
admin@localhost : performance_schema 06:23:02> show tables like '%events_stages_summary%';
 -------------------------------------------------------- 
| Tables_in_performance_schema (%events_stages_summary%) |
 -------------------------------------------------------- 
| 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            |
 -------------------------------------------------------- 
5 rows in set (0.00 sec)

我们先来看看这些表中记录的统计信息是什么样子的。

代码语言:javascript复制
# events_stages_summary_by_account_by_event_name表
root@localhost : performance_schema 11:21:04> select * from events_stages_summary_by_account_by_event_name where USER is not null limit 1G
*************************** 1. row ***************************
      USER: root
      HOST: localhost
EVENT_NAME: stage/sql/After create
COUNT_STAR: 0
SUM_TIMER_WAIT: 0
MIN_TIMER_WAIT: 0
AVG_TIMER_WAIT: 0
MAX_TIMER_WAIT: 0
1 row in set (0.01 sec)
# events_stages_summary_by_host_by_event_name表
root@localhost : performance_schema 11:29:27> select * from events_stages_summary_by_host_by_event_name where HOST is not null limit 1G
*************************** 1. row ***************************
      HOST: localhost
EVENT_NAME: stage/sql/After create
COUNT_STAR: 0
SUM_TIMER_WAIT: 0
MIN_TIMER_WAIT: 0
AVG_TIMER_WAIT: 0
MAX_TIMER_WAIT: 0
1 row in set (0.00 sec)
# events_stages_summary_by_thread_by_event_name表
root@localhost : performance_schema 11:37:03> select * from events_stages_summary_by_thread_by_event_name where thread_id is not null limit 1G
*************************** 1. row ***************************
 THREAD_ID: 1
EVENT_NAME: stage/sql/After create
COUNT_STAR: 0
SUM_TIMER_WAIT: 0
MIN_TIMER_WAIT: 0
AVG_TIMER_WAIT: 0
MAX_TIMER_WAIT: 0
1 row in set (0.01 sec)
# events_stages_summary_by_user_by_event_name表
root@localhost : performance_schema 11:42:37> select * from events_stages_summary_by_user_by_event_name where user is not null limit 1G
*************************** 1. row ***************************
      USER: root
EVENT_NAME: stage/sql/After create
COUNT_STAR: 0
SUM_TIMER_WAIT: 0
MIN_TIMER_WAIT: 0
AVG_TIMER_WAIT: 0
MAX_TIMER_WAIT: 0
1 row in set (0.00 sec)
# events_stages_summary_global_by_event_name表
root@localhost : performance_schema 11:43:03> select * from events_stages_summary_global_by_event_name limit 1G
*************************** 1. row ***************************
EVENT_NAME: stage/sql/After create
COUNT_STAR: 0
SUM_TIMER_WAIT: 0
MIN_TIMER_WAIT: 0
AVG_TIMER_WAIT: 0
MAX_TIMER_WAIT: 0
1 row in set (0.00 sec)

从上面表中的示例记录信息中,我们可以看到,同样与等待事件类似,按照用户、主机、用户 主机、线程等纬度进行分组与统计的列,这些列的含义与等待事件类似,这里不再赘述。

注意:这些表只针对阶段事件信息进行统计,即包含setup_instruments表中的stage/%开头的采集器,每个阶段事件在每个表中的统计记录行数需要看如何分组(例如:按照用户分组统计的表中,有多少个活跃用户,表中就会有多少条相同采集器的记录),另外,统计计数器是否生效还需要看setup_instruments表中相应的阶段事件采集器是否启用。

PS:对这些表使用truncate语句,影响与等待事件类似。

|  事务事件统计表

performance_schema把事务事件统计表也按照与等待事件统计表类似的规则进行分类统计,事务事件instruments只有一个transaction,默认禁用,事务事件统计表有如下几张表:

代码语言:javascript复制
admin@localhost : performance_schema 06:37:45> show tables like '%events_transactions_summary%';
 -------------------------------------------------------------- 
| Tables_in_performance_schema (%events_transactions_summary%) |
 -------------------------------------------------------------- 
| 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            |
 -------------------------------------------------------------- 
5 rows in set (0.00 sec)

我们先来看看这些表中记录的统计信息是什么样子的(由于单行记录较长,这里只列出events_transactions_summary_by_account_by_event_name表中的示例数据,其余表的示例数据省略掉部分相同字段)。

代码语言:javascript复制
# events_transactions_summary_by_account_by_event_name表
root@localhost : performance_schema 01:19:07> select * from events_transactions_summary_by_account_by_event_name where COUNT_STAR!=0 limit 1G
*************************** 1. row ***************************
            USER: root
            HOST: localhost
      EVENT_NAME: transaction
      COUNT_STAR: 7
  SUM_TIMER_WAIT: 8649707000
  MIN_TIMER_WAIT: 57571000
  AVG_TIMER_WAIT: 1235672000
  MAX_TIMER_WAIT: 2427645000
COUNT_READ_WRITE: 6
SUM_TIMER_READ_WRITE: 8592136000
MIN_TIMER_READ_WRITE: 87193000
AVG_TIMER_READ_WRITE: 1432022000
MAX_TIMER_READ_WRITE: 2427645000
 COUNT_READ_ONLY: 1
SUM_TIMER_READ_ONLY: 57571000
MIN_TIMER_READ_ONLY: 57571000
AVG_TIMER_READ_ONLY: 57571000
MAX_TIMER_READ_ONLY: 57571000
1 row in set (0.00 sec)
# events_transactions_summary_by_host_by_event_name表
root@localhost : performance_schema 01:25:13> select * from events_transactions_summary_by_host_by_event_name where COUNT_STAR!=0 limit 1G
*************************** 1. row ***************************
            HOST: localhost
      EVENT_NAME: transaction
      COUNT_STAR: 7
......
1 row in set (0.00 sec)
# events_transactions_summary_by_thread_by_event_name表
root@localhost : performance_schema 01:25:27> select * from events_transactions_summary_by_thread_by_event_name where SUM_TIMER_WAIT!=0G
*************************** 1. row ***************************
       THREAD_ID: 46
      EVENT_NAME: transaction
      COUNT_STAR: 7
......
1 row in set (0.00 sec)
# events_transactions_summary_by_user_by_event_name表
root@localhost : performance_schema 01:27:27> select * from events_transactions_summary_by_user_by_event_name where SUM_TIMER_WAIT!=0G
*************************** 1. row ***************************
            USER: root
      EVENT_NAME: transaction
      COUNT_STAR: 7
......
1 row in set (0.00 sec)
# events_transactions_summary_global_by_event_name表
root@localhost : performance_schema 01:27:32> select * from events_transactions_summary_global_by_event_name where SUM_TIMER_WAIT!=0G
*************************** 1. row ***************************
      EVENT_NAME: transaction
      COUNT_STAR: 7
......
1 row in set (0.00 sec)

从上面表中的示例记录信息中,我们可以看到,同样与等待事件类似,按照用户、主机、用户 主机、线程等纬度进行分组与统计的列,这些列的含义与等待事件类似,这里不再赘述,但对于事务统计事件,针对读写事务和只读事务还单独做了统计(xx_READ_WRITE和xx_READ_ONLY列,只读事务需要设置只读事务变量transaction_read_only=on才会进行统计)。

注意:这些表只针对事务事件信息进行统计,即包含且仅包含setup_instruments表中的transaction采集器,每个事务事件在每个表中的统计记录行数需要看如何分组(例如:按照用户分组统计的表中,有多少个活跃用户,表中就会有多少条相同采集器的记录),另外,统计计数器是否生效还需要看transaction采集器是否启用。

事务聚合统计规则 

* 事务事件的收集不考虑隔离级别,访问模式或自动提交模式 

* 读写事务通常比只读事务占用更多资源,因此事务统计表包含了用于读写和只读事务的单独统计列 

* 事务所占用的资源需求多少也可能会因事务隔离级别有所差异(例如:锁资源)。但是:每个server可能是使用相同的隔离级别,所以不单独提供隔离级别相关的统计列

PS:对这些表使用truncate语句,影响与等待事件类似。

|  语句事件统计表

performance_schema把语句事件统计表也按照与等待事件统计表类似的规则进行分类统计,语句事件instruments默认全部开启,所以,语句事件统计表中默认会记录所有的语句事件统计信息,语句事件统计表包含如下几张表:

events_statements_summary_by_account_by_event_name:按照每个帐户和语句事件名称进行统计

events_statements_summary_by_digest:按照每个库级别对象和语句事件的原始语句文本统计值(md5 hash字符串)进行统计,该统计值是基于事件的原始语句文本进行精炼(原始语句转换为标准化语句),每行数据中的相关数值字段是具有相同统计值的统计结果。

events_statements_summary_by_host_by_event_name:按照每个主机名和事件名称进行统计的Statement事件

events_statements_summary_by_program:按照每个存储程序(存储过程和函数,触发器和事件)的事件名称进行统计的Statement事件

events_statements_summary_by_thread_by_event_name:按照每个线程和事件名称进行统计的Statement事件

events_statements_summary_by_user_by_event_name:按照每个用户名和事件名称进行统计的Statement事件

events_statements_summary_global_by_event_name:按照每个事件名称进行统计的Statement事件

prepared_statements_instances:按照每个prepare语句实例聚合的统计信息

可通过如下语句查看语句事件统计表:

代码语言:javascript复制
admin@localhost : performance_schema 06:27:58> show tables like '%events_statements_summary%';
 ------------------------------------------------------------ 
| Tables_in_performance_schema (%events_statements_summary%) |
 ------------------------------------------------------------ 
| 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            |
 ------------------------------------------------------------ 
7 rows in set (0.00 sec)
admin@localhost : performance_schema 06:28:48> show tables like '%prepare%';
 ------------------------------------------ 
| Tables_in_performance_schema (%prepare%) |
 ------------------------------------------ 
| prepared_statements_instances            |
 ------------------------------------------ 
1 row in set (0.00 sec)

我们先来看看这些表中记录的统计信息是什么样子的(由于单行记录较长,这里只列出events_statements_summary_by_account_by_event_name 表中的示例数据,其余表的示例数据省略掉部分相同字段)。

代码语言:javascript复制
# events_statements_summary_by_account_by_event_name表
root@localhost : performance_schema 10:37:27> select * from events_statements_summary_by_account_by_event_name where COUNT_STAR!=0 limit 1G
*************************** 1. row ***************************
                   USER: root
                   HOST: localhost
             EVENT_NAME: statement/sql/select
             COUNT_STAR: 53
         SUM_TIMER_WAIT: 234614735000
         MIN_TIMER_WAIT: 72775000
         AVG_TIMER_WAIT: 4426693000
         MAX_TIMER_WAIT: 80968744000
          SUM_LOCK_TIME: 26026000000
             SUM_ERRORS: 2
           SUM_WARNINGS: 0
      SUM_ROWS_AFFECTED: 0
          SUM_ROWS_SENT: 1635
      SUM_ROWS_EXAMINED: 39718
SUM_CREATED_TMP_DISK_TABLES: 3
 SUM_CREATED_TMP_TABLES: 10
   SUM_SELECT_FULL_JOIN: 21
SUM_SELECT_FULL_RANGE_JOIN: 0
       SUM_SELECT_RANGE: 0
 SUM_SELECT_RANGE_CHECK: 0
        SUM_SELECT_SCAN: 45
  SUM_SORT_MERGE_PASSES: 0
         SUM_SORT_RANGE: 0
          SUM_SORT_ROWS: 170
          SUM_SORT_SCAN: 6
      SUM_NO_INDEX_USED: 42
 SUM_NO_GOOD_INDEX_USED: 0
1 row in set (0.00 sec)
# events_statements_summary_by_digest表
root@localhost : performance_schema 11:01:51> select * from events_statements_summary_by_digest limit 1G
*************************** 1. row ***************************
            SCHEMA_NAME: NULL
                 DIGEST: 4fb483fe710f27d1d06f83573c5ce11c
            DIGEST_TEXT: SELECT @@`version_comment` LIMIT ?
             COUNT_STAR: 3
......
             FIRST_SEEN: 2018-05-19 22:33:50
              LAST_SEEN: 2018-05-20 10:24:42
1 row in set (0.00 sec)
# events_statements_summary_by_host_by_event_name表
root@localhost : performance_schema 11:02:15> select * from events_statements_summary_by_host_by_event_name where COUNT_STAR!=0 limit 1G
*************************** 1. row ***************************
                   HOST: localhost
             EVENT_NAME: statement/sql/select
             COUNT_STAR: 55
......
1 row in set (0.00 sec)
# events_statements_summary_by_program表(需要调用了存储过程或函数之后才会有数据)
root@localhost : performance_schema 12:34:43> select * from events_statements_summary_by_programG;
*************************** 1. row ***************************
            OBJECT_TYPE: PROCEDURE
          OBJECT_SCHEMA: sys
            OBJECT_NAME: ps_setup_enable_consumer
            COUNT_STAR: 1
............
1 row in set (0.00 sec)
# events_statements_summary_by_thread_by_event_name表
root@localhost : performance_schema 11:03:19> select * from events_statements_summary_by_thread_by_event_name where COUNT_STAR!=0 limit 1G
*************************** 1. row ***************************
              THREAD_ID: 47
             EVENT_NAME: statement/sql/select
             COUNT_STAR: 11
......
1 row in set (0.01 sec)
# events_statements_summary_by_user_by_event_name表
root@localhost : performance_schema 11:04:10> select * from events_statements_summary_by_user_by_event_name where COUNT_STAR!=0 limit 1G
*************************** 1. row ***************************
                   USER: root
             EVENT_NAME: statement/sql/select
             COUNT_STAR: 58
......
1 row in set (0.00 sec)
# events_statements_summary_global_by_event_name表
root@localhost : performance_schema 11:04:31> select * from events_statements_summary_global_by_event_name limit 1G
*************************** 1. row ***************************
             EVENT_NAME: statement/sql/select
             COUNT_STAR: 59
......
1 row in set (0.00 sec)

从上面表中的示例记录信息中,我们可以看到,同样与等待事件类似,按照用户、主机、用户 主机、线程等纬度进行分组与统计的列,分组和部分时间统计列与等待事件类似,这里不再赘述,但对于语句统计事件,有针对语句对象的额外的统计列,如下:

SUM_xxx:针对events_statements_*事件记录表中相应的xxx列进行统计。例如:语句统计表中的SUM_LOCK_TIME和SUM_ERRORS列对events_statements_current事件记录表中LOCK_TIME和ERRORS列进行统计

events_statements_summary_by_digest表有自己额外的统计列:

* FIRST_SEEN,LAST_SEEN:显示某给定语句第一次插入       events_statements_summary_by_digest表和最后一次更新该表的时间戳

events_statements_summary_by_program表有自己额外的统计列:

* COUNT_STATEMENTS,SUM_STATEMENTS_WAIT,MIN_STATEMENTS_WAIT,AVG_STATEMENTS_WAIT,MAX_STATEMENTS_WAIT:关于存储程序执行期间调用的嵌套语句的统计信息

prepared_statements_instances表有自己额外的统计列:

* COUNT_EXECUTE,SUM_TIMER_EXECUTE,MIN_TIMER_EXECUTE,AVG_TIMER_EXECUTE,MAX_TIMER_EXECUTE:执行prepare语句对象的统计信息

PS1:

关于events_statements_summary_by_digest表

如果setup_consumers配置表中statements_digest consumers启用,则在语句执行完成时,将会把语句文本进行md5 hash计算之后 再发送到events_statements_summary_by_digest表中。分组列基于该语句的DIGEST列值(md5 hash值) 

* 如果给定语句的统计信息行在events_statements_summary_by_digest表中已经存在,则将该语句的统计信息进行更新,并更新LAST_SEEN列值为当前时间 

* 如果给定语句的统计信息行在events_statements_summary_by_digest表中没有已存在行,并且events_statements_summary_by_digest表空间限制未满的情况下,会在events_statements_summary_by_digest表中新插入一行统计信息,FIRST_SEEN和LAST_SEEN列都使用当前时间 

* 如果给定语句的统计信息行在events_statements_summary_by_digest表中没有已存在行,且events_statements_summary_by_digest表空间限制已满的情况下,则该语句的统计信息将添加到DIGEST 列值为 NULL的特殊“catch-all”行,如果该特殊行不存在则新插入一行,FIRST_SEEN和LAST_SEEN列为当前时间。如果该特殊行已存在则更新该行的信息,LAST_SEEN为当前时间

由于performance_schema表内存限制,所以维护了DIGEST = NULL的特殊行。 当events_statements_summary_by_digest表限制容量已满的情况下,且新的语句统计信息在需要插入到该表时又没有在该表中找到匹配的DIGEST列值时,就会把这些语句统计信息都统计到 DIGEST = NULL的行中。此行可帮助您估算events_statements_summary_by_digest表的限制是否需要调整

* 如果DIGEST = NULL行的COUNT_STAR列值占据整个表中所有统计信息的COUNT_STAR列值的比例大于0%,则表示存在由于该表限制已满导致部分语句统计信息无法分类保存,如果你需要保存所有语句的统计信息,可以在server启动之前调整系统变量performance_schema_digests_size的值,默认大小为200

PS2:关于存储程序监控行为:对于在setup_objects表中启用了instruments的存储程序类型,events_statements_summary_by_program将维护存储程序的统计信息,如下所示:

当某给定对象在server中首次被使用时(即使用call语句调用了存储过程或自定义存储函数时),将在events_statements_summary_by_program表中添加一行统计信息;

当某给定对象被删除时,该对象在events_statements_summary_by_program表中的统计信息行将被删除;

当某给定对象被执行时,其对应的统计信息将记录在events_statements_summary_by_program表中并进行统计。

PS3:对这些表使用truncate语句,影响与等待事件类似。

|  内存事件统计表

performance_schema把内存事件统计表也按照与等待事件统计表类似的规则进行分类统计。

performance_schema会记录内存使用情况并聚合内存使用统计信息,如:使用的内存类型(各种缓存,内部缓冲区等)和线程、帐号、用户、主机的相关操作间接执行的内存操作。performance_schema从使用的内存大小、相关操作数量、高低水位(内存一次操作的最大和最小的相关统计值)。

内存大小统计信息有助于了解当前server的内存消耗,以便及时进行内存调整。内存相关操作计数有助于了解当前server的内存分配器的整体压力,及时掌握server性能数据。例如:分配单个字节一百万次与单次分配一百万个字节的性能开销是不同的,通过跟踪内存分配器分配的内存大小和分配次数就可以知道两者的差异。

检测内存工作负载峰值、内存总体的工作负载稳定性、可能的内存泄漏等是至关重要的。

内存事件instruments中除了performance_schema自身内存分配相关的事件instruments配置默认开启之外,其他的内存事件instruments配置都默认关闭的,且在setup_consumers表中没有像等待事件、阶段事件、语句事件与事务事件那样的单独配置项。

PS:内存统计表不包含计时信息,因为内存事件不支持时间信息收集。

内存事件统计表有如下几张表:

代码语言:javascript复制
admin@localhost : performance_schema 06:56:56> show tables like '%memory%summary%';
 ------------------------------------------------- 
| Tables_in_performance_schema (%memory%summary%) |
 ------------------------------------------------- 
| 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            |
 ------------------------------------------------- 
5 rows in set (0.00 sec)

我们先来看看这些表中记录的统计信息是什么样子的(由于单行记录较长,这里只列出memory_summary_by_account_by_event_name 表中的示例数据,其余表的示例数据省略掉部分相同字段)。

代码语言:javascript复制
# 如果需要统计内存事件信息,需要开启内存事件采集器
root@localhost : performance_schema 11:50:46> update setup_instruments set enabled='yes',timed='yes' where name like 'memory/%';
Query OK, 377 rows affected (0.00 sec)
Rows matched: 377 Changed: 377 Warnings: 0
# memory_summary_by_account_by_event_name表
root@localhost : performance_schema 11:53:24> select * from memory_summary_by_account_by_event_name where COUNT_ALLOC!=0 limit 1G
*************************** 1. row ***************************
                    USER: NULL
                    HOST: NULL
              EVENT_NAME: memory/innodb/fil0fil
             COUNT_ALLOC: 103
              COUNT_FREE: 103
SUM_NUMBER_OF_BYTES_ALLOC: 3296
SUM_NUMBER_OF_BYTES_FREE: 3296
          LOW_COUNT_USED: 0
      CURRENT_COUNT_USED: 0
         HIGH_COUNT_USED: 1
LOW_NUMBER_OF_BYTES_USED: 0
CURRENT_NUMBER_OF_BYTES_USED: 0
HIGH_NUMBER_OF_BYTES_USED: 32
1 row in set (0.00 sec)
# memory_summary_by_host_by_event_name表
root@localhost : performance_schema 11:54:36> select * from memory_summary_by_host_by_event_name where COUNT_ALLOC!=0 limit 1G
*************************** 1. row ***************************
                    HOST: NULL
              EVENT_NAME: memory/innodb/fil0fil
             COUNT_ALLOC: 158
......
1 row in set (0.00 sec)
# memory_summary_by_thread_by_event_name表
root@localhost : performance_schema 11:55:11> select * from memory_summary_by_thread_by_event_name where COUNT_ALLOC!=0 limit 1G
*************************** 1. row ***************************
               THREAD_ID: 37
              EVENT_NAME: memory/innodb/fil0fil
             COUNT_ALLOC: 193
......
1 row in set (0.00 sec)
# memory_summary_by_user_by_event_name表
root@localhost : performance_schema 11:55:36> select * from memory_summary_by_user_by_event_name where COUNT_ALLOC!=0 limit 1G
*************************** 1. row ***************************
                    USER: NULL
              EVENT_NAME: memory/innodb/fil0fil
             COUNT_ALLOC: 216
......
1 row in set (0.00 sec)
# memory_summary_global_by_event_name表
root@localhost : performance_schema 11:56:02> select * from memory_summary_global_by_event_name where COUNT_ALLOC!=0 limit 1G
*************************** 1. row ***************************
              EVENT_NAME: memory/performance_schema/mutex_instances
             COUNT_ALLOC: 1
......
1 row in set (0.00 sec)

从上面表中的示例记录信息中,我们可以看到,同样与等待事件类似,按照用户、主机、用户 主机、线程等纬度进行分组与统计的列,分组列与等待事件类似,这里不再赘述,但对于内存统计事件,统计列与其他几种事件统计列不同(因为内存事件不统计时间开销,所以与其他几种事件类型相比无相同统计列),如下:

每个内存统计表都有如下统计列:

* COUNT_ALLOC,COUNT_FREE:对内存分配和释放内存函数的调用总次数 

* SUM_NUMBER_OF_BYTES_ALLOC,SUM_NUMBER_OF_BYTES_FREE:已分配和已释放的内存块的总字节大小 

* CURRENT_COUNT_USED:这是一个便捷列,等于COUNT_ALLOC - COUNT_FREE 

* CURRENT_NUMBER_OF_BYTES_USED:当前已分配的内存块但未释放的统计大小。这是一个便捷列,等于SUM_NUMBER_OF_BYTES_ALLOC - SUM_NUMBER_OF_BYTES_FREE 

* LOW_COUNT_USED,HIGH_COUNT_USED:对应CURRENT_COUNT_USED列的低和高水位标记 

* LOW_NUMBER_OF_BYTES_USED,HIGH_NUMBER_OF_BYTES_USED:对应CURRENT_NUMBER_OF_BYTES_USED列的低和高水位标记

内存统计表允许使用TRUNCATE TABLE语句。使用truncate语句时有如下行为: 

* 通常,truncate操作会重置统计信息的基准数据(即清空之前的数据),但不会修改当前server的内存分配等状态。也就是说,truncate内存统计表不会释放已分配内存 

* 将COUNT_ALLOC和COUNT_FREE列重置,并重新开始计数(等于内存统计信息以重置后的数值作为基准数据)

* SUM_NUMBER_OF_BYTES_ALLOC和SUM_NUMBER_OF_BYTES_FREE列重置与COUNT_ALLOC和COUNT_FREE列重置类似 

* LOW_COUNT_USED和HIGH_COUNT_USED将重置为CURRENT_COUNT_USED列值 

*  LOW_NUMBER_OF_BYTES_USED和HIGH_NUMBER_OF_BYTES_USED将重置为CURRENT_NUMBER_OF_BYTES_USED列值 

* 此外,按照帐户,主机,用户或线程分类统计的内存统计表或memory_summary_global_by_event_name表,如果在对其依赖的accounts、hosts、users表执行truncate时,会隐式对这些内存统计表执行truncate语句

关于内存事件的行为监控设置与注意事项

内存行为监控设置:

* 内存instruments在setup_instruments表中具有memory/code_area/instrument_name格式的名称。但默认情况下大多数instruments都被禁用了,默认只开启了memory/performance_schema/*开头的instruments

* 以前缀memory/performance_schema命名的instruments可以收集performance_schema自身消耗的内部缓存区大小等信息。memory/performance_schema/* instruments默认启用,无法在启动时或运行时关闭。performance_schema自身相关的内存统计信息只保存在memory_summary_global_by_event_name表中,不会保存在按照帐户,主机,用户或线程分类聚合的内存统计表中

* 对于memory instruments,setup_instruments表中的TIMED列无效,因为内存操作不支持时间统计

* 注意:如果在server启动之后再修改memory instruments,可能会导致由于丢失之前的分配操作数据而导致在释放之后内存统计信息出现负值,所以不建议在运行时反复开关memory instruments,如果有内存事件统计需要,建议在server启动之前就在my.cnf中配置好需要统计的事件采集

当server中的某线程执行了内存分配操作时,按照如下规则进行检测与聚合:

* 如果该线程在threads表中没有开启采集功能或者说在setup_instruments中对应的instruments没有开启,则该线程分配的内存块不会被监控

* 如果threads表中该线程的采集功能和setup_instruments表中相应的memory instruments都启用了,则该线程分配的内存块会被监控

对于内存块的释放,按照如下规则进行检测与聚合:

* 如果一个线程开启了采集功能,但是内存相关的instruments没有启用,则该内存释放操作不会被监控到,统计数据也不会发生改变

* 如果一个线程没有开启采集功能,但是内存相关的instruments启用了,则该内存释放的操作会被监控到,统计数据会发生改变,这也是前面提到的为啥反复在运行时修改memory instruments可能导致统计数据为负数的原因

对于每个线程的统计信息,适用以下规则。

当一个可被监控的内存块N被分配时,performance_schema会对内存统计表中的如下列进行更新:

* COUNT_ALLOC:增加1 

* CURRENT_COUNT_USED:增加1 

* HIGH_COUNT_USED:如果CURRENT_COUNT_USED增加1是一个新的最高值,则该字段值相应增加 

* SUM_NUMBER_OF_BYTES_ALLOC:增加N 

* CURRENT_NUMBER_OF_BYTES_USED:增加N 

* HIGH_NUMBER_OF_BYTES_USED:如果CURRENT_NUMBER_OF_BYTES_USED增加N之后是一个新的最高值,则该字段值相应增加

当一个可被监控的内存块N被释放时,performance_schema会对统计表中的如下列进行更新:  * COUNT_FREE:增加1  * CURRENT_COUNT_USED:减少1  * LOW_COUNT_USED:如果CURRENT_COUNT_USED减少1之后是一个新的最低值,则该字段相应减少  * SUM_NUMBER_OF_BYTES_FREE:增加N  * CURRENT_NUMBER_OF_BYTES_USED:减少N  * LOW_NUMBER_OF_BYTES_USED:如果CURRENT_NUMBER_OF_BYTES_USED减少N之后是一个新的最低值,则该字段相应减少

对于较高级别的聚合(全局,按帐户,按用户,按主机)统计表中,低水位和高水位适用于如下规则 : * LOW_COUNT_USED和LOW_NUMBER_OF_BYTES_USED是较低的低水位估算值。performance_schema输出的低水位值可以保证统计表中的内存分配次数和内存小于或等于当前server中真实的内存分配值  * HIGH_COUNT_USED和HIGH_NUMBER_OF_BYTES_USED是较高的高水位估算值。performance_schema输出的低水位值可以保证统计表中的内存分配次数和内存大于或等于当前server中真实的内存分配值

对于内存统计表中的低水位估算值,在memory_summary_global_by_event_name表中如果内存所有权在线程之间传输,则该估算值可能为负数

|  温馨提示

性能事件统计表中的数据条目是不能删除的,只能把相应统计字段清零;

性能事件统计表中的某个instruments是否执行统计,依赖于在setup_instruments表中的配置项是否开启;

性能事件统计表在setup_consumers表中只受控于"global_instrumentation"配置项,也就是说一旦"global_instrumentation"配置项关闭,所有的统计表的统计条目都不执行统计(统计列值为0);

内存事件在setup_consumers表中没有独立的配置项,且memory/performance_schema/* instruments默认启用,无法在启动时或运行时关闭。performance_schema相关的内存统计信息只保存在memory_summary_global_by_event_name表中,不会保存在按照帐户,主机,用户或线程分类聚合的内存统计表中。

下期将为大家分享 《数据库对象事件统计与属性统计 | performance_schema全方位介绍》 ,谢谢你的阅读,我们下期不见不散!

| 作者简介

罗小波·沃趣科技高级数据库技术专家

IT从业多年,历任运维工程师、高级运维工程师、运维经理、数据库工程师,曾参与版本发布系统、轻量级监控系统、运维管理平台、数据库管理平台的设计与编写,熟悉MySQL体系结构,Innodb存储引擎,喜好专研开源技术,追求完美。

0 人点赞