涂抹mysql笔记-mysql性能调优和诊断

时间:2023-03-10 01:14:11
涂抹mysql笔记-mysql性能调优和诊断

<>关键性指标
1、IOPS(Input/Output operations Per Second)每秒处理的I/O请求次数:需要说明的一点,通常提到磁盘读写能力,比如形容它每秒读300M写200M这个说的是数据吞吐量(I/O能力的另一个关键指标),但是IOPS指的不是数据吞吐量,它指的是每秒能够处理的I/O请求次数。什么是一次I/O请求呢?举个例子:读写100M的文件就是一次I/O请求,写入1B的数据也是一次I/O请求。IOPS指标越高,那么单位时间内能够响应的请求自然也就越多。从理论上来讲,只要系统实际的请求数低于IOPS能力,就相当于每一个请求都能及时得到响应,那么I/O就不会是瓶颈了。如果想I/O系统的响应够快那么IOPS越高越好。IOPS指标比较高的话,就更适合要求快速响应的系统,尤其是对于短连接、小事务、轻量数据位操作特点的OLTP系统,当然吞吐量也很重要,但 吞吐量对于磁盘性能来说基本是个确定的值,没有讨论空间。
传统磁盘完成一个I/O请求所花费的时间受3个方面因素影响:
(1)寻道时间(Tseek):将磁头移动到数据所在的磁道上所需要的时间,通常都在3-15毫秒
(2)旋转延迟时间(Trotation):将盘片旋转,使所请求的数据所在扇区移动至磁头下方所需要的时间,这个时间跟磁盘的转速密切相关,转速越快延迟越短,一般15000转的磁盘平均旋转延迟为2ms
(3)数据传输时间(Transfer):完成传输所请求的数据所需要的时间。数据传输时间跟要传输的数据量密切相关,而传输数据块又与吞吐量密切相关。

假定数据要传输的数据量很小或者吞吐量极高,数据能在瞬间完成(忽略数据传输时间)。那么可以计算出理论上最大的IOPS,计算公式为:
IOPS=1000ms/(寻道时间+旋转延迟时间)基于这个公式计算的话单块SAS 15k转的磁盘,其最大IOPS=1000/(3+2)=200个每秒。这是理论上的最大值。
要提高IOPS,目前来看基本就是拼硬件,传统方案使用多块磁盘通过RAID条带后使IO读写能力获得提升。
比如我们希望IOPS达到5000,那么理论上就需要5000/200=25块磁盘组成RAID0来实现。
RAID5每个写IO操作时间将产生4次IO,若使用RAID5条带后的存储系统写入时IOPS能达到5000个/s,那么至少需要4x5000/200=100块磁盘,实际上极少会存在纯写而不读取的系统,更多都是读写平均或者读都写少。假如仍然是套RAID5条带过的存储系统,平均下来系统有1/3时间在做写入操作,2/3座读取操作那么实际需要的磁盘数就可能变为(2/3x5000+4x1/3x5000)/200约需要50块磁盘。总之不管是吞吐量还是IOPS组RAID时磁盘数移动要留足富裕。
2、QPS(Query Per Second)每秒请求(查询)次数:可在mysql命令行下输入status或者通过mysqladmin附加status参数都能查到QPS指标
QPS=Questions/Uptime,不过这个Uptime一般使我们自己定义的时间段
3、TPS(Transaction Per Second)每秒事务数:TPS=(Com_commit+Com_rollback)/Seconds Seconds是我们定义的时间间隔,如果换成Uptime就是该mysql实例在本次生命周期的平均TPS

<>获取关键性能指标
1、手动获取性能指标:
QPS指标:show global status like 'Questions';
system@(none)>show global status like 'Questions';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Questions | 42 |
+---------------+-------+
1 row in set (0.00 sec)
2、自动获取性能指标
QPS:mysqladmin -h 192.168.1.6 -usystem -poralinux extended-status -r -i 1 |grep "Questions"
mysqlslap:mysql自带轻量压测工具。例:在另一个会话中的jason库下模拟30个用户连接,共执行100万次请求共测试运行10次:
mysqlslap -h 192.168.1.6 -usystem -poralinux --query="select user,host from mysql.user" --number-of-queries=100000 -c 30 -i 10 --create-schema=jason
mysqlslap -h 192.168.1.6 -usystem -poralinux --auto-generate-sql --auto-generate-sql-add-autoincrement --auto-generate-sql-execute-number=100000 --auto-generate-sql-unique-query-number=10000 -c 30 --commit=10000 --create-schema=jason
具体mysqlslap这里不做详细介绍。
TPS:mysqladmin -h 192.168.1.6 -usystem -poralinux extended-status -r -i 1 |grep -E "Com_commit | Com_rollback"
另一个会话中执行:
mysqlslap -h 192.168.1.6 -usystem -poralinux --auto-generate-sql --auto-generate-sql-add-autoincrement --auto-generate-sql-execute-number=10000 --auto-generate-sql-unique-query-number=1000 -c 30 --commit=1 --create-schema=jason
3、TPCC测试

<>数据库参数配置优化
连接相关参数:
max_connections:指定mysql服务端最大并发连接数。范围1-10万,默认为151,一般设置在500-2000都没有太大问题。
max_connect_errors:指定允许连接不成功的最大尝试次数。如果尝试连接的错误数量超过该参数指定值,则服务器就不在允许新的连接。实际表现就是拒绝。这样就无法创建新的连接了。出现这种情况在已经连接的会话中执行flush hosts;使状态清零,或者重新启动mysql服务。这个参数的默认值较小建议加大。一般设置在10万以上的量级。
interactive_timeout和wait_timeout:这两个参数都与连接会话的自动超时断开有关。前者用于指定关闭交互连接前等待的时间。后者用于指定关闭非交互连接前的等待时间。单位均是秒,默认28800即8个小时
是否是交互模式取决于客户端创建连接调用mysql_real_connect()函数时指定的client_interactive选项,如果指定了这个选项,那么wait_timeout的值就会被interactive_timeout值覆盖,这是基于mysql的实现机制进行的设置,因此这两个参数必须被同时设置(如果不确定所使用的客户端到底使用交互还是非交互模式)这个参数的参数值设置有些讲究,不能太小负责可能出现连上去后一会会话就被断开,可是又不能设置太大,否则可能存在长时间不操作但占据着连接资源(如果前端应用层没有主动断开的话)建议设置时长不要超过24小时。
skip-name-resole:可以将之简单理解为禁用DNS解析。这个是服务端行为,;连接时不检查客户端主机名,而只使用IP。如果指定了这个参数,那么在创建用户及授予权限时,HOST列必须是IP而不能是主机名,建议启用本参数,对于加快网络连接速度有一定帮助,相当于跳过域名解析。
back_log:指定mysql连接请求队列中存放的最大连接请求数量,在5.6.6版本之前默认是50个最大不能超过65535.5.6.6版本之后默认为-1,表示由mysql自动调节。所谓自动调节其实也有规则即50+(max_connections/5),该参数应对短时间内有大量的连接请求,mysql主线程无法及时为每一个连接请求分配或者创建连接的线程。但它也不能直接拒绝,于是就会将一部分请求放到等待队列中待处理。 这个队列的长度就是back_log的参数值,若队列也被放满了,那么后续的连接请求才会被拒绝。

<>文件相关参数
1、sync_binlog:指定同步二进制日志文件的频率,默认为0。二进制日志有自己的换存区(binlog_cache_size控制)一般会先写到换存中。当sync_binlog设置为0时就表示mysql不关注二进制文件何时刷新,完全交由它自己的缓存机制决定何时刷新磁盘文件,这种情况下性能肯定是好的。但存在一定风险,若mysql服务宕机,缓存中未来得及刷新到磁盘的数据就丢失了。当sync_binlog的值设置为n(n>0)时就表示mysql每进行n次事务后,就触发同步其binary log到磁盘。如果说将sync_binlog参数设置为1,这种情况下即使数据库服务崩溃最多丢失一条语句的数据或者一个事务数据。当然每个事务同步肯定会对性能产生影响。就作者本人而言2/4/6/8/16都是不错的选择
2、expire_logs_days:指定设置二进制日志文件的生命周期,超出将自动被删除,参考值以天为单位。值范围总0-99默认是0。为0时表示不自动删除二进制日志文件需要dba手工进行清理。一般设置7-14之间足够。自动清除操作一般会在启动或二进制日志被flushed时,手动删除二进制日志可以通过PURGE BINARY LOGS语句进行,不建议直接在操作系统层删除物理文件。
3、max_binlog_size:指定二进制日志文件的大小,值的范围从4kb-1GB默认为1GB
4、local_infile:指定是否允许从客户端本地加载数据,该参数值为布尔型,默认为允许。可以说是LOAD DATA INFILE的专用参数。
5、open_files_limit:指定操作系统运行mysqld进程使用文件描述符数量。正常情况下,mysql会按照规则从下列的3个条件中,选择值最大的一项作为参数值。
10+max_connections+(table_open_cache*2)
max_connections*5
启动时指定的open_files_limit参数值大小,未指定默认为5000

<>缓存控制参数
1、binlog_cache_size:指定二进制日志事务缓存区的大小,默认值为32KB,最大2。一般设置为8或16MB即可满足大多数场景。如果经常使用大量含有多条sql语句的事务,可以通过调高该参数来获得性能的提升,不过最大不建议超过64MB,这主要是考虑到这个参数是为每一个连接的(支持事务)客户端分配内存,如果连接的客户端较多,每个会话二进制日志缓存占用过多,也不利于系统的整体性能。
2、max_binlog_cache_size:与binlog_cache_size密切相关,主要用来指定binlog能够使用的最大内存区。一般建议该参数为binlog_cache_size的两倍大小即可。
3、binlog_stmt_cache_size:可以理解为非事务语句的binlog_cache_size
4、table_open_cache:指定mysql同时能打开的表对象的数量,这个参数至少1000起步
5、thread_cache_size:指定mysql为快速重用而缓存的线程数量。值范围0-16384,默认为0。一般当客户端中断连接后为了后续再有连接创建时,能够快速创建成功,mysql会将客户端中断的连接放入缓存区,而不是马上中断并释放连接。这样当有新的客户端请求连接时就可以快速创建成功。本参数建议在300-500之间均可。线程缓存的命中率也是一项比较重要的监控指标:(1-Thread_created/Connections)*100%,大家可以通过计算这项指标的值来优化和调整thread_cache_size参数
6、query_cache_size:指定用于缓存查询结果集的内存区大小,该参数值应为1024的整倍数。太小缓存结果集就没有意义,热点数据保存不了多少,而且总是很快就被刷新出去。但是也不能太大,负责可能占用过多的内存资源。影响整机性能。太大意义不大会浪费内存。建议大小不要超过256M
7、query_cache_limit:用来控制查询缓存,能够缓存的单条sql语句生成的最大结果集。默认是1M,超出就不要进入查询缓存。默认值即可。
8、query_cache_min_res_unit:指定查询缓存最小分配的块大小,默认为4K。最大能够支持到2。如果查询多数都是小结果集,那么当指定的块比较大时,就可能会导致内存分裂,这种情况下降低query_cache_min_res_unit的值可能就更合适。如果查询都是大结果集的话增大该参数值可能更合适。可视情况增大到query_cache_limit指定的值。
9、query_cache_type:设置查询缓存类型。支持全局或会话级进行设置
0orOFF:不适用查询缓存,本选项并不会关闭查询缓存区,不过不想分配查询缓存的内存空间,还需将query_cache_size值设为0
1orON:缓存除select sql_no_cache之外的查询结果,本参数的默认值
2orDEMAND:只缓存select sql_cache的查询结果
show global status like 'Qcache%';获取查询缓存的情况。查询缓存的命中率:Qcache_his * 100/(Qcache_hits+Qcache_inserts)
10、sort_buffer_size:指定单个会话能够使用的排序区的大小,默认为256KB,最大2。一般单个会话执行的语句进行排序操作时,会使用这不跟空间,如果排序的数据在sort_buffer_size指定的区域内就可以完成排查,那么所有的操作都是在内存中进行,性能自然很好。否则的话mysql就不得不使用临时表来交换排序,要知道临时表可是创建在磁盘上的文件,这个性能相比内存中的运行效率差距不知道有多少倍。通常当发现状态变量sort_merge_passes值比较大时,可以考虑增加sort_buffer_size参数值的大小。这个参数一般设置在1-4MB之间即可。
11、read_buffer_size:指定顺序读取时的数据缓冲区大小,默认128KB最大能支持2GB。从表中读取数据时也会应用缓存,从表中读取塑化剂其实有两种方式,一种是顺序读取(全表扫描),另一种是随机读取(索引扫描)。当采用顺序方式读取时,数据就会保存在read_buffer_size指定的缓存区中。该参数设置时应为4KB的整数倍,一般来说加大本参数UI与提升全表扫描的效率会有帮助。
12、read_rnd_buffer_size:指定随机读取时的数据缓存区大小,默认256KB最大能够支持到4GB。增大该参数值能够有效提高order by语句的执行效率,不过这两个参数都是针对单个会话,不建议指定太大的值。如有需要可在session级别单独进行设置
13、join_buffer_size:指定表join操作时的缓存区大小,默认为256KB,最大支持到2.对于这个缓存区的设置建议参照sort_buffer_size的方式,全局只设置得保守些。对于特殊的查询可以在session界别设置。
14、net_buffer_lenth:指定单个客户端与mysql服务端交互时相关信息的缓存区大小,默认是16KB,最大能够支持到1MB。默认即可满足大多数场景,不建议进行修改。
15、max_allowed_packet:指定网络传输时,单次最大传输的数据包大小。数据包初始化时被置为join_buffer_size参数值,不过最大可以增长到max_allowed_packet参数值得大小,该参数默认比较小,建议增加。特别是使用了大字段类型(BLOG)时。但是最大不超过1GB,应该设为1024的整数倍。
16、bulk_insert_buffer_size:指定批量插入时的缓存区大小,默认大小是8M,该参数用于加速像insert... select、insert... values、以及LOAD DATA INFILE这类语句,这是个会话级的参数,可以动态调整。比如mysqldump导出数据时可以加大该参数,一般保存默认值即可。
17、max_heap_table_size:指定内存引擎表的最大可用空间。默认是16M。
18、tmp_table_size:指定内部内存临时表的最大可用空间(实际大小将取决于tmp_table_size和max_heap_table_size两参数的最小值)当内存临时表达到最大值时,mysql制动将其转换成保存在磁盘上的MyISAM了下的表对象。如果内存超大,并且临时表需要执行复杂的group by查询,那么可以适当增加tmp_table_size(以及max_heap_table_size)参数值。可以通过show global status like '%created_tmp%'查看创建的内部磁盘临时表(created_tmp_disk_tables)和内部临时表(created_tmp_tables)的总数量来确定tmp_table_size参数值是否合适。

<>MyISAM专用参数
1、key_buffer_size:指定MyISAM表索引的缓存区大小,该缓存区为所有线程共用,不是针对单个会话。默认缓存区大小是8M,64位平台最大无限制。该参数不是越大越好,建议不要超过物理内存的25%,鉴于目InnoDB引擎使用频率最高本参数指定128M已经算顶天了。
2、key_cache_block_size:指定索引缓存的块大小,值范围从512B-16KB默认是1KB。
3、myisam_sort_buffer_size:指定MyISAM引擎排序时的缓存区大小,默认是8M。
4、myisam_max_sort_file_size:当重建MyISAM索引(repair table/alter table/load data file)时,mysql允许操作的临时文件最大空间。如果文件大小超过了该参数值,则索引创建时也会把key_cache_size用上,但这个缓存区太小,缓存中的频繁数据交换将导致速度慢很多。因此如果索引文件超出该参数值,并且在磁盘空间有空闲的情况下,提高该参数值能够提高系统性能。
5、myisam_repair_threads:指定修复MyISAM表时的线程数,默认为1.如果参数值大于1则repair by sorting过程中,MyISAM表索引创建时将启用并行。

<>InnoDB专用参数
1、innodb_buffer_pool_size:指定InnoDB引擎专用的缓存区大小,用来缓存表对象的数据及索引信息。默认128M。是个全局参数,若mysql表对象以InnoDB为主,则本参数的值越大越好,可以将该参数设置为服务器物理内存的80%。InnoDB缓存命中率计算:1-(innodb_buffer_pool_reads/innodb_buffer_pool_read-requests)*100,命中率越接近100%越好,说明几乎所有要请求的数据都能从内存中获取。
2、innodb_buffer_pool_instances:指定InnoDB缓存池分为多少个区域来使用,值得范围从1-64默认为-1表示由InnoDB自行调整。相当于把一块大的缓存池划分为多个小的缓存池来管理,不同连接的读写操作的是不同的缓存页,以提高并发性能。只有当innodb_buffer_pool_size大于1GB时本参数才有用。建议innodb_buffer_pool_size为多大本参数设置为多少。比如innodb_buffer_pool_size为16G,本参数设置为16即可
3、innodb_max_dirty_pages_pct:指定InnoDB缓存池中的脏页(即已被修改,但未同步到数据文件)比例,本参数的值范围0-99,默认75。InnoDB更新innodb_buffer_pool_size中的数据时,并不会实时将数据写回到磁盘,而是等待相关触发事件,本参数就是指定缓存数据中被改动数据未刷新到磁盘的最大百分比。如果数据库的写操作比较频繁建议适当降低这个比率值,以减少mysql宕机后的恢复时间,当然这也也会带来更多的IO操作。
4、innodb_thread_concurrency:指定InnoDB内部的最大线程数,值范围0-1000,默认为0表示没有限制。当线程数达到该参数指定数量时,后面的线程将被置入FIFO队列进入等待状态,不过当参数值设置为0时,就表示没有限制,由InnoDB自己去管理可创建的线程数量。
5、innodb_flush_method:用来控制InnoDB刷新数据文件及日志文件的方式。仅作用于Linux、Unix操作系统。与IO吞吐量有密切关系。当使用基于SAN存储的系统在用对大量select语句时,使用O_DSYNC选项可能会更快一些。对于使用支持回写保护的硬件RAID卡使用O_DIRECT选项可以避免InnoDB缓存和操作系统层缓存的双重缓存写。
6、innodb_data_home_dir:指定InnoDB数据文件保存的路径,默认将保存在mysql datadir参数指定的路径下。
7、innodb_data_file_path:指定InnoDB数据文件名及文件大小
8、innodb_file_per_table:指定是否将每个InnoDB表对象存储到独立的数据文件。
9、innodb_undo_directory:指定InnoDB引擎的undo表空间数据文件存储路径
10、innodb_undo_logs:指定回滚段的数量,默认是0值范围0-128
11、innodb_undo_tablespaces:指定InnoDB回滚段表空间(其实也是数据文件)的数量。这些文件就会创建到innodb_undo_directory参数指定的路径下
12、innodb_log_files_in_group:指定InnoDB日志文件组中日志文件的数量。
13、innodb_log_group_home_dir:指定InnoDB日志文件的保存位置
14、innodb_log_file_size:指定InnoDB单个日志文件的大小
上述参数在7.4.2节介绍过。
15、innodb_log_buffer_size:指定InnoDB日志缓存区的大小,最小256KB最大不超过4GB,默认8M,为该参数指定一个适当的值,能够延缓未提交事务向磁盘日志文件的写操作频率,因此对于较大事务的应用,可以考虑加大该缓存池以节省磁盘IO,通常4-8M都是合适的。
16、innodb_flush_log_at_trx_commit:指定InnoDB刷新log buffer中的数据到日志文件的方式。可选值为0/1/2默认为1。参数值为0时logbuffer每秒向日志文件写入一次,并写入磁盘。但是在事务提交前不做任何操作(不同步数据文件)mysqld进程崩溃会导致丢失最后一秒的事务。参数为1时,只要事务提交或回滚就会将缓存中的数据写入日志文件。并且明确触发文件系统同步数据。参数为2时,log buffer在遇到事务提交时会将缓存写向日志文件,但是并不会即刻触发文件系统层的同步写入,这里稍稍有些不保险,因为文件系统层也有缓存设计,所以这类写入不能保证数据以及被写入到物理磁盘。它只是调用了文件系统的文件写入操作,在这种情况下若mysqld进程崩溃那么数据还是安全的(不影响操作系统层的缓存刷新),不过若操作系统崩溃或主机掉电那就有能导致丢失最后一秒钟的事务。所以设置为1安全性最高,不为1可能性能更好。
17、innodb_lock_wait_timeout:指定InnoDB事务等待行锁的超时时间以秒为单位默认50秒。单个事务尝试获取一行数据时,如果该行数据被InnoDB的其他事务所锁定,那么该事务会先进入等待状态,等待本参数指定的时间后若仍未成功获得,则抛出下列所务:ERRPR 1205(HY000):Lock wait timeout exceeded;try restarting transaction。
18、innodb_fast_shutdown:指定InnoDB引擎的关闭模式。有0/1/2三种选择,默认是1

<>参数优化案例
16G内存,会话最大连接数为500个,表对象使用MyISAM和InnoDB两种存储引擎,InnoDB引擎表为主,针对这种情况内存参数如何配置:
1、首先为操作系统预留20%的内存,约3GB
2、与线程相关的几个关键参数设置:
sort_buffer_size=2m
read_buffer_size=2m
read_rnd_buffer_size=2m
join_buffer_szie=2m
预计连接数达到峰值时,线程预计最大将有可能占用500*(2+2+2+2)=4GB(理论最大值)
3、MyISAM引擎表对象不多,主要是系统对象因此与之相关的几个缓存区就没必要分配太多内存,相关参数设置如下:
key_buffer_size=16m
key_cache_block_size=64k
myisam_sort_buffer_size=64m
4、剩下的空间16-3-4=9GB就可以全部都分配给InnoDB的缓存池,设定相关参数如下:
innodb_buffer_pool_size=9GB
innodb_thread_concurrency=8
innodb_flush_method=O_DIRECT
innodb_log_buffer_size=16m
innodb_flush_log_at_trx_commit=2
修改后重启mysql服务使我们的配置生效。

<>分析慢查询日志
mysqldumpslow:用来分析慢查询日志的命令行工具,用perl语言编写。它能够将类似的SQL语句(即语句抽象,将SQL语句相同但语句中的值不同)归为一组显示。常用参数:
-s t:按照总的查询时间排序
-S at:按照平均查询时间排序
-s l:按照总的锁定时间排序
-s al:按照平均的而锁定时间排序
-s s:按照总的记录行数排序
-s as:按照平均的记录行数排序
-s c:按照语句执行的次数排序,这也是默认的排序方式
-r:按照排序规则倒序输出,也就是说先执行-s参数指定的规则,而后将数据以倒序的方式输出
-t:用来控制输出的SQL语句的数量。比如慢查询日志*有10000条记录,抽象后产生100条不同的sql语句,但实际上后面的90条每个只执行了一次,前面的10条语句产生了9910次慢查询,对于dba来说重点关注这10条即可。
比如:mysqldumpslow -s c -t 1 slowlogxxxx.log mysqldumpslow功能稍显薄弱如果需要更强大的工具那就使用mysqlsla

mysqlsla:功能强大,不仅可以用来分析慢查询,而且还可以解析二进制日志以及标准查询日志。
安装mysqlsla:
perl -MCPAN -e shell
wget http://hackmysql.com/scripts/mysqlsla-2.03.tar.gz
tar -zxcf mysqlsla-2.03.tar.gz
cd mysqlsla-2.03
per Mekefile.PL
make
make install
mysqlsla命令默认保存在/usr/bin下这样方便在任意路径下调用对于慢查询日志文件的分析,最简化的调用方式如下:
mysqlsla -lt slow slowlogfilepath >resultfilepath
mysqlsla参数:
1、--log-type(-lt) TYPE LOGS:用来指定分析的日志文件类型。
slow:慢查询日志
general:普通查询日志
binary:二进制日志,注意需要首先通过mysqlbinlog命令处理
例如分析慢查询日志:mysqlsla -lt slow /mysql/logs/showlog.log
2、--abstract-in (-AI) N:用于首先处理in(..)语句,默认不启用。
例如分析慢查询日志对于in语句按照值的个数每100个做分级:mysqlsla -lt slow -Ai 100/mysql/logs/showlog.log
3、--abstract-values(-AV):抽象values()语句,按照values值得个数显示,默认不启用。
4、--explain(-ex):显示每条查询的执行计划,默认不启用,不过某些场景下还是有些用处。
5、--databases(-db)(-D)DATABASES:当指定了explain选项时需要指定本参数,以便能够到正确的数据库中获取语句的执行计划。可以一次指定多个数据库名,互相以逗号分隔。
6、--microsecond-symbol(-us)STRING:以字符串方式显示毫秒值,默认显示为纳秒
7、--statement-filter(-sf)CONDITIONS:过滤SQL语句类型,默认不启用。
8、--top N:只显示topN的查询,默认是10
例如分析慢查询日志并列出前50条:mysqlsla -lt slow -top 50 /mysql/logs/showlog.log

编写脚本mysql_slowlog_file_archive.sh使mysql实例中的slowlog文件每日自动归档,而后调用mysqlsla命令对归档的慢查询日志文件进行分析,并将分析后的文件自动发送至dba邮箱。

#!/bin/sh
#Created by jason 20170421
#Init environment variables
LOG_FILEPATH=/mysql/slowlogs/
LOG_FILENAME=$LOG_FILEPATH/mysql-slow-n.log.`date+%F`
LOG_ANALYZE=$LOG_FILEPATH/mysql-slow-ana.log.`date+%F`
SLOWLOG_FILENAME=/mysql/logs/slow_query.log

#Do the job!
/bin/cp -f $SLOWLOG_FILENAME $LOG_FILENAME
/bin/echo "" > $SLOWLOG_FILENAME
/usr/bin/mysqlsla -lt slow $LOG_FILENAME --top 100 -Ai 1000 > $LOG_ANALYZE
/bin/cat $LOG_ANALYZE |iconv -f utf-8 -t gb18030 | mail -s "[`date+F%] MySql SlowLogs from Linux01" jasoname@qq.com
#Delete slowlog history
/use/bin/find $LOG_FILEPATH / -mtime +7 -exec rm{} \;

<>关注系统状态
1、mysql服务在做什么:show full processlist;
列有id user host db command time state info
mysql中的每个连接都是独立的线程,通过show processlist命令能够查看到它们,同时对于异常的连接dba也可以手动清除。命令如下:
system@(none)>kill 48;
2、mysql语句在做什么
show profiles:用于显示最近执行过的语句(以及语句执行的时间开销),当然不是所有执行过的语句都显示。show profiles显示执行语句相关信息时,受制于两方面因素:首先资源统计由一个名为profiling的状态变量控制,因此得先确定当前系统是否启用了资源统计。若未启用的话那么show profiles命令的返回结果就始终为空。控制profiling的系统状态变量,其默认值为OFF,若要启用它,则需要将该变量的值改为NO或1。其次所显示的最近执行语句的条数,是由系统变量profiling_history_size控制,该变量的默认值是15,最大值不超过100.也就是说在profiling已启用的前提下show profiles语句最多只能显示出最近100条执行的语句。
在profiling启用的前提下,show profile(s)能够记录和分析他们自身以外的任意语句,不管用户执行的是DML还是DDL,甚至是那些存在语法错误的语句,都将被记录。
show profile:命令用于显示(单个)语句执行时的详细资源信息。默认将显示最近(show profiles中记录的)执行过的语句所使用资源的综合信息,不过它支持for query子句,当指定for query n,就可以查询具体的某些语句执行时所使用的资源信息。同时show profile还支持limit子句,这样就可以用来限制输出的记录。默认情况下show profile只显示status和duration列,其中status列中内容与show processlist命令中的state内容相同。另外注意到show profile还有个type关键字,对于可选的type关键字来说,它可以控制show profile命令输出下列附加信息:
ALL:显示所有信息
BLOCK IO:显示输入输出的块数量
CONTEXT SWITCHES:显示换页操作的数量
CPU:显示CPU使用时间
IPC:显示消息发送和接收的数量
MEMORY:暂不可用直接忽略
PAGE FAULTS:显示失败页的数量
SOURCE:显示所调用的方法名,位于源码文件中的行等基础信息。
SWAPS:显示交换次数。
启用profiling:set profiling=1;
system@(none)>set profiling=1;
Query OK, 0 rows affected, 1 warning (0.00 sec)
system@5ienet>select * from jason_v2;
+------+
| id |
+------+
| 1 |
| 2 |
| 4 |
| 3 |
+------+
system@5ienet>show profiles;
+----------+------------+------------------------+
| Query_ID | Duration | Query |
+----------+------------+------------------------+
| 1 | 0.00013225 | show wangnings |
| 2 | 0.00010900 | show wangnings |
| 3 | 0.00030800 | show warnings |
| 4 | 0.00014650 | show jason.tables |
| 5 | 0.00036175 | SELECT DATABASE() |
| 6 | 0.00018200 | SELECT DATABASE() |
| 7 | 0.00176525 | show databases |
| 8 | 0.00036200 | SELECT DATABASE() |
| 9 | 0.00097125 | show databases |
| 10 | 0.00066225 | show tables |
| 11 | 0.00228675 | SELECT DATABASE() |
| 12 | 0.00077200 | show tables |
| 13 | 0.00091675 | select * from jason_v2 |
+----------+------------+------------------------+
13 rows in set, 1 warning (0.00 sec)
可以看到刚刚执行的语句被记录下来了。而后可以通过show profile命令来获取这条语句执行时具体做了什么以及各步骤的开销:

system@5ienet>show profile;
+----------------------+----------+
| Status | Duration |
+----------------------+----------+
| starting | 0.000066 |
| checking permissions | 0.000011 |
| Opening tables | 0.000022 |
| init | 0.000027 |
| System lock | 0.000019 |
| optimizing | 0.000010 |
| statistics | 0.000015 |
| preparing | 0.000016 |
| executing | 0.000005 |
| Sending data | 0.000632 |
| end | 0.000015 |
| query end | 0.000014 |
| closing tables | 0.000020 |
| freeing items | 0.000023 |
| cleaning up | 0.000025 |
+----------------------+----------+
15 rows in set, 1 warning (0.00 sec)
查看每项状态所执行操作的方法以及占用的CPU资源,可以附加CPU和SOURCE两个类型,实际执行show profile命令如下:
system@5ienet>show profile cpu,source;
+----------------------+----------+----------+------------+-----------------------+------------------+-------------+
| Status | Duration | CPU_user | CPU_system | Source_function | Source_file | Source_line |
+----------------------+----------+----------+------------+-----------------------+------------------+-------------+
| starting | 0.000066 | 0.000000 | 0.000000 | NULL | NULL | NULL |
| checking permissions | 0.000011 | 0.000000 | 0.000000 | check_access | sql_parse.cc | 5296 |
| Opening tables | 0.000022 | 0.000000 | 0.000000 | open_tables | sql_base.cc | 5095 |
| init | 0.000027 | 0.000000 | 0.000000 | mysql_prepare_select | sql_select.cc | 1051 |
| System lock | 0.000019 | 0.000000 | 0.000000 | mysql_lock_tables | lock.cc | 304 |
| optimizing | 0.000010 | 0.000000 | 0.000000 | optimize | sql_optimizer.cc | 138 |
| statistics | 0.000015 | 0.000000 | 0.000000 | optimize | sql_optimizer.cc | 364 |
| preparing | 0.000016 | 0.000000 | 0.000000 | optimize | sql_optimizer.cc | 487 |
| executing | 0.000005 | 0.000000 | 0.000000 | exec | sql_executor.cc | 110 |
| Sending data | 0.000632 | 0.000000 | 0.000000 | exec | sql_executor.cc | 190 |
| end | 0.000015 | 0.000000 | 0.000000 | mysql_execute_select | sql_select.cc | 1106 |
| query end | 0.000014 | 0.000000 | 0.000000 | mysql_execute_command | sql_parse.cc | 4995 |
| closing tables | 0.000020 | 0.000000 | 0.000000 | mysql_execute_command | sql_parse.cc | 5043 |
| freeing items | 0.000023 | 0.000000 | 0.000000 | mysql_parse | sql_parse.cc | 6432 |
| cleaning up | 0.000025 | 0.000000 | 0.000000 | dispatch_command | sql_parse.cc | 1777 |
+----------------------+----------+----------+------------+-----------------------+------------------+-------------+
15 rows in set, 1 warning (0.01 sec)

show profile for query 13;这个13对于show profiles;中的Query_ID

system@5ienet> show profile for query 13;
+----------------------+----------+
| Status | Duration |
+----------------------+----------+
| starting | 0.000066 |
| checking permissions | 0.000011 |
| Opening tables | 0.000022 |
| init | 0.000027 |
| System lock | 0.000019 |
| optimizing | 0.000010 |
| statistics | 0.000015 |
| preparing | 0.000016 |
| executing | 0.000005 |
| Sending data | 0.000632 |
| end | 0.000015 |
| query end | 0.000014 |
| closing tables | 0.000020 |
| freeing items | 0.000023 |
| cleaning up | 0.000025 |
+----------------------+----------+
15 rows in set, 1 warning (0.00 sec)
show profile(s)本身也占用资源开销所以更多是用于分析,往往都是属于事后行为。show profiles命令最多也就只能显示最近100条语句的资源使用情况,对于繁忙的线上系统来说并发不止100,因此全局启用的意义不大,日常使用时更多还是针对会话级进行操作。在mysql5.6.7开始这两语句都废弃了

Performance Schema:
use performance_schema
system@performance_schema>show tables like 'setup_%';
+----------------------------------------+
| Tables_in_performance_schema (setup_%) |
+----------------------------------------+
| setup_actors |
| setup_consumers |
| setup_instruments |
| setup_objects |
| setup_timers |
+----------------------------------------+
5 rows in set (0.00 sec)

setup_actors:用来控制要监控的线程,可以控制只处理指定主机或指定用户创建的线程,默认所有线程全部监控。
setup_consumers :用来控制哪类事件信息将被保存,默认较为保守,需要dba根据实际情况进行配置。
setup_instruments:用来控制哪些事件信息将被收集,以及是否记录事件
setup_objects:用来控制被监控的对象,可以将粒度细化到某个schema下的某个对象,默认除mysql/performance_schema/information_schema库除外,所有对象均会被监控
setup_timers:用来控制各项事件所使用的计时器,计时器来自于performance_timers表对象中的定义。

system@performance_schema>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 | NO |
| events_statements_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 |
+--------------------------------+---------+
events_stages%(用于保存sql语句执行过程中各类事件的列表)默认都是禁用状态,执行update将之全部启用
system@performance_schema> update setup_consumers set enabled='YES' where name like 'events_stages%';
Query OK, 3 rows affected (0.00 sec)
Rows matched: 3 Changed: 3 Warnings: 012 rows in set (0.00 sec)
global_instrumentation的时间具备最高优先级,用来指定全局级别的信息收集,如果该条记录被禁用那么不管其他consumer的记录如何设置所有事件均不会被收集。
thread_instrumentation具备次要优先级,用来指定线程级别的信息收集当global_instrumentation指定为YES时,就会继续检查thread_instrumentation的配置。只有当其他也被启用其他的时间收集

现在关键事件列表中允许记录数据了,但是我们关注的事件当前有没有被启用呢。那么需要执行以下语句:
system@performance_schema>update setup_instruments set enabled='YES',timed='YES' where name like 'stage/sql/%';
Query OK, 107 rows affected (0.00 sec)
Rows matched: 107 Changed: 107 Warnings: 0
上面所做的修改都是及时生效,现在通过Performance Schema分析执行过程中的各项消耗了。
执行:select * from 5ienet.jason_v2;
所有触发的事件都保存在events_stages_history表中(因为是已经执行过的,而不是当前正在执行的所以在history表)。执行如下语句:
system@performance_schema>desc events_stages_history;
+--------------------+----------------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+----------------------------------+------+-----+---------+-------+
| THREAD_ID | bigint(20) unsigned | NO | | NULL | |
| EVENT_ID | bigint(20) unsigned | NO | | NULL | |
| END_EVENT_ID | bigint(20) unsigned | YES | | NULL | |
| EVENT_NAME | varchar(128) | NO | | NULL | |
| SOURCE | varchar(64) | YES | | NULL | |
| TIMER_START | bigint(20) unsigned | YES | | NULL | |
| TIMER_END | bigint(20) unsigned | YES | | NULL | |
| TIMER_WAIT | bigint(20) unsigned | YES | | NULL | |
| NESTING_EVENT_ID | bigint(20) unsigned | YES | | NULL | |
| NESTING_EVENT_TYPE | enum('STATEMENT','STAGE','WAIT') | YES | | NULL | |
+--------------------+----------------------------------+------+-----+---------+-------+
select * from threads;
*************************** 20. row ***************************
THREAD_ID: 702
NAME: thread/sql/one_connection
TYPE: FOREGROUND
PROCESSLIST_ID: 683
PROCESSLIST_USER: system
PROCESSLIST_HOST: localhost
PROCESSLIST_DB: performance_schema
PROCESSLIST_COMMAND: Query
PROCESSLIST_TIME: 0
PROCESSLIST_STATE: Sending data
PROCESSLIST_INFO: select * from threads
PARENT_THREAD_ID: NULL
ROLE: NULL
INSTRUMENTED: YES
20 rows in set (0.00 sec)
system@performance_schema>select THREAD_ID,EVENT_ID,EVENT_NAME,TIMER_WAIT from events_stages_history where THREAD_ID in(select THREAD_ID from threads where processlist_id=683) order by event_id;
+-----------+----------+--------------------------------+------------+
| THREAD_ID | EVENT_ID | EVENT_NAME | TIMER_WAIT |
+-----------+----------+--------------------------------+------------+
| 702 | 222 | stage/sql/checking permissions | 14552000 |
| 702 | 223 | stage/sql/Opening tables | 91965000 |
| 702 | 224 | stage/sql/init | 82961000 |
| 702 | 225 | stage/sql/System lock | 19472000 |
| 702 | 226 | stage/sql/optimizing | 67036000 |
| 702 | 227 | stage/sql/statistics | 174354000 |
| 702 | 228 | stage/sql/preparing | 47450000 |
| 702 | 229 | stage/sql/Sorting result | 5029000 |
| 702 | 230 | stage/sql/executing | 2556000 |
| 702 | 231 | stage/sql/Sending data | 23796000 |
+-----------+----------+--------------------------------+------------+
10 rows in set (0.00 sec)

event_stages_current:保存当前正在产生的事件,从理论上来说,每个线程当前只会存在一种事件,在这个表中记录的就是该线程的最近一次事件。
event_stages_history:保存每个线程所产生的事件的历史记录,我们想要分析的是语句执行的各项时间,因此最好就是到历史表中获取。不过mysql默认历史表中只记录最近10条,这个数量是系统变量performance_schena_events_stages_history_size控制。
event_stages_history_long:查询更多语句触发的事件使用这个表。该表记录最近1万条记录。这个数量是由performance_schema_events_stages_history_long_size控制

<>实战优化案例:业务反应系统访问速度很慢。登陆mysql通过show processlist查看有许多locked,通常我们会下意识的认为是写阻塞了读。因为只有一条update语句,而有无数条select。但是查看update的语句很简单这个语句应该瞬时就完成。查看系统状态整体负载都很低。再次分析show processlist语句返回信息注意到。ID为123890的语句执行时间最长,肯定是在该update语句之前执行的。通过show full processlist查看完整的sql,看到该查询也是访问了a表,经此分析应该是该语句长时间的读阻塞了写,而被阻塞的写操作由于处于最优先处理队列,又阻塞了其他的读。我们也可以用mysqladmin的debug参数做更精准的分析:
mysqladmin -ujason -poraplinux -S /mysql/conf/mysql.sock debug
debug会将状态信息生成到mysql数据库的错误文件中保存。一般锁的信息都会保存在最后几行。所以查看最后几行显示
2 hdpic.a Waiting-write Highest priority write lock
123890 hdpic.a Locked-read Low priority read lock
123890 hdpic.a Locked-read Low priority read lock
123890 hdpic.a Locked-read Low priority read lock
124906 hdpic.a Waiting-read Low priority read lock
从上面的信息可以看出123890持有的读锁阻塞了2的写入和124906的读取操作。如果现在不可接受无法继续等待那么将123890杀掉,释放资源:
mysql> kill 123890;