千金良方:MySQL性能优化金字塔法则
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

5.3 运行时配置

在MySQL启动之后,我们就无法使用启动选项来开关相应的consumers和instruments了,那么此时如何根据自己的需求来灵活地开关performance_schema中的采集信息呢?(比如:在默认配置下很多配置项并未开启,我们可能需要即时修改配置;再如:在高并发场景中,有大量的线程连接到MySQL,执行各种SQL语句产生大量的事件信息,而我们只想查看某一个会话产生的事件信息时,也可能需要即时修改配置)我们可以通过修改performance_schema下的一些配置表中的配置项来实现。

这些配置表中的配置项之间存在着关联关系,按照配置影响的先后顺序,可整理成如图5-1所示的关系(仅代表个人理解)。

图5-1

5.3.1 performance_timers表

performance_timers表中记录了Server中有哪些可用的事件计时器(注意:该表中的配置项不支持增、删、改,是只读的。记录了哪些计时器就表示当前的版本支持这些计时器)。setup_timers表中的配置项引用此表中的计时器。

每个计时器的精度和数量相关的特征值会有所不同,可以通过如下查询语句查看performance_timers表中记录的计时器和相关的特征信息。

mysql> SELECT * FROM performance_timers;
+----------------+----------------+------------------+-----------------+
| TIMER_NAME     | TIMER_FREQUENCY | TIMER_RESOLUTION  | TIMER_OVERHEAD   |
+----------------+----------------+------------------+-----------------+
| CYCLE          | 2389029850     | 1                | 72               |
| NANOSECOND     | 1000000000     | 1                | 112              |
| MICROSECOND    | 1000000        | 1                | 136              |
| MILLISECOND    | 1036           | 1                | 168              |
| TICK           | 105            | 1                | 2416             |
+----------------+----------------+------------------+-----------------+

performance_timers表中各字段的含义如下。

● TIMER_NAME:表示可用计时器的名称,其中CYCLE是指基于CPU(处理器)周期的计数器。在setup_timers表中可以使用performance_timers表中字段值不为NULL的计时器(如果performance_timers表中某字段值为NULL,则表示该定时器可能不支持当前Server所在平台)。

● TIMER_FREQUENCY:表示每秒对应的计时器单位的数量(即相对于每秒时间换算为对应的计时器单位之后的数值,例如,每秒=1000毫秒=1000000微秒=1000000000纳秒)。对于CYCLE计时器的换算值,通常与CPU的频率相关。对于在performance_timers表中查看到的CYCLE计时器的TIMER_FREQUENCY字段值,是从基于2.4GHz处理器的系统上获得的预设值(在基于2.4GHz处理器的系统上,CYCLE计时器的TIMER_FREQUENCY字段值可能接近2400000000)。NANOSECOND、MICROSECOND、MILLISECOND计时器的TIMER_FREQUENCY字段值是基于固定的1秒换算而来的。对于TICK计时器,TIMER_FREQUENCY字段值可能会因平台而异(例如,有些平台使用100个tick/秒,还有些平台使用1000个tick/秒)。

● TIMER_RESOLUTION:计时器精度值,表示每个计时器被调用时额外增加的值(即使用该计时器时,计时器被调用一次,需要额外增加的值)。如果计时器的分辨率为10,则该计时器每次被调用时,其时间值相当于TIMER_FREQUENCY值+10。

● TIMER_OVERHEAD:表示在使用计时器获取事件时开销的最小周期值(比如performance_schema在初始化期间调用计时器20次,选择一个最小值作为此字段值)。每个事件的时间开销值都是计时器显示值的两倍,因为在事件的开始和结束时都调用了计时器。注意:计时器代码仅用于支持计时类事件,对于非计时类事件(如调用次数的统计事件),这种计时器统计开销方法不适用。

提示:对于performance_timers表,不允许使用TRUNCATE TABLE语句。

5.3.2 setup_timers表

setup_timers表中记录了当前使用的事件计时器信息(注意:该表不支持增加和删除记录,只支持修改和查询记录)。

可以通过UPDATE语句来更改setup_timers.TIMER_NAME字段值,以给不同的事件类别选择不同的计时器。setup_timers.TIMER_NAME字段的有效值来自performance_timers. TIMER_NAME字段值。

对setup_timers表的修改会立即影响监控。正在执行的事件可能会使用修改之前的计时器作为开始时间,但可能会使用修改之后的新的计时器作为结束时间。为避免修改计时器后可能导致收集的时间信息不正确,请在修改之后使用TRUNCATE TABLE语句来重置performance_schema下相关表中的统计信息。

mysql> SELECT * FROM setup_timers;
+--------------+------------+
| NAME          | TIMER_NAME  |
+--------------+------------+
| idle          | MICROSECOND |
| wait          | CYCLE       |
| stage         | NANOSECOND  |
| statement    | NANOSECOND  |
| transaction  | NANOSECOND  |
+--------------+------------+

setup_timers表中各字段的含义如下。

● NAME:计时器类型,对应于事件类别。

● TIMER_NAME:计时器类型名称。此字段可以修改,其有效值参见performance_timers.TIMER_NAME字段值。

提示:对于setup_timers表,不允许使用TRUNCATE TABLE语句。

5.3.3 setup_consumers表

setup_consumers表中列出了consumers可配置列表项(注意:该表不支持增加和删除记录,只支持修改和查询记录)。

mysql> SELECT * FROM setup_consumers;
+-------------------------------------+-----------+
| NAME                                  | ENABLED   |
+-------------------------------------+-----------+
| events_stages_current                | NO        |
| events_stages_history                | NO        |
| events_stages_history_long           | NO        |
| events_statements_current            | YES       |
| events_statements_history            | YES       |
| events_statements_history_long       | NO        |
| events_transactions_current          | NO        |
| events_transactions_history          | NO        |
| events_transactions_history_long     | NO        |
| events_waits_current                 | NO        |
| events_waits_history                 | NO        |
| events_waits_history_long            | NO        |
| global_instrumentation               | YES       |
| thread_instrumentation               | YES       |
| statements_digest                    | YES       |
+-------------------------------------+-----------+

对setup_consumers表的修改会立即影响监控。setup_consumers表中各字段的含义如下。

● NAME:consumers名称。

● ENABLED:是否启用consumers,有效值为YES或NO,此字段可以使用UPDATE语句修改。如果需要禁用consumers,就将ENABLED字段设置为NO,当设置为NO时,Server不会对consumers表的内容新增和删除进行维护,并且也会关闭consumers对应的instruments(如果instruments发现采集数据没有任何consumers消费的话)。

提示:对于setup_consumers表,不允许使用TRUNCATE TABLE语句。

setup_consumers表中的consumers配置项具有层级关系,按照优先级顺序,显示为如图5-2所示的层次结构(可以根据这个层次结构,关闭不需要的较低级别的consumers,这样有助于节省性能开销,并且后续查看所采集的事件信息时也方便进行筛选)。

图5-2

从图5-2所示的信息中可以看到:

(1)global_instrumentation处于顶级位置,优先级最高。

● 当global_instrumentation为YES时,会检查setup_consumers表中的statements_digest和thread_instrumentation的配置,并附带检查setup_instruments、setup_objects、setup_timers配置表。

● 当global_instrumentation为YES时(无论setup_consumers表中的statements_digest和thread_instrumentation如何配置,只依赖于global_instrumentation的配置),会维护全局events输出表:mutex_instances、rwlock_instances、cond_instances、file_instances、users、hostsaccounts、socket_summary_by_event_name、file_summary_by_instance、file_summary_by_event_name、objects_summary_global_by_type、memory_summary_global_by_event_name、table_lock_waits_summary_by_table、table_io_waits_summary_by_index_usage、table_io_waits_summary_by_table、events_waits_summary_by_instance、events_waits_summary_global_by_event_name、events_stages_summary_global_by_event_name、events_statements_summary_global_by_event_name、events_transactions_summary_global_by_event_name。

● 当global_instrumentation为NO时,不会检查任何更低级别的consumers配置,不会维护任何events输出表(以memory_%开头的events输出表除外,因为对这些表的维护只受setup_instruments配置表控制)。

(2)statements_digest和thread_instrumentation处于同一级别,其优先级次于global_instrumentation,且依赖于global_instrumentation为YES时的配置才会被检测。

● 当statements_digest为YES时,由于statements_digest consumers没有更低级别的配置,因此还需要依赖于global_instrumentation为YES时的配置才会生效。会维护events输出表:events_statements_summary_by_digest。

● 当statements_digest为NO时,不维护events输出表:events_statements_summary_by_digest。

● 当thread_instrumentation为YES时,会检查setup_consumers表中的events_xxx_current配置(xxx表示waits、stages、statements、transactions),且附带检查setup_actors、threads配置表。会维护events输出表:events_xxx_summary_by_yyy_by_event_name,其中xxx的含义同上,yyy表示thread、user、host、account。

● 当thread_instrumentation为NO时,不检查setup_consumers表中的events_xxx_current配置,不维护events_xxx_current以及更低级别的events输出表。

(3)events_xxx_current系列(xxx的含义同上)consumers处于同一级别,且依赖于thread_instrumentation为YES时的配置才会被检测。

● 当events_xxx_current为YES时,会检测setup_consumers配置表中的events_xxx_history和events_xxx_history_long系列consumers配置,会维护events_xxx_current系列表。

● 当events_xxx_current为NO时,不检测setup_consumers配置表中的events_xxx_history和events_xxx_history_long系列consumers配置,不维护events_xxx_current系列表。

(4)events_xxx_history和events_xxx_history_long系列(xxx的含义同上)consumers处于同一级别,优先级次于events_xxx_current系列consumers,依赖于events_xxx_current系列consumers配置为YES时才会被检测。

● 当events_xxx_history为YES时,没有更低级别的consumers配置需要检测,但会附带检测setup_actors、threads配置表中的HISTORY字段值,会维护events_xxx_history系列表,反之不维护。

● 当events_xxx_history_long为YES时,没有更低级别的consumers配置需要检测,但会附带检测setup_actors、threads配置表中的HISTORY字段值,会维护events_xxx_history_long系列表,反之不维护。

注意:

● events输出表events_xxx_summary_by_yyy_by_event_name的开关由global_instrumentation控制,且表中有固定数据行,不可清理,当truncate或者关闭相关的consumers时,只是不统计相关的instruments收集的events数据,相关字段为0值。

● 如果performance_schema在对setup_consumers表做检查时发现某个consumers配置行的ENABLED字段值不为YES,则与该配置项相关的events输出表中就不会接收存储任何事件记录。

● 当高级别的consumers配置不为YES时,依赖于这个consumers配置为YES时才会启用的那些更低级别的consumers将一同被禁用。

配置项修改示例如下:

# 打开events_waits_current表的当前等待事件记录功能
mysql> UPDATE setup_consumers SET ENABLED ='NO' WHERE NAME ='events_waits_current';
# 关闭历史事件记录功能
mysql> UPDATE setup_consumers SET ENABLED ='NO' where name like '%history%';
# where条件 ENABLED ='YES' 即表示打开对应的记录表功能
......

5.3.4 setup_instruments表

setup_instruments表中列出了instruments可配置列表项,即代表哪些事件支持被收集。

mysql> SELECT * FROM setup_instruments;
+------------------------------------------------------+---------+-------+
| NAME                                                 | ENABLED | TIMED |
+------------------------------------------------------+---------+-------+
...
| wait/synch/mutex/sql/LOCK_global_read_lock             | YES     | YES   |
| wait/synch/mutex/sql/LOCK_global_system_variables       | YES     | YES   |
| wait/synch/mutex/sql/LOCK_lock_db                      | YES     | YES   |
| wait/synch/mutex/sql/LOCK_manager                      | YES     | YES   |
...
| wait/synch/rwlock/sql/LOCK_grant                     | YES     | YES   |
| wait/synch/rwlock/sql/LOGGER::LOCK_logger              | YES     | YES   |
| wait/synch/rwlock/sql/LOCK_sys_init_connect            | YES     | YES   |
| wait/synch/rwlock/sql/LOCK_sys_init_slave              | YES     | YES   |
...
| wait/io/file/sql/binlog                              | YES     | YES   |
| wait/io/file/sql/binlog_index                        | YES     | YES   |
| wait/io/file/sql/casetest                            | YES     | YES   |
| wait/io/file/sql/dbopt                               | YES     | YES   |
...

setup_instruments表中各字段详解如下。

● NAME:instruments名称,该名称可能由多个部分组成并形成层次结构。当instruments被执行时,产生的事件名称就取自instruments名称,事件没有真正的名称,直接使用instruments来作为事件名称,可以将instruments与产生的事件进行关联。

● ENABLED:是否启用instruments,其有效值为YES或NO,此字段可以使用UPDATE语句修改。如果将其设置为NO,则这个instruments不会被执行,不会产生任何事件信息。

● TIMED:instruments是否收集时间信息,其有效值为YES或NO,此字段可以使用UPDATE语句修改。如果将其设置为NO,则这个instruments不会收集时间信息。

instruments具有树形结构的命名空间,从setup_instruments表中的NAME字段可以看到,在instruments名称的组成中,最左边的是顶层instruments类型命名,最右边的是一个具体的instruments名称。有一些顶层instruments没有其他层级的组件(如:transaction和idle,那么它既是类型又是具体的instruments名称),也有一些顶层instruments具有下层instruments(如:wait/io/file/myisam/log),一个层级的instruments名称对应的组件数量取决于instruments类型。

一个给定instruments名称的含义,需要根据instruments名称的左侧命名而定。例如,下面两个与MyISAM相关的instruments名称的含义各不相同,对于名称中给定组件的解释取决于其左侧的组件。

# 第一个instruments表示与MyISAM存储引擎的文件I/O相关
wait/io/file/myisam/log
# 第二个instruments表示与MyISAM存储引擎的磁盘同步相关
wait/synch/cond/myisam/MI_SORT_INFO::cond

instruments的命名格式组成:performance_schema实现的一个前缀结构(如:wait/io/file/myisam/log中的wait)+由开发人员实现的instruments代码定义的一个后缀名称(如:wait/io/file/myisam/log中的io/file/myisam/log)。

● instruments名称前缀表示instruments的类型(如wait/io/file/myisam/log中的wait),该前缀还用于在setup_timers表中配置某个事件类型的定时器,也被称作顶层组件。

● instruments名称后缀来自instruments本身的代码。后缀可能包括:

■ 主要组件的名称(如:myisam、innodb、mysys或sql,这些都是Server的子系统模块组件)或插件名称。

■ 代码中变量的名称,格式为XXX(全局变量)或CCC::MMM(CCC表示一个类名,MMM表示在类CCC作用域中的一个成员对象),如:'wait/synch/cond/sql/COND_thread_cache' instruments中的COND_thread_cache、'wait/synch/mutex/mysys/THR_LOCK_myisam' instruments中的THR_LOCK_myisam、'wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_index' instruments中的MYSQL_BIN_LOG::LOCK_index。

对于在源代码中实现的每一个instruments,如果该源代码被加载到Server中,那么在setup_instruments表中就会有一行对应的配置,当启用或执行instruments时,会创建对应的instruments实例,这些实例在*_instances表中可以查看到

大多数setup_instruments配置行修改后会立即影响监控,但对于某些instruments,运行时修改不生效(可以修改配置表,但不生效),只有在启动之前修改才会生效(使用system variables写到配置文件中),不生效的instruments主要有mutex、condition、rwlock。

对于内存instruments, setup_instruments表中的TIMED字段将被忽略(使用UPDATE语句对这些内存instruments设置TIMED字段值为YES时可以执行成功,但是你会发现执行UPDATE语句之后,再执行SELECT语句查询这些instruments的TIMED字段值还是NO),因为内存操作没有计时器信息。

如果某个instruments的ENABLED设置为YES(表示启用这个instruments),而TIMED字段值未设置为YES(表示计时器功能禁用),则instruments会产生事件信息,但是事件信息对应的TIMER_START、TIMER_END和TIMER_WAIT计时器值都为NULL。后续在汇总表中计算sum、minimum、maximum和average时间值时会忽略这些NULL值。

提示:setup_instruments表不允许使用TRUNCATE TABLE语句。

setup_instruments表中的instruments名称层级结构如图5-3所示。

图5-3

在setup_instruments表中顶级instruments组件分类如下。

(1)Idle Instrument组件:用于检测空闲事件的instruments,该instruments没有其他层级的组件。空闲事件的收集时机如下:

● 依据socket_instances表中的STATE字段而定,STATE字段有ACTIVE和IDLE两个值,如果STATE字段值为ACTIVE,则performance_schema使用与socket类型相对应的instruments跟踪活跃的socket连接的等待时间(监听活跃的socket的instruments有wait/io/socket/sql/server_tcpip_socket、wait/io/socket/sql/ server_unix_socket、wait/io/socket/sql/client_connection);如果STATE字段值为IDLE,则performance_schema使用idle instruments跟踪空闲socket连接的等待时间。

● 如果socket连接在等待来自客户端的请求,则此时socket连接处于空闲状态,socket_instances表中处于空闲的socket连接的STATE字段值会从ACTIVE变为IDLE。EVENT_NAME字段值保持不变,instruments的计时器被暂停,并在events_waits_current表中生成一行EVENT_NAME字段值为idle的事件记录(需要设置setup_consumers表中的events_waits_current配置项的ENABLED字段值为YES之后,该表才会记录内容)。

● 当socket连接接收到客户端的下一个请求时,空闲事件被终止,socket实例从空闲状态切换到活动状态,并恢复socket instruments的计时器工作。

注意:socket_instances表不允许使用TRUNCATE TABLE语句。

(2)Transaction Instrument组件:用于检测transactions事件的instruments,该instruments没有其他层级的组件。

(3)Memory Instrument组件:用于检测memorys事件的instruments。

在默认情况下禁用了大多数memory instruments,但可以在启动Server时在my.cnf中启用或禁用,或者在运行时更新setup_instruments表中的相关instruments配置来动态启用或禁用。memory instruments的命名格式为:memory/code_area/instrument_name,其中code_area是一个Server组件字符串值(如sql、client、vio、mysys、partition和存储引擎名称:performance_schema、myisam、innodb、csv、myisammrg、memory、blackhole、archive等),而instrument_name是具体的instruments名称。

以前缀memory/performance_schema命名的instruments显示为performance_schema内部缓冲区分配了多少内存。以memory/performance_schema开头的instruments是内置的,无法在启动时或者运行时人为开关,内部始终启用。这些instruments采集的events事件记录仅存储在memory_summary_global_by_event_name表中。

(4)Stage Instrument组件:用于检测stages事件的instruments。

stage instruments的命名格式为:stage/code_area/stage_name,其中code_area是一个Server组件字符串值(与memory instruments类似),stage_name表示语句的执行阶段,如'Sorting result’和 ’Sending data'。这些执行阶段字符串值与SHOW PROCESSLIST的State字段值、INFORMATION_SCHEMA.PROCESSLIST表的STATE字段值类似。

(5)Statement Instrument组件:用于检测statements事件的instruments,其包含如下几个子类。

● statement/abstract/:statement操作的抽象instruments。该抽象instruments用在没有确定语句类型的早期阶段,当语句类型确定之后,使用对应语句类型的instruments代替。

● statement/com/:与command操作相关的instruments。其名称对应于COM_xxx操作命令(详见mysql_com.h头文件和sql/sql_parse.cc文件。例如:statement/com/Connect和statement/com/Init DB instruments分别对应于COM_CONNECT和COM_INIT_DB命令)。

● statement/scheduler/event:用于跟踪一个事件调度器执行过程中所有事件的instruments,该类型的instruments只有一个。

● statement/sp/:用于检测存储程序执行过程中内部命令的instruments。例如,statement/sp/cfetch和statement/sp/freturn instruments分别表示检测存储程序内部使用游标提取数据、函数返回数据等相关命令。

● statement/sql/:与SQL语句操作相关的instruments。例如,statements/sql/create_db和statement/sql/select instruments分别表示检测CREATE DATABASE和SELECT语句的instruments。

(6)Wait Instrument组件:用于检测waits事件的instruments,其包含如下几个子类。

● wait/io:用于检测I/O操作的instruments,其又包含如下几个子类。

■ wait/io/file:用于检测文件I/O操作的instruments。对于文件来说,表示与等待文件相关的系统调用完成,如fwrite()系统调用。由于缓存的存在,在数据库中进行相关操作时不一定需要在磁盘上读写。

■ wait/io/socket:用于检测socket操作的instruments。socket instruments的命名格式为:wait/io/socket/sql/socket_type, Server在支持的每一种网络通信协议上监听socket。socket instruments监听TCP/IP、UNIX套接字文件连接的socket_type值有server_tcpip_socket和server_unix_socket。当监听套接字检测到有客户端连接进来时,Server将客户端连接转移到被单独线程管理的新套接字来处理。新连接线程对应的socket_type值为client_connection。使用语句select * from setup_instruments where name like 'wait/io/socket%';可以查询这三个socket_type值对应的instruments。

● wait/io/table/sql/handler:与表I/O操作相关的instruments。这个类别包括了对持久基表或临时表的行级访问(对数据行获取、插入、更新和删除)。对于视图来说,在做instruments检测时会参照被视图引用的基表访问情况。

与大多数等待事件不同,表I/O等待可以包括其他等待。例如,表I/O可能包括文件I/O或内存操作。因此,表I/O等待的事件在events_waits_current表中的记录通常有两行(除wait/io/table/sql/handler的事件记录之外,可能还包含一行wait/io/file/myisam/dfile的事件记录)。这种情况可以叫作表I/O操作的原子事件。

某些行操作可能会导致多个表I/O等待。例如,如果有INSERT触发器,那么插入操作可能导致触发器更新操作。

● wait/lock:与锁操作相关的instruments。

■ wait/lock/table:与表锁操作相关的instruments。

■ wait/lock/metadata/sql/mdl:与MDL锁操作相关的instruments。

● wait/synch:与磁盘同步对象相关的instruments。performance_schema.events_waits_xxx表中的TIMER_WAIT字段包含了在尝试获取某个对象上的锁(如果这个对象上已经存在锁)时被阻塞的时长。

■ wait/synch/cond:一个线程使用一个状态来向其他线程发信号,通知它们正在等待的事情已经发生了。如果只有一个线程正在等待这个状态,那么它可以被这个状态唤醒并继续往下执行。如果有多个线程都在等待这个状态,则这些线程都会被唤醒,并竞争它们正在等待的资源。该instruments用于采集某线程等待这个资源时被阻塞的事件信息。

■ wait/synch/mutex:一个线程在访问某个资源时,使用互斥对象防止其他线程同时访问这个资源。该instruments用于采集发生互斥时的事件信息。

■ wait/synch/rwlock:一个线程使用一个读写锁对象对某个特定变量进行锁定,以防止其他线程同时访问。对于使用共享读锁锁定的资源,多个线程可以同时访问;对于使用独占写锁锁定的资源,只有一个线程可以访问。该instruments用于采集发生读写锁锁定时的事件信息。

■ wait/synch/sxlock:Shared-Exclusive(SX)锁是一种rwlock锁对象,它在提供对公共资源写访问的同时允许其他线程的不一致读取。sxlocks锁对象可用于优化数据库读写场景下的并发性和可扩展性。

要控制这些instruments的启停,应将ENABLED字段值设置为YES或NO;要配置instruments是否收集计时器信息,应将TIMED字段值设置为YES或NO。

对setup_instruments表的大多数instruments的修改会立即影响监控。但对于某些instruments,在MySQL Server重启后修改才生效,运行时修改不生效,因为可能会影响mutexes、conditions和rwlocks。下面我们来看一些setup_instruments表修改示例。

# 禁用所有的instruments,修改之后,生效的instruments修改会立即产生影响,即立即关闭收集功能
mysql> UPDATE setup_instruments SET ENABLED = 'NO';
# 禁用所有文件类instruments,使用NAME字段结合like模糊匹配
mysql> UPDATE setup_instruments SET ENABLED = 'NO' WHERE NAME LIKE 'wait/io/file/%';
# 仅禁用文件类instruments,启用所有其他instruments,使用NAME字段结合if函数,LIKE模糊匹配到就改为NO,没有匹配到就改为YES
mysql> UPDATE setup_instruments SET ENABLED = IF(NAME LIKE 'wait/io/ file/%', 'NO', 'YES');
# 启用所有类型的eventsmysys子系统的instruments
mysql> UPDATE setup_instruments SET ENABLED = CASE WHEN NAME LIKE '%/mysys/%' THEN 'YES' ELSE 'NO' END;
# 禁用指定的instruments
mysql> UPDATE setup_instruments SET ENABLED = 'NO' WHERE NAME = 'wait/synch/mutex/mysys/TMPDIR_mutex';
# 切换instruments开关的状态,“翻转”ENABLED字段值,使用ENABLED字段值+if函数IF(ENABLED='YES', 'NO', 'YES')表示,如果ENABLED字段值为YES,则修改为NO;反之,修改为YES
mysql> UPDATE setup_instruments SET ENABLED = IF(ENABLED= 'YES', 'NO', 'YES')WHERE NAME= 'wait/synch/mutex/mysys/TMPDIR_mutex';
# 禁用所有instruments的计时器
mysql> UPDATE setup_instruments SET TIMED = 'NO';

查找与InnoDB存储引擎文件相关的instruments,可以使用如下语句:

mysql> select * from setup_instruments where name like 'wait/io/file/innodb/%';
+------------------------------------------+---------+-------+
| NAME                                       | ENABLED | TIMED |
+------------------------------------------+---------+-------+
| wait/io/file/innodb/innodb_data_file     | YES     | YES   |
| wait/io/file/innodb/innodb_log_file       | YES     | YES   |
| wait/io/file/innodb/innodb_temp_file     | YES     | YES   |
+------------------------------------------+---------+-------+
3 rows in set(0.00 sec)

提示:在官方文档中没有找到所有instruments的具体说明,官方给出的原因如下。

● instruments是服务端代码,可能会经常发生变动。

● instruments有数百种,全部列出不现实。

● instruments会因为所安装的版本不同而有所不同,每一个版本所支持的instruments可以通过查询setup_instruments表获取。

与常用的场景相关的设置如下:

● 监控metadata locks(MDL元数据锁)需要打开’wait/lock/metadata/sql/mdl' instruments,开启这个instruments之后,在performance_schema.metadata_locks表中可以查询到MDL锁信息。

● profiling功能即将废弃,监控与原profiling功能相关的事件信息需要启用对应的instruments,具体的instruments列表可使用select * from setup_instruments where name like '%stage/sql%' and name not like '%stage/sql/Waiting%' and name not like '%stage/sql/%relay%' and name not like '%stage/sql/%binlog%' and name not like '%stage/sql/%load%';语句查看。开启这些instruments之后,可以在performance_schema.events_stages_xxx表中查看原show profiles语句输出的相关事件信息。

● 监控表锁需要打开’wait/io/table/sql/handler' instruments,开启这个instruments之后,在performance_schema.table_handles表中会记录当前打开了哪些表(当执行flush tables强制关闭打开的表时,该表中的信息会被清空)、哪些表已经被加了表锁(当某会话持有表锁时,相关记录行中的OWNER_THREAD_ID和OWNER_EVENT_ID字段值会记录相关的thread id和event id),以及表锁被哪个会话持有(当释放表锁时,相关记录行中的OWNER_THREAD_ID和OWNER_EVENT_ID字段值会被清零)。

● 监控查询语句top number需要打开’statement/sql/select' instruments,然后打开events_statements_xxx表,通过查询performance_schema.events_statements_xxx表的SQL_TEXT字段可以看到原始的SQL语句,查询TIMER_WAIT字段可以知道总的响应时间,查询LOCK_TIME字段可以知道加锁时间(注意时间单位是皮秒,需要除以1000000000000单位才是秒)。

5.3.5 setup_actors表

setup_actors表用于配置是否为新的前台Server线程(与客户端连接相关联的线程)启用监视和历史事件日志记录。在默认情况下,此表的最大行数为100。可以使用系统变量performance_schema_setup_actors_size,在Server启动之前更改此表的最大配置行数。

● 对于每个新的前台Server线程,performance_schema会匹配该表中的User、Host字段进行匹配,如果匹配到某个配置行,则继续匹配该行的ENABLED和HISTORY字段值,该字段值也会用于生成threads表中的INSTRUMENTED和HISTORY字段。如果在创建用户线程时在该表中没有匹配到User、Host字段,则该线程的INSTRUMENTED和HISTORY字段值将被设置为NO,表示不对这个线程进行监控,不记录该线程的历史事件信息。

● 对于后台线程(如I/O线程、日志线程、主线程、purged线程等),没有关联的用户,INSTRUMENTED和HISTORY字段值默认为YES,并且在创建后台线程时,不会查看setup_actors表的配置,因为该表只能控制前台线程,后台线程也不具备用户、主机属性。

setup_actors表的初始内容是匹配任何用户和主机,因此对于所有的前台线程,默认启用监视和历史事件收集功能。

mysql> SELECT * FROM setup_actors;
+------+------+------+---------+---------+
| HOST | USER | ROLE | ENABLED | HISTORY |
+------+------+------+---------+---------+
| %    | %    | %    | YES     | YES     |
+------+------+------+---------+---------+

setup_actors表中各字段的含义如下。

● HOST:一个具体的字符串名称(是能够解析为IP地址的主机名或DNS域名),或者使用“%”表示任意主机。

● USER:一个具体的字符串名称,或者使用“%”表示任意用户。

● ROLE:当前未使用,在MySQL 8.0中才启用角色功能。

● ENABLED:是否启用与HOST、USER、ROLE匹配的前台线程的监控功能,其有效值为YES或NO。

● HISTORY:是否启用与HOST、USER、ROLE匹配的前台线程的历史事件记录功能,其有效值为YES或NO。

提示:对于setup_actors表,允许使用TRUNCATE TABLE语句清空表,使用DELETE语句删除指定行。

对setup_actors表的修改仅影响修改之后新创建的前台线程,对修改之前已经创建的前台线程没有影响。如果要修改已经创建的前台线程的监控和历史事件记录功能,则可以修改threads表行的INSTRUMENTED和HISTORY字段值。

当一个前台线程初始化连接MySQL Server时,performance_schema会对setup_actors表执行查询,在表中查找每个配置行。首先尝试使用USER和HOST字段(ROLE未使用)依次找出匹配的配置行,然后再找出最佳匹配行并读取匹配行的ENABLED和HISTORY字段值,用于填充threads表中的ENABLED和HISTORY字段。

示例:假如setup_actors表中有如下HOST和USER字段值。

USER ='literal' and HOST ='literal'
USER ='literal' and HOST ='%'
USER ='%' and HOST ='literal'
USER ='%' and HOST ='%'

匹配顺序很重要,因为不同的匹配行可能具有不同的USER和HOST字段值(在MySQL中对用户账号是使用user@host进行区分的),根据匹配行的ENABLED和HISTORY字段值来决定对每个HOST、USER或ACCOUNT(USER和HOST组合,如:user@host)对应的线程在threads表中生成相应匹配行的ENABLED和HISTORY字段值,以便决定是否启用相应的instruments和历史事件记录功能。

● 当在setup_actors表中最佳匹配行的ENABLED = YES时,在threads表中对应线程的配置行的INSTRUMENTED字段值将变为YES。HISTORY字段同理。

● 当在setup_actors表中最佳匹配行的ENABLED = NO时,在threads表中对应线程的配置行的INSTRUMENTED字段值将变为NO。HISTORY字段同理。

● 当在setup_actors表中找不到匹配行时,在threads表中对应线程的配置行的INSTRUMENTED和HISTORY字段值将变为NO。

● 在setup_actors表中配置行的ENABLED和HISTORY字段值可以相互独立设置为YES或NO,互不影响,其中一个表示是否启用线程对应的instruments,一个表示是否启用与线程相关的历史事件记录的consumers。

在默认情况下,所有新的前台线程都启用instruments和历史事件记录功能,因为setup_actors表中的预设值是HOST='%', USER='%', ENABLED='YES', HISTORY='YES'。如果要执行更精细的匹配(例如,仅对某些前台线程进行监控),那么就必须要对setup_actors表中的默认值进行修改。示例如下:

# 首先使用UPDATE语句禁用默认配置行
mysql> UPDATE setup_actors SET ENABLED = 'NO', HISTORY = 'NO' WHERE HOST = '%' AND USER = '%';
# 插入用户joe@'localhost’对应的ENABLEDHISTORY字段值都为YES的配置行
mysql>INSERT INTO setup_actors(HOST, USER, ROLE, ENABLED, HISTORY)VALUES('localhost', 'joe', '%', 'YES', 'YES');
# 插入用户joe@'hosta.example.com’对应的ENABLED=YESHISTORY=NO的配置行
mysql>INSERT INTO setup_actors(HOST, USER, ROLE, ENABLED, HISTORY)VALUES('hosta.example.com', 'joe', '%', 'YES', 'NO');
# 插入用户sam@'%’对应的ENABLED=NOHISTORY=YES的配置行
mysql> INSERT INTO setup_actors(HOST, USER, ROLE, ENABLED, HISTORY)VALUES('%', 'sam', '%', 'NO', 'YES');
## 此时,在threads表中对应用户的前台线程配置行的INSTRUMENTEDHISTORY字段有效值如下
## joelocalhost连接到MySQL Server时,则连接符合第一个INSERT语句插入的配置行,在threads表中对应配置行的INSTRUMENTEDHISTORY字段值变为YES
## joehosta.example.com连接到MySQL Server时,则连接符合第二个INSERT语句插入的配置行,在threads表中对应配置行的INSTRUMENTED字段值为YES, HISTORY字段值为NO
##  joe从其他任意主机(%匹配除 localhost hosta.example.com之外的主机连接到 MySQL Server时,则连接符合第三个INSERT语句插入的配置行,在threads表中对应配置行的INSTRUMENTEDHISTORY字段值变为NO
## sam从任意主机(%匹配连接到MySQL Server时,则连接符合第三个INSERT语句插入的配置行,在threads表中对应配置行的INSTRUMENTED字段值变为NO, HISTORY字段值为YES
## joesam用户之外,其他任何用户从任意主机连接到MySQL Server时,则匹配到第一个UPDATE语句更新之后的默认配置行,在threads表中对应配置行的INSTRUMENTEDHISTORY字段值变为NO
## 如果把 UPDATE 语句改成 DELETE,让未明确指定的用户在 setup_actors 表中找不到任何匹配行,则在threads表中对应配置行的INSTRUMENTEDHISTORY字段值变为NO

对于后台线程,对setup_actors表的修改不生效,如果要干预后台线程默认的设置,则需要查询threads表找到相应的线程,然后使用UPDATE语句直接修改threads表中的INSTRUMENTED和HISTORY字段值。

5.3.6 setup_objects表

setup_objects表控制performance_schema是否监控特定对象。在默认情况下,此表的最大行数为100行。若要更改表行数,则可以在Server启动之前修改系统变量performance_schema_setup_objects_size的值。

setup_objects表的初始内容如下:

mysql> SELECT * FROM setup_objects;
+----------------+--------------------+-------------+---------+-------+
| OBJECT_TYPE | OBJECT_SCHEMA          | OBJECT_NAME | ENABLED | TIMED |
+----------------+--------------------+-------------+---------+-------+
| EVENT          | mysql               | %           | NO       | NO    |
| EVENT          | performance_schema  | %           | NO       | NO    |
| EVENT          | information_schema  | %           | NO       | NO    |
| EVENT          | %                   | %           | YES      | YES   |
| FUNCTION       | mysql               | %           | NO       | NO    |
| FUNCTION       | performance_schema  | %           | NO       | NO    |
| FUNCTION       | information_schema  | %           | NO       | NO    |
| FUNCTION       | %                   | %           | YES      | YES   |
| PROCEDURE      | mysql               | %           | NO       | NO    |
| PROCEDURE      | performance_schema  | %           | NO       | NO    |
| PROCEDURE      | information_schema  | %           | NO       | NO    |
| PROCEDURE      | %                   | %           | YES      | YES   |
| TABLE          | mysql               | %           | NO       | NO    |
| TABLE          | performance_schema  | %           | NO       | NO    |
| TABLE          | information_schema  | %           | NO       | NO    |
| TABLE          | %                   | %           | YES      | YES   |
| TRIGGER        | mysql               | %           | NO       | NO    |
| TRIGGER        | performance_schema  | %           | NO       | NO    |
| TRIGGER        | information_schema  | %           | NO       | NO    |
| TRIGGER        | %                   | %           | YES      | YES   |
+----------------+--------------------+-------------+---------+-------+

对setup_objects表的修改会立即影响对象监控。

在setup_objects表中列出了监控对象类型,在进行匹配时,performance_schema基于OBJECT_SCHEMA和OBJECT_NAME字段依次往后匹配,如果没有匹配的对象,则不会被监控。

在默认配置中开启监控的对象不包含mysql、information_schema和performance_schema数据库中的所有表(从上面的信息中可以看到,这几个库的ENABLED和TIMED字段值都为NO。注意:对于information_schema数据库,虽然该表中有一行配置,但是无论如何设置,都不会监控该库,在setup_objects表中information_schema.%的配置行仅作为一个缺省值)。

当performance_schema在setup_objects表中进行匹配检测时,会尝试首先找到最具体(最精确)的匹配项。例如,在匹配db1.t1表时,它会从setup_objects表中先查找“db1”和“t1”的匹配项,然后查找“db1”和“%”,最后查找“%”和“%”。匹配顺序很重要,因为不同的匹配行可能具有不同的ENABLED和TIMED字段值。

如果用户对该表具有INSERT和DELETE权限,则可以对其配置行进行删除和插入新的配置行。对于已经存在的配置行,如果用户对该表具有UPDATE权限,则可以修改ENABLED和TIMED字段,其有效值为YES或NO。

setup_objects表中各字段的含义如下。

● OBJECT_TYPE:instruments类型,有效值为EVENT(事件调度器事件)、FUNCTION(存储函数)、PROCEDURE(存储过程)、TABLE(基表)、TRIGGER(触发器),TABLE对象类型的配置会影响表I/O事件(wait/io/table/sql/handler instruments)和表锁事件(wait/lock/table/sql/handler instruments)的收集。

● OBJECT_SCHEMA:某个监控类型对象涵盖的数据库名称,可以是一个字符串或“%”(表示任意数据库)。

● OBJECT_NAME:监控类型对象的名称,可以是一个字符串或“%”(表示任意数据库内的对象)。

● ENABLED:是否开启对某个类型对象的监控功能,其有效值为YES或NO。此字段可以修改。

● TIMED:是否开启对某个类型对象的时间收集功能,其有效值为YES或NO。此字段可以修改。

提示:对于setup_objects表,允许使用TRUNCATE TABLE语句。

在setup_objects表中默认的配置规则是不启用对mysql、information_schema、performance_schema数据库下的对象进行监控(ENABLED和TIMED字段值全都为NO)。

performance_schema在setup_objects表中进行查询匹配时,如果发现某个OBJECT_TYPE字段值有多行,则会尝试匹配更多的配置行,performance_schema按照如下顺序进行检查:

OBJECT_SCHEMA ='literal' and OBJECT_NAME ='literal'
OBJECT_SCHEMA ='literal' and OBJECT_NAME ='%'
OBJECT_SCHEMA ='%' and OBJECT_NAME ='%'

例如,要匹配表对象db1.t1, performance_schema在setup_objects表中先查找“OBJECT_SCHEMA = db1”和“OBJECT_NAME = t1”的匹配项,然后查找“OBJECT_SCHEMA = db1”和“OBJECT_NAME =%”,最后查找“OBJECT_SCHEMA =%”和“OBJECT_NAME = %”。匹配顺序很重要,因为不同的匹配行中的ENABLED和TIMED字段可以有不同的值,最终会选择一个最精确的匹配项。

对于与表对象相关的事件,instruments是否生效需要将setup_objects和setup_instruments两个表中的配置项相结合,以确定是否启用instruments以及计时器功能(例如前面说的I/O事件:wait/io/table/sql/handler instruments和表锁事件:wait/lock/table/sql/handler instruments,在setup_instruments表中也有明确的配置项)。

● 只有setup_instruments表和setup_objects表中的ENABLED字段值都为YES时,表的instruments才会生成事件信息。

● 只有setup_instruments表和setup_objects表中的TIMED字段值都为YES时,表的instruments才会启用计时器功能(收集时间信息)。

例如:要监控db1.t1、db1.t2、db2.%、db3.%这些表,setup_instruments和setup_objects两个表中有如下配置项。

# setup_instruments
mysql> select * from setup_instruments where name like '%/table/%';
+---------------------------------+---------+-------+
| NAME                             | ENABLED | TIMED |
+---------------------------------+---------+-------+
| wait/io/table/sql/handler       | YES     | YES    |
| wait/lock/table/sql/handler     | YES     | YES    |
+---------------------------------+---------+-------+
2 rows in set(0.00 sec)
# setup_objects
mysql> select * from setup objects;
+----------------+---------------+-------------+--------+-------+
| OBJECT_TYPE    | OBJECT_SCHEMA  | OBJECT_NAME | ENABLED| TIMED |
+----------------+---------------+-------------+--------+-------+
| TABLE          | db1            | t1          | YES    | YES   |
| TABLE          | db1            | t2          | NO     | NO    |
| TABLE          | db2            | %           | YES    | YES   |
| TABLE          | db3            | %           | NO     | NO    |
| TABLE          | %              | %           | YES    | YES   |
+----------------+---------------+-------------+--------+-------+
# 以上两个表中的配置项结合之后,只有 db1.t1db2.%%.%表对象的 instruments 会被启用,db1.t2 db3.%不会被启用,因为这两个对象在setup_objects表中ENABLEDTIMED字段值都为NO

对于与存储程序对象相关的事件,performance_schema只需要从setup_objects表中读取配置项的ENABLED和TIMED字段值即可。因为存储程序对象在setup_instruments表中没有对应的配置项。

如果持久性表和临时表名称相同,则在setup_objects表中进行匹配时,针对这两种类型的表的匹配规则同时生效(不会发生一个表启用监控,另一个表不启用监控的情况)。

5.3.7 threads表

threads表对于每个Server线程都会生成一行线程相关信息,例如:显示是否启用监控和历史事件记录功能。

mysql> select * from threads where TYPE='FOREGROUND' limit 2\G
*************************** 1. row ***************************
          THREAD_ID: 43
              NAME: thread/sql/compress_gtid_table
              TYPE: FOREGROUND
    PROCESSLIST_ID: 1
  PROCESSLIST_USER: NULL
  PROCESSLIST_HOST: NULL
    PROCESSLIST_DB: NULL
PROCESSLIST_COMMAND: Daemon
  PROCESSLIST_TIME: 27439
  PROCESSLIST_STATE: Suspending
  PROCESSLIST_INFO: NULL
  PARENT_THREAD_ID: 1
              ROLE: NULL
      INSTRUMENTED: YES
            HISTORY: YES
    CONNECTION_TYPE: NULL
      THREAD_OS_ID: 3652
*************************** 2. row ***************************
............
2 rows in set(0.00 sec)

当performance_schema初始化时,它根据当时存在的线程在threads表中为每个线程都生成一行信息。此后,每新建一个线程,在该表中就会新增一行信息。

新线程信息的INSTRUMENTED和HISTORY字段值由setup_actors表中的配置决定。

当某个线程结束时,会从threads表中删除对应行。对于与客户端会话关联的线程,当会话结束时会删除threads表中该线程配置行。如果客户端自动重新连接,则也相当于断开一次(会删除断开连接的配置行),再重新创建新的连接,两次连接创建的PROCESSLIST_ID字段值不同。新线程的初始INSTRUMENTED和HISTORY字段值可能与断开之前线程的初始INSTRUMENTED和HISTORY字段值不同。在此期间setup_actors表可能已发生更改,并且如果一个线程在创建之后,后续又修改了setup_actors表中的INSTRUMENTED或HISTORY字段值,那么后续修改的值不会影响threads表中已经创建好的线程的INSTRUMENTED或HISTORY字段值。

以PROCESSLIST_开头的字段提供了与INFORMATION_SCHEMA.PROCESSLIST表或SHOW PROCESSLIST语句类似的信息,但threads表中的信息来源与它们有所不同。

● 对threads表的访问不需要互斥体,对Server性能影响最小。而使用INFORMATION_SCHEMA.PROCESSLIST表和SHOW PROCESSLIST语句查询线程信息的方式会损耗一定的性能,因为它们需要互斥体。

● threads表为每个线程都提供了附加信息,例如:它是前台线程还是后台线程,以及与线程相关联的Server内部信息。

● threads表可以提供有关后台线程的信息,而INFORMATION_SCHEMA.PROCESSLIST表和SHOW PROCESSLIST语句不能提供相关信息。

● 可以通过threads表中的INSTRUMENTED和HISTORY字段分别灵活地动态开关某个线程的监控和历史事件记录功能。要控制新的前台线程的初始INSTRUMENTED和HISTORY字段值,则可以通过setup_actors表的HOST、USER字段对某个主机、用户进行配置。要控制已创建线程的采集和历史事件记录功能,则可以通过threads表的INSTRUMENTED和HISTORY字段进行配置。

● 对于INFORMATION_SCHEMA.PROCESSLIST表和SHOW PROCESSLIST语句,需要有PROCESS权限;而对于threads表,只要有SELECT权限就可以查看所有用户的线程信息。

threads表中各字段的含义如下。

● THREAD_ID:线程的唯一标识符(ID)。

● NAME:与Server中的线程检测代码相关联的名称(注意,这里不是instruments名称)。例如,thread/sql/one_connection对应于负责处理用户连接的代码中的线程函数名,thread/sql/main表示Server的main()函数名称。

● TYPE:线程类型,有效值为FOREGROUND和BACKGROUND,分别表示前台线程和后台线程。如果是用户创建的连接或者和复制线程创建的连接,则标记为前台线程,如复制I/O和SQL线程、Worker线程、Dump线程等;如果是Server内部创建的线程(用户不能干预的线程),则标记为后台线程,如InnoDB的后台I/O线程等。

● PROCESSLIST_ID:对应于INFORMATION_SCHEMA.PROCESSLIST表中的ID字段。该字段值与SHOW PROCESSLIST语句、INFORMATION_SCHEMA.PROCESSLIST表、connection_id()函数返回的线程ID值相等。另外,threads表中记录了内部线程,而INFORMATION_SCHEMA.PROCESSLIST表中没有记录内部线程,所以对于内部线程,在threads表中该字段值显示为NULL。因此,在threads表中NULL值不唯一(可能有多个后台线程)。

● PROCESSLIST_USER:与前台线程关联的用户名,对于后台线程为NULL。

● PROCESSLIST_HOST:与前台线程关联的客户端的主机名,对于后台线程为NULL。与INFORMATION_SCHEMA.PROCESSLIST表的HOST字段或SHOW PROCESSLIST语句输出的主机字段不同,PROCESSLIST_HOST字段不包括TCP/IP连接的端口号。要从performance_schema中获取端口信息,需要查询socket_instances表(关于socket的wait/io/socket/sql/* instruments默认关闭)。

● PROCESSLIST_DB:线程的默认数据库,如果没有,则该字段值为NULL。

● PROCESSLIST_COMMAND:对于前台线程,该字段值代表当前客户端正在执行的command,如果是sleep,则表示当前会话处于空闲状态。对于后台线程,则不会执行这些command,因此此字段值可能为NULL。

● PROCESSLIST_TIME:线程已处于当前状态的持续时间(秒)。

● PROCESSLIST_STATE:表示线程正在做什么事情。如果字段值为NULL,则该线程可能处于空闲状态或者是一个后台线程。大多数状态停留的时间非常短暂。如果一个线程在某个状态下停留了非常长的时间,则表示可能有性能问题需要排查。

● PROCESSLIST_INFO:线程正在执行的语句,如果没有执行任何语句,则该字段值为NULL。该语句可能是发送到Server的语句,也可能是其他语句执行时内部调用的语句。例如:如果CALL语句执行存储程序,并且在存储程序中正在执行SELECT语句,那么PROCESSLIST_INFO字段值将显示为SELECT语句。

● PARENT_THREAD_ID:如果线程是一个子线程(由另一个线程生成),那么该字段值显示为其父线程ID。

● ROLE:暂未使用。

● INSTRUMENTED:线程执行的事件是否被检测,其有效值为YES或NO。

对于前台线程,初始INSTRUMENTED字段值还需要看控制前台线程的setup_actors表中的ENABLED字段值。如果在setup_actors表中找到了对应的用户名和主机行,则会用该表中的ENABLED字段值生成threads表中的INSTRUMENTED字段值,setup_actors表中的USER和HOST字段值也会被一并写入threads表的PROCESSLIST_USER和PROCESSLIST_HOST字段中。如果某个线程产生了一个子线程,则该子线程会再次与setup_actors表进行匹配。

对于后台线程,INSTRUMENTED字段值默认为YES。其初始值无须查看setup_actors表,该表不控制后台线程,因为后台线程没有关联的用户。

对于任何线程,都可以在该线程的生命周期内更改其INSTRUMENTED字段值。

要监控线程产生的事件,需要满足如下条件:

■ setup_consumers表中的thread_instrumentation consumers必须为YES。

■ threads.INSTRUMENTED字段值必须为YES。

■ 在setup_instruments表中与线程相关的instruments配置行的ENABLED字段值必须为YES。

■ 如果是前台线程,那么setup_actors表中对应主机和用户配置行中的ENABLED字段值必须为YES。

● HISTORY:是否记录线程的历史事件,其有效值为YES或NO。

对于前台线程,初始HISTORY字段值还需要看控制前台线程的setup_actors表中的HISTORY字段值。如果在setup_actors表中找到了对应的用户名和主机行,则会用该表中的HISTORY字段值生成threads表中的HISTORY字段值,setup_actors表中的USER和HOST字段值也会被一并写入threads表的PROCESSLIST_USER和PROCESSLIST_HOST字段中。如果某个线程产生了一个子线程,则该子线程会再次与setup_actors表进行匹配。

对于后台线程,HISTORY字段值默认为YES。初始值无须查看setup_actors表,该表不控制后台线程,因为后台线程没有关联的用户。

对于任何线程,都可以在该线程的生命周期内更改其HISTORY字段值。

要记录线程产生的历史事件,需要满足如下条件:

■ 在setup_consumers表中必须启用相关联的consumers配置。例如:要记录线程的等待事件历史记录,则需要启用events_waits_history和events_waits_history_long consumers。

■ threads.HISTORY字段值必须为YES。

■ 在setup_instruments表中必须启用相关联的instruments配置。

■ 如果是前台线程,那么在setup_actors表中对应主机和用户配置行中的HISTORY字段值必须为YES。

● CONNECTION_TYPE:用于建立连接的协议,如果是后台线程,字段值则为NULL。其有效值为TCP/IP(不使用SSL建立的TCP/IP连接)、SSL/TLS(与SSL建立的TCP/IP连接)、Socket(UNIX套接字文件连接)、Named Pipe(Windows命名管道连接)、Shared Memory(Windows共享内存连接)。

● THREAD_OS_ID:由操作系统层定义的线程或任务标识符(ID)。

当一个MySQL线程与操作系统中某个线程关联时,通过THREAD_OS_ID字段可以查看到与这个MySQL线程相关联的操作系统线程ID。

当一个MySQL线程与操作系统线程不关联时,THREAD_OS_ID字段值为NULL。例如,当用户使用线程池插件时:

■ 对于Windows, THREAD_OS_ID对应于Process Explorer中可见的线程ID。

■ 对于Linux, THREAD_OS_ID对应于gettid()函数获取的值。比如使用perf、ps -L命令或proc文件系统(/proc/[pid]/task/[tid])可以查看此值。

提示:对于threads表,不允许使用TRUNCATE TABLE语句。

关于线程类对象,前台线程与后台线程还有少许差别。

● 对于前台线程(使用客户端连接协议建立的连接,可以是用户发起的连接,也可以是不同Server之间发起的连接),当用户或者其他Server与某个Server创建了一个连接之后(连接方式可能是Socket或者TCP/IP),在threads表中就会记录一行这个线程的配置信息,此时threads表中该线程配置行中的INSTRUMENTED和HISTORY字段的默认值是YES还是NO,还需要看与线程相关联的用户账号是否匹配setup_actors表中的配置行(查看某用户在setup_actors表中配置行的ENABLED和HISTORY字段值为YES还是NO,在threads表中,与setup_actors表相关联的用户账号的线程配置行的ENABLED和HISTORY字段值,以setup_actors表中的值为准)。

● 对于后台线程,不可能存在关联的用户,所以threads表中的INSTRUMENTED和HISTORY字段在线程创建时的初始值默认为YES,不需要查看setup_actors表。

关闭与开启所有后台线程的事件采集功能:

# 关闭所有后台线程的事件采集功能
mysql> update threads set INSTRUMENTED='NO' where TYPE='BACKGROUND';
Query OK, 40 rows affected(0.00 sec)
Rows matched: 40  Changed: 40  Warnings: 0
# 开启所有后台线程的事件采集功能
mysql> update threads set INSTRUMENTED='YES' where TYPE='BACKGROUND';
Query OK, 40 rows affected(0.00 sec)
Rows matched: 40  Changed: 40  Warnings: 0

关闭与开启除当前连接之外的所有前台线程的事件采集功能:

# 关闭除当前连接之外的所有前台线程的事件采集功能
mysql> update threads set INSTRUMENTED='NO' where PROCESSLIST_ID! =connection_id();
Query OK, 2 rows affected(0.00 sec)
Rows matched: 2  Changed: 2  Warnings: 0
# 开启除当前连接之外的所有前台线程的事件采集功能
mysql> update threads set INSTRUMENTED='YES' where PROCESSLIST_ID! =connection_id();
Query OK, 2 rows affected(0.00 sec)
Rows matched: 2  Changed: 2  Warnings: 0
# 当然,如果要连后台线程一起操作,请带上条件PROCESSLIST_ID is NULL
update ... where PROCESSLIST_ID! =connection_id()or PROCESSLIST_ID is NULL;

温馨提示:如果阅读了本章内容之后,感觉对performance_schema仍然比较迷糊,那么建议按照如下步骤动动手、看一看。

● 使用命令行命令mysqld --verbose --help |grep performance-schema |grep -v '--' |sed '1d' |sed '/[0-9]+/d';查看完整的启动选项列表。

● 登录到数据库中,使用show variables like '%performance_schema%';语句查看完整的system variables列表。

● 登录到数据库中,使用use performance_schema;语句切换到schema下,然后使用show tables;语句查看完整的表列表,并手动执行show create table tb_xxx;语句查看表结构,执行select * from xxx;语句查看表中的内容。

performance_schema配置部分为整个performance_schema的难点,为了后续更好地学习performance_schema,建议初学者多读两遍本章内容。

提示:关于文中提到的参数的详细解释,可参考本书下载资源中的“附录C”。