01-monitor

frame 英 /freɪm, 框架;

schema 英 [ˈskiːmə] n. (计划或理论的)提要,纲要

  1. 99_install_binary.md
  2. 97_install_rpm.md
  3. 98_uninstall_rpm.md
  4. mysql_官网open in new window
  5. Chapter 27 MySQL Performance Schemaopen in new window
  6. 各种连接池性能对比测试open in new window
  7. druid_常见问题open in new window

1. 基础

  • 结合公司之前的应用场景来阐述有关调优的问题
image-20220519091424113

1. Server架构,三层

  1. Client
  2. Server
    1. 连接器
      • 采用数据库连接池,减少频繁的开关连接
    2. 分析器(开发能操作)
      • 词法分析,语法分析
    3. 优化器。自带一定优化(开发能操作)
      1. RBO:基于规则优化
      2. CBO:基于成本(代价)优化
    4. 执行器。select *是有大问题(IO)
    5. 缓存器。mysql8.0后废除
  3. Engine存储引擎
    1. InnoDB:磁盘
    2. MyISAM:磁盘
    3. Memory:内存
image-20220623193249491

2. 文件存放

# mac_mysql_data目录
sudo chmod -R a+rwx /usr/local/mysql/data
  1. InnoDB
    • 默认情况下所有数据文件放到表空间中,不会为每个表保存一份数据文件。set global innodb_file_per_table=on开启为每个表单独文件保存
    1. .frm:表结构
    2. .ibd:data和index(聚簇索引)数据文件和索引文件存放在一起
  2. MyISAM
    1. .frm:表结构
    2. .MYI:index文件
    3. .MYD:data文件
image-20220520084812264

3. 优化目标(IO)

  1. 减少IO量
  2. 减少IO次数

2. profile

  1. 客户端不能profile,客户端一个查询执行了太多其他sql了
  2. Mysql8.0取消了
  3. sql的duration精确到小数点后8位
# 调用mac本地mysql
/usr/local/mysql/bin/mysql -u root -p

# 查看所有db
show databases;

# 切换db
use mca;

# 查询profiling
show variables like 'profiling%';

# 配置耗时,开启profiling功能
set profiling = 1;

# 可以查询到具体sql详细时间
show profiles;

# sql每个阶段具体耗时(默认最近一条sql)
show profile;

# 指定sql,执行具体耗时
show profile for query 2;

-- -----------------------------------------------
# all:显示所有性能信息
show profile all for query 1;

# block io:显示块io操作的次数
show profile block io for query 1;

# context switches:显示上下文切换次数,被动和主动
show profile context switches for query 1;

# cpu:显示用户cpu时间、系统cpu时间
show profile cpu for query 1;

# IPC:显示发送和接受的消息数量
show profile ipc for query 1;

# page faults:显示页错误数量
show profile page faults for query 1;

# source:显示源码中的函数名称与位置
show profile source for query 1;

# swaps:显示swap的次数
show profile swaps for query 1;

 














































image-20220519093133452
image-20220519092313113
image-20220519092325713
  • starting, Sending data 耗时多,是正常的sql
image-20220519092334450image-20220519092608871
image-20220519092627082
image-20220519092645948
image-20220519092655101
image-20220519093116594
image-20220519093124439
image-20220519093139957
image-20220519093146445
image-20220519093220449

3. performance_schema

image-20220519093439886

1. 特点

performance_schema用于监控MySQL_Server在一个较低级别的运行过程中的资源消耗、资源等待等情况

  1. 实时检查mysql_server的内部执行情况
    • performance_schema使用performance_schema存储引擎。该数据库主要关注数据库运行过程中的性能数据
    • information_schema:Server运行过程中的元数据信息
  2. 通过监视Server的事件来监视Server内部运行情况
    • ”事件“就是Server内部活动中所做的任何事情以及对应的时间消耗,利用这些信息来判断Server中的相关资源消耗在了哪里
    • 一般来说,事件可以是函数调用、OS等待、SQL执行的阶段(parsing或sorting阶段)或者整个SQL语句与SQL语句集合。事件的采集可以方便的提供Server中的相关存储引擎对磁盘文件、表I/O、表锁等资源的同步调用信息
  3. performance_schema存储引擎使用Server源代码中的检测点来实现事件数据的收集。实现机制本身的代码没有相关的单独线程来检测,这与其他功能(如复制或事件计划程序)不同
  4. 事件与写入二进制日志中的事件(描述数据修改的events)、事件计划调度程序(这是一种存储程序)的事件不同
    • 记录Server执行某些活动对某些资源的消耗、耗时、这些活动执行的次数等情况
  5. 事件只记录在本地Server的performance_schema中,其下的这些表中数据发生变化时不会被写入binlog中,也不会通过复制机制被复制到其他Server中
  6. 当前活跃事件、历史事件、事件摘要相关的表中记录的信息。能提供某个事件的执行次数、使用时长。进而可用于分析某个特定线程、特定对象(mutex或file)相关联的活动
  7. 收集的事件数据存储在performance_schema数据库的表中。这些表可以使用select语句查询,也可以使用SQL语句更新performance_schema数据库中的表记录
    • (动态修改performance_schema的setup_*开头的几个配置表,但要注意:配置表的更改会立即生效,这会影响数据收集)
  8. performance_schema的表中的数据不会持久化存储在磁盘中,而是保存在内存中,一旦服务器重启,这些数据会丢失(包括配置表在内的整个performance_schema下的所有数据)
  9. Mysql支持的所有平台中事件监控功能都可用,但不同平台中用于统计事件时间开销的《计时器类型》可能会有所差异

2. 开启

  1. Mysql的5.7版本,性能模式是默认开启
  2. 显式关闭的话需要修改配置文件,不能直接进行修改,报错:Variable 'performance_schema' is a read only variable
show databases;

# 切换数据库
use performance_schema;

# 87张表
show tables;

# 开关
show variables like 'performance_schema';
# 'performance_schema', 'ON'

# 只读无法设置,配置文件修改
set performance_schema = off;
# [HY000][1238] Variable 'performance_schema' is a read only variable

# 查看表结构
show create table setup_consumers;

-- ---------------------------------------------------------------
create table setup_consumers
(
    NAME    varchar(64)        not null,
    ENABLED enum ('YES', 'NO') not null
)
    engine = PERFORMANCE_SCHEMA;



 









 
 











# 修改配置文件
cd /etc/
vi my.cnf
# performance_schema,ON开启,OFF关闭
[mysqld]
performance_schema=ON


 

理解两个基本概念:

  1. instruments生产者:采集Mysql中各种各样event_info,对应配置表中的配置项称为《event_info采集配置项》
    • 采集项的配置表中每一项都有一个开关字段(YES,NO)
  2. consumers消费者:存储Mysql中各种各样event_info,对应配置表中的配置项称为《event_info存储配置项》
    • 存储项的配置表中每一项都有一个开关字段(YES,NO)

3. 表的分类(87张)

# 监视不同的纬度进行分组
use performance_schema;

# 聚合后的摘要表summary
# summary表还可以根据帐号(account)、主机(host)、程序(program)、线程(thread)、用户(user)和全局(global)再进行细分

# 《语句事件记录表》这些表记录了语句事件信息
# 《当前语句事件表》events_statements_current
# 《历史语句事件表》events_statements_history
# 《长语句历史事件表》events_statements_history_long
show tables like '%statement%';

# 《等待事件记录表》与语句事件类型的相关记录表类似
show tables like '%wait%';

# 《阶段事件记录表》记录语句执行的阶段事件的表
show tables like '%stage%';

# 《事务事件记录表》记录事务相关的事件的表
show tables like '%transaction%';

# 监控文件系统层调用的表
show tables like '%file%';

# 监控内存使用的表
show tables like '%memory%';

# 动态对performance_schema进行配置的配置表
show tables like '%setup%';

 



























4. 简单配置与使用

  • DB刚刚初始化并启动时,并非所有instrumentsconsumers都启用了,所以默认不会收集所有的事件(因MySQL版本而异)
use performance_schema;

# 查看所有配置开关
select * from setup_instruments;
select * from setup_consumers;

# 打开《等待event_info采集配置项》开关
update setup_instruments set enabled = 'YES', timed = 'YES' where name like 'wait%';

# 打开《等待event_info存储配置项》开关
update setup_consumers set enabled = 'YES' where name like '%wait%';


# _current表中每个线程只保留一条记录,一旦线程完成工作,该表中不会再记录该线程的事件信息
# events_waits_current,该表中每个线程只包含一行数据,用于显示每个线程的最新监视事件
select * from events_waits_current;
*************************** 1. row ***************************
            THREAD_ID: 11
             EVENT_ID: 570
         END_EVENT_ID: 570
           EVENT_NAME: wait/synch/mutex/innodb/buf_dblwr_mutex
               SOURCE:
          TIMER_START: 4508505105239280
            TIMER_END: 4508505105270160
           TIMER_WAIT: 30880
                SPINS: NULL
        OBJECT_SCHEMA: NULL
          OBJECT_NAME: NULL
           INDEX_NAME: NULL
          OBJECT_TYPE: NULL
OBJECT_INSTANCE_BEGIN: 67918392
     NESTING_EVENT_ID: NULL
   NESTING_EVENT_TYPE: NULL
            OPERATION: lock
      NUMBER_OF_BYTES: NULL
                FLAGS: NULL
# 该信息表示线程id为11的线程正在等待buf_dblwr_mutex锁,等待事件为30880
# 属性说明:
# 	id: 事件来自哪个线程,事件编号是多少
# 	event_name: 检测到的具体的内容
# 	source: 这个检测代码在哪个源文件中以及行号
# 	timer_start: 该事件的开始时间
# 	timer_end: 该事件的结束时间
# 	timer_wait: 该事件总的花费时间

# _history表:记录每个线程应该执行完成的事件信息,但每个线程的事件信息只会记录10条,再多就会被覆盖
# _history_long表:记录所有线程的事件信息,但总记录数量是10000,超过就会被覆盖掉
select thread_id, event_id, event_name, timer_wait from events_waits_history order by thread_id limit 21;


# _summary_表:提供所有事件的汇总信息,该组中的表以不同的方式汇总事件数据(如:按用户、主机、线程等等)
# eg:要查看哪些instruments占用最多的时间,可以通过对events_waits_summary_global_by_event_name表的COUNT_STAR或SUM_TIMER_WAIT列进行查询
# (这两列是对事件的记录数执行COUNT(*)、事件记录的TIMER_WAIT列执行SUM(TIMER_WAIT)统计而来)
SELECT EVENT_NAME, COUNT_STAR FROM events_waits_summary_global_by_event_name ORDER BY COUNT_STAR DESC LIMIT 10;


# _instance表:记录了哪些类型的对象会被检测。这些对象在被server使用时,在该表中将会产生一条事件记录
# eg:file_instances表列出了文件I/O操作及其关联文件名
select * from file_instances limit 20;
 


 
 






















































5. 常用配置项说明

1. 启动选项

# 启动之后也可以在setup_consumers表中使用UPDATE语句进行动态更新配置项

# 开机启动events_statements_current表的记录功能(该表记录当前的语句事件信息),默认值为TRUE
performance_schema_consumer_events_statements_current=TRUE

# 类似上,配置是否记录语句事件短历史信息,默认为TRUE
performance_schema_consumer_events_statements_history=TRUE

# 类似上,配置是否记录语句事件长历史信息,默认为FALSE
performance_schema_consumer_events_stages_history_long=FALSE

# 除了statement(语句)事件之外,还支持:wait(等待)事件、state(阶段)事件、transaction(事务)事件,他们与statement事件一样都有三个启动项分别进行配置,
# 但这些等待事件默认未启用,如果需要在MySQL_Server启动时一同启动,则通常需要写进my.cnf配置文件中


# 开机启动全局表(eg:mutex_instances、rwlock_instances、cond_instances、file_instances、users、hostsaccounts、
# socket_summary_by_event_name、file_summary_by_instance等大部分的全局对象计数统计和事件汇总统计信息表)的记录功能,默认值为TRUE
performance_schema_consumer_global_instrumentation=TRUE

# 开机启动events_statements_summary_by_digest表的记录功能,,默认值为TRUE
performance_schema_consumer_statements_digest=TRUE

# 开机启动
performance_schema_consumer_thread_instrumentation=TRUE

# events_xxx_summary_by_yyy_by_event_name表的记录功能,默认值为TRUE


performance_schema_instrument[=name]
# 开机启动某些采集器,由于instruments配置项多达数千个,所以该配置项支持key-value模式,还支持%号进行通配等,如下:
# [=name]可以指定为具体的Instruments名称(但是这样如果有多个需要指定的时候,就需要使用该选项多次),
# 也可以使用通配符,可以指定instruments相同的前缀+通配符,也可以使用%代表所有的instruments

# 指定开启单个instruments
--performance-schema-instrument= 'instrument_name=value'

# 使用通配符指定开启多个instruments
--performance-schema-instrument= 'wait/synch/cond/%=COUNTED'

# 开关所有的instruments
--performance-schema-instrument= '%=ON'
--performance-schema-instrument= '%=OFF'

# 注意,这些启动选项要生效的前提是,需要设置performance_schema=ON。
# 另外,这些启动选项虽然无法使用`show variables`语句查看,但可以通过setup_instruments和setup_consumers表查询这些选项指定的值

2. 系统变量

show variables like '%performance_schema%';
# performance_schema功能的开关
# 5.7.x版本之前默认关闭,5.7.x版本开始默认开启
# 注意:如果mysqld在初始化performance_schema时发现无法分配任何相关的内部缓冲区,则performance_schema将自动禁用,并将performance_schema设置为OFF
performance_schema=ON

# 控制events_statements_summary_by_digest表中的最大行数
# 如果产生的语句摘要信息超过此最大值,便无法继续存入该表,此时performance_schema会增加状态变量
performance_schema_digests_size=10000

# 控制events_statements_history_long表中的最大行数
# 该参数控制所有会话在events_statements_history_long表中能够存放的总事件记录数,超过这个限制之后,最早的记录将被覆盖
# 全局变量,只读变量,整型值,5.6.3版本引入
# 5.6.x版本中,5.6.5及其之前的版本默认为10000,5.6.6及其之后的版本默认值为-1,通常情况下,自动计算的值都是10000
# 5.7.x版本中,默认值为-1,通常情况下,自动计算的值都是10000
performance_schema_events_statements_history_long_size=10000

# events_statements_history表中单个线程(会话)的最大行数
# 控制单个会话在events_statements_history表中能够存放的事件记录数,超过这个限制之后,单个会话最早的记录将被覆盖
# 全局变量,只读变量,整型值,5.6.3版本引入
# 5.6.x版本中,5.6.5及其之前的版本默认为10,5.6.6及其之后的版本默认值为-1,通常情况下,自动计算的值都是10
# 5.7.x版本中,默认值为-1,通常情况下,自动计算的值都是10
# 除了statement(语句)事件之外,wait(等待)事件、state(阶段)事件、transaction(事务)事件,与statement事件一样都有三个参数分别进行存储限制配置
performance_schema_events_statements_history_size=10

# 用于控制标准化形式的SQL在存入performance_schema的限制长度,该变量与max_digest_length变量相关(max_digest_length变量含义请自行查阅相关资料)
# 全局变量,只读变量,默认值1024字节,整型值,取值范围0~1048576
performance_schema_max_digest_length=1024

# 控制存入events_statements_current、events_statements_history和events_statements_history_long语句事件表中的SQL_TEXT列的最大SQL长度字节数。
# 超出系统变量performance_schema_max_sql_text_length的部分将被丢弃,不会记录,一般情况下不需要调整该参数,除非被截断的部分与其他SQL比起来有很大差异
# 全局变量,只读变量,整型值,默认值为1024字节,取值范围为0~1048576,5.7.6版本引入
# 降低该值可以减少内存使用,但如果汇总的SQL中,被截断部分有较大差异,会导致没有办法再对这些有较大差异的SQL进行区分。
# 增加该值会增加内存使用,但对于汇总SQL来讲可以更精准地区分不同的部分。
performance_schema_max_sql_text_length=1024

6. 配置表相互关系

  • performance_schema库中还包含了很多其他的库、表,对DB的性能做完整监控,参考官网详细了解
  • 配置表之间相互关联关系,按照配置影响的先后顺序,可添加为
image-20240323111431353
# 记录了server中有哪些可用的事件计时器
# 字段解释:
# 	timer_name:表示可用计时器名称,CYCLE是基于CPU周期计数器的定时器
# 	timer_frequency:表示每秒钟对应的计时器单位的数量,CYCLE计时器的换算值与CPU的频率相关、
# 	timer_resolution:计时器精度值,表示在每个计时器被调用时额外增加的值
# 	timer_overhead:表示在使用定时器获取事件时开销的最小周期值
select * from performance_timers;

# 记录当前使用的事件计时器信息
# 字段解释:
# 	name:计时器类型,对应某个事件类别
# 	timer_name:计时器类型名称
select * from setup_timers;

# 列出了consumers可配置项
# 字段解释:
# 	NAME:consumers配置名称
# 	ENABLED:consumers是否启用,有效值为YES或NO,此列可以使用UPDATE语句修改
select * from setup_consumers;

# 列出了instruments可配置项,即代表了哪些事件支持被收集
# 字段解释:
# 	NAME:instruments名称,可能具有多个部分并形成层次结构
# 	ENABLED:instrumetns是否启用,有效值为YES或NO,此列可以使用UPDATE语句修改。如果设置为NO,则这个instruments不会被执行,不会产生任何的事件信息
# 	TIMED:instruments是否收集时间信息,有效值为YES或NO,此列可以使用UPDATE语句修改,如果设置为NO,则这个instruments不会收集时间信息
SELECT * FROM setup_instruments;

# setup_actors表的初始内容是匹配任何用户和主机,因此对于所有前台线程,默认情况下启用监视和历史事件收集功能
# 字段解释:
# 	HOST:与grant语句类似的主机名,一个具体的字符串名字,或使用“%”表示“任何主机”
# 	USER:一个具体的字符串名称,或使用“%”表示“任何用户”
# 	ROLE:当前未使用,MySQL 8.0中才启用角色功能
# 	ENABLED:是否启用与HOST,USER,ROLE匹配的前台线程的监控功能,有效值为:YES或NO
# 	HISTORY:是否启用与HOST, USER,ROLE匹配的前台线程的历史事件记录功能,有效值为:YES或NO
SELECT * FROM setup_actors;

# 控制performance_schema是否监视特定对象。默认情况下,此表的最大行数为100行
# 字段解释:
# 	OBJECT_TYPE:
# 		instruments类型,有效值为:“EVENT”(事件调度器事件)、“FUNCTION”(存储函数)、“PROCEDURE”(存储过程)、“TABLE”(基表)、“TRIGGER”(触发器),
# 		TABLE对象类型的配置会影响表I/O事件(wait/io/table/sql/handler instrument)和表锁事件(wait/lock/table/sql/handler instrument)的收集
# 	OBJECT_SCHEMA:某个监视类型对象涵盖的数据库名称,一个字符串名称,或“%”(表示“任何数据库”)
# 	OBJECT_NAME:某个监视类型对象涵盖的表名,一个字符串名称,或“%”(表示“任何数据库内的对象”)
# 	ENABLED:是否开启对某个类型对象的监视功能,有效值为:YES或NO。此列可以修改
# 	TIMED:是否开启对某个类型对象的时间收集功能,有效值为:YES或NO,此列可以修改
SELECT * FROM setup_objects;

# 对于每个server线程生成一行包含线程相关的信息,
# 字段解释:
# 	THREAD_ID:线程的唯一标识符(ID)
# 	NAME:与server中的线程检测代码相关联的名称(注意,这里不是instruments名称)
# 	TYPE:线程类型,有效值为:FOREGROUND、BACKGROUND。分别表示前台线程和后台线程
# 	PROCESSLIST_ID:对应INFORMATION_SCHEMA.PROCESSLIST表中的ID列
# 	PROCESSLIST_USER:与前台线程相关联的用户名,对于后台线程为NULL
# 	PROCESSLIST_HOST:与前台线程关联的客户端的主机名,对于后台线程为NULL
# 	PROCESSLIST_DB:线程的默认数据库,如果没有,则为NULL
# 	PROCESSLIST_COMMAND:对于前台线程,该值代表着当前客户端正在执行的command类型,如果是sleep则表示当前会话处于空闲状态
# 	PROCESSLIST_TIME:当前线程已处于当前线程状态的持续时间(秒)
# 	PROCESSLIST_STATE:表示线程正在做什么事情
# 	PROCESSLIST_INFO:线程正在执行的语句,如果没有执行任何语句,则为NULL
# 	PARENT_THREAD_ID:如果这个线程是一个子线程(由另一个线程生成),那么该字段显示其父线程ID
# 	ROLE:暂未使用
# 	INSTRUMENTED:线程执行的事件是否被检测。有效值:YES、NO
# 	HISTORY:是否记录线程的历史事件。有效值:YES、NO *
# 	THREAD_OS_ID:由操作系统层定义的线程或任务标识符(ID)
select * from threads;

7. 实践

# 1. 哪类的sql执行最多?
select digest_text, count_star, first_seen, last_seen
from events_statements_summary_by_digest
order by count_star desc;

# 2. 哪类sql的平均响应时间最多?
select digest_text, avg_timer_wait
from events_statements_summary_by_digest
order by count_star desc;

# 3. 哪类sql排序记录数最多?
select digest_text, sum_sort_rows
from events_statements_summary_by_digest
order by count_star desc;

# 4. 哪类sql扫描记录数最多?
select digest_text, sum_rows_examined
from events_statements_summary_by_digest
order by count_star desc;

# 5. 哪类sql使用临时表最多?
select digest_text, sum_created_tmp_tables, sum_created_tmp_disk_tables
from events_statements_summary_by_digest
order by count_star desc;

# 6. 哪类sql返回结果集最多?
select digest_text, sum_rows_sent
from events_statements_summary_by_digest
order by count_star desc;

# 7. 哪个表物理IO最多?
select file_name, event_name, sum_number_of_bytes_read, sum_number_of_bytes_write
from file_summary_by_instance
order by sum_number_of_bytes_read + sum_number_of_bytes_write desc;

# 8. 哪个表逻辑IO最多?
select object_name, count_read, count_write, count_fetch, sum_timer_wait
from table_io_waits_summary_by_table
order by sum_timer_wait desc;

# 9. 哪个索引访问最多?
select object_name, index_name, count_fetch, count_insert, count_update, count_delete
from table_io_waits_summary_by_index_usage
order by sum_timer_wait desc;

# 10. 哪个索引从来没有用过?
select object_schema, object_name, index_name
from table_io_waits_summary_by_index_usage
where index_name is not null
  and count_star = 0
  and object_schema <> 'mysql'
order by object_schema, object_name;

# 11. 哪个等待事件消耗时间最多?
select event_name, count_star, sum_timer_wait, avg_timer_wait
from events_waits_summary_global_by_event_name
where event_name != 'idle'
order by sum_timer_wait desc;

# 12-1. 剖析某条sql的执行情况,包括statement信息、stege信息、wait信息
select event_id, sql_text
from events_statements_history
where sql_text like '%count(*)%';

# 12-2. 查看每个阶段的时间消耗
select event_id, event_name, source, timer_end - timer_start
from events_stages_history_long
where nesting_event_id = 1553;

# 12-3. 查看每个阶段的锁等待情况
select event_id,
       event_name,
       source,
       timer_wait,
       object_name,
       index_name,
       operation,
       nesting_event_id
from events_waits_history_long
where nesting_event_id = 1553;

4. processlist

# 查看mysql数据库连接。id即为thread_id,kill该id即断开连接
show processlist;

# 写代码一定要关闭数据库连接

 


image-20220519094013098
image-20220519164144695
image-20220519094024665
image-20220519094034020

5. 连接池


  1. dbcp,没人用了
  2. c3p0
  3. durid
  4. HikariCP,号称“性能杀手”,只是查询快,PSCache不支持,ExceptionSorter不支持