很多人让我来阐述一下 SHOW INNODB STATUS 的输出信息,了解SHOW INNODB STATUS都输出了几个什么信息,并且我们能够这些信息中获取什么资讯,得以提高MySQL性能。
首先,让我们来了解一下SHOW INNODB STATUS输出的基础,它打印了很多关于InnoDB内部性能相关的计数器,统计,事务处理信息等。在mysql 5中,InnoDB的性能统计结果也在 SHOW STATUS 结果中显示了。大部分和SHOW INNODB STATUS的其他信息相同,在旧版本中还没有这个功能。
SHOW INNODB STATUS中的很多统计值都是每秒更新一次的,如果你打算利用这些统计值的话,那么最好统计一段时间内的结果.InnoDB首先输出以下信息:
1。===================================== 2.060717 3:07:56 INNODB MONITOR OUTPUT 3。===================================== 4.从最后44秒计算的第二个平均值
首先要确认这是至少统计了20-30秒的样本数据。如果平均统计间隔是0或1秒,那么结果就没什么意义了。
说实在的我不喜欢InnoDB提供的平均值,因为很难取得合理的平均间隔统计值,如果你是写脚本来取得SHOW INNODB状态结果的话,那么最好取得全局的统计结果,然后取得平均值当然了,直接查看输出的结果信息也是很有用的。
下一部分显示了信号(信号量)相关信息:
1 .---------- 2.SEMAPHORES 3 .---------- 4.OS等待信息:预约计数13569,信号数11421 5 .--线程1152170336等待./../include/buf0buf.ic行630,信号量为0.00秒: 6.Mutex在0x2a957858b8创建文件buf0buf.c行517,锁var 0 7.等待标志0 等待结束 9 .--线程1147709792等待./../include/buf0buf.ic行630为0.00秒信号量: 10.Mutex在0x2a957858b8创建文件buf0buf.c行517,锁var 0 等待标志0 等待结束 13.Mutex旋转等待5672442,轮3899888,操作系统等待4719 14.RW共享自转5920,操作系统等待2918; RW-excl旋转3463,操作系统等待3163
这部分可以分成2个部分。一部分是当前的等待,这部分只是包含了在高并发环境下的全部记录,因此InnoDB会频繁回退到系统等待。如果等待是通过自旋锁来解决的话,那么这些信息就就不会显示了。
通过这部分信息,你就会知道系统负载的热点在哪了。不过这需要了解一下源码相关的知识 - 从上面的信息中就可以看出来是哪个源码文件中的哪行(不同的版本结果可能不同),只是从这里却看不出来任何信息。尽管如此,还是可以从文件名中猜到一些东西 - 比如本例中文,文件名“buf0buf.ic”预示着和一些缓冲池争夺有关系如果想了解更多,就去看源码吧。
还有一些关于等待的更多细节。“lock var”表示当前的mutex对象的值(被锁住= 1 /释放= 0)值,“waiters flag”表示当前的等待个数。另外,本例中还可以看到等待状态信息“等待结束”,这表示mutex已经释放,但是系统调度线程还正在处理。
第二块是事件统计 - “预约计数”和“信号计数”显示了innodb使用内部同步阵列的活跃程度 - 时间片(槽)分配以及线程信号使用同步阵列的频繁程度这些统计信息可以用于表示innodb回退系统等待的频率。还有关于系统等待的直接相关信息,可以看到“OS Waits”的互斥信号灯(mutexes),以及读写锁这些信息中显示了互斥锁和共享锁系统等待和“保留(保留)”不完全一样,在回退到用sync_array的复杂等待模式前,innodb会尝试“输出(yield)”到系统,希望下一次调度时间对象里命名线程已经释放了。系统等待相对较慢,如果每秒发生了上万次系统等待,则可能会有问题。另一个观察方法是查看系统状态中的上下文(上下文)交换频率。
另一块重要的信息是“旋转等待”和“旋转圆”的数量。相比于系统等待,自旋锁是低成本的等待;不过它是一个活跃的等待,会浪费一些cpu资源。因此如果看到大量的自旋等待和自旋轮转,则很显然它浪费了很多CPU资源。浪费CPU时间和无谓的上下文切换之间可以 用innodb_sync_spin_loops 来平衡。
接下来的这段显示死锁状况:
1 .------------------------ 最新检测的死锁 3 .------------------------ 4.060717 4:16:48 5。***(1)交易: 6.TRANSACTION 0 42313619,ACTIVE 49秒,进程号10099,OS线程号3771312开始索引读取 7.mysql表中使用1,锁定1 锁定等待3锁结构,堆大小320 9.MySQL线程号为30898,查询id为100626 localhost root更新 10.update iz set pad =‘a‘其中i = 2 11。***(1)等待这个锁定被授予: 12.RECORD LOCKS空格id 0页否16403 n位72索引`PRIMARY‘表‘test / iz` trx id 0 42313619 lock_mode X锁定rec但不等待间隙 记录锁,堆没有5物理记录:n_fields 4; 紧凑格式; 信息位0 0:len 4; 十六进制80000002; ; 1:len 6; 十六进制00000285a78f; ; 2:len 7; 十六进制00000040150110; asc @ ;; 3:len 10; hex 61202020202020202020; ; 15。 16。***(2)交易: 17.TRANSACTION 0 42313620,ACTIVE 24秒,进程号10099,OS线程号4078512起始索引读取,线程声明内部InnoDB 500 18.mysql表正在使用1,锁定1 19.3锁结构,堆大小320 20.MySQL线程号30899,查询id 100627 localhost root更新 21.update iz set pad =‘a‘其中i = 1 22。***(2)DS THE:::::::::: 23.RECORD LOCKS空格id 0页否16403 n位72索引`PRIMARY‘表‘test / iz` trx id 0 42313620 lock_mode X锁定rec但不是间隙 24.记录锁,堆不5物理记录:n_fields 4; 紧凑格式; 信息位0 0:len 4; 十六进制80000002; ; 1:len 6; 十六进制00000285a78f; ; 2:len 7; 十六进制00000040150110; asc @ ;; 3:len 10; hex 61202020202020202020; ; 26。 27。***(2)等待这个锁定被授予: 28.RECORD LOCKS空格id 0页号16403 n位72索引`PRIMARY‘表‘test / iz` trx id 0 42313620 lock_mode X锁定rec但没有间隙等待 记录锁,堆没有4物理记录:n_fields 4; 紧凑格式; 信息位0 0:len 4; hex 80000001; ; 1:len 6; 十六进制00000285a78e; ; 2:len 7; 十六进制000000003411d9; asc 4 ;; 3:len 10; hex 61202020202020202020; ; 31。 32。***我们回滚交易(2)
这里显示了Innodb最后检测到事务引发的死锁,包括发生死锁时的状态,加了什么锁,在等待什么锁释放,以及Innodb决定哪个事务会被回滚。注意,innodb只显示了事务持有锁的相关简单信息。并且只显示了每个事务最后执行的语句,发生死锁的记录就是由于这些语句引起的。查看复杂的死锁信息还需要查看日志文件,才能找到真正引发冲突的语句大部分情况下,SHOW INNODB状态显示的信息基本足够了。
下面是关于外键约束引发的死锁信息:
1 .------------------------ 2.最新的外来键错误 3 .------------------------ 4.060717 4:29:00交易: 5.TRANSACTION 0 336342767,ACTIVE 0秒,进程号3946,OS线程号1151088992插入,在InnoDB 500中声明的线程 使用mysql表1,锁定1 7.3锁结构,堆大小368,撤销日志条目1 8.MySQL线程号9697561,查询id 188161264 localhost根更新 9.插入子值(2,2) 表‘test / child`的外键键约束失败: 11, 12. CONSTRAINT`child_ibfk_1` FOREIGN KEY(`parent_id`)REFERENCES`parent`(`id`)ON DELETE CASCADE 13.尝试在子表中添加索引中的`par_ind`元组: DATA TUPLE:2场; 0:len 4; 十六进制80000002; ; 1:len 6; 十六进制000000000401; ; 16。 在父表“test / parent”中,在索引“PRIMARY”中, 我们可以找到最接近的比赛是记录: 物理记录:n_fields 3; 1字节关闭TRUE; 信息位0 0:len 4; hex 80000001; ; 1:len 6; 十六进制0000140c2d8f; asc - ;; 2:len 7; 十六进制80009c40050084; asc @ ;;
Innodb的会显示引发错误的语句。外键约束定义失败,以及定义关系最密切的父表。有很多嵌接信息都是用16进制表示,不过对于问题诊断并不是太重要,它们主要用于给Innodb的开发者来查看或者用于调试目的。
接下来是显示Innodb当前活跃的事务:
1 .------------ 2.TRANSACTIONS 3 .------------ 4.Trx id计数器0 80157601 5.对于trx的n进行完成:o <0 80154573 undo n:o <0 0 历史名单长度6 行锁哈希表中的锁结构总数0 8.每届会议交易清单: 9 .--- TRANSACTION 0 0,未启动,进程号3396,OS线程号1152440672 10.MySQL线程号为8080,查询id为728900 localhost根 显示innodb状态 12 .--- TRANSACTION 0 80157600,ACTIVE 4秒,进程号3396,OS线程号1148250464,InnoDB 442内部声明的线程 13.mysql表正在使用1,锁定0 14.MySQL线程号8079,查询id 728899 localhost root发送数据 15.从b限制中选择sql_calc_found_rows * 5 16.Trx读取视图不会看到id为= 80157601的trx,看到<0 80157597 17 .--- TRANSACTION 0 80157599,ACTIVE 5秒,进程号3396,操作系统线程号1150142816提取行,线程内宣告InnoDB 166 18.mysql表中使用1,锁定0 19.MySQL线程id为8078,查询id为728898 localhost root发送数据 20.从b限制中选择sql_calc_found_rows * 5 21.Trx读取视图不会看到具有id> = 0的trx 80157600,看到<0 80157596 22 .--- TRANSACTION 0 80157598,ACTIVE 7秒,进程号3396,OS线程号1147980128提取行,线程在InnoDB 114内部声明 23.mysql表正在使用1,锁定0 24.MySQL线程id 8077,查询id 728897 localhost root发送数据 25.从b限制中选择sql_calc_found_rows * 5 26.Trx读取视图不会看到具有id> = 0的trx 80157599,看到<0 80157595 27 .--- TRANSACTION 0 80157597,ACTIVE 7秒,进程号3396,OS线程号1152305504提取行,线程内部声明InnoDB 400 28. mysql表正在使用1,锁定0 29.MySQL线程号8076,查询id 728896 localhost root发送数据 30.从b限制中选择sql_calc_found_rows * 5 31.Trx读取视图不会看到具有id> = 0的字符串0x157598,看到<0 80157594
如果当前连接不是很多,则会显示全部事务列表;如果有大量连接,则Innodb只会显示他们的数量,减少输出的列表信息,使得输出结果不会太多。
事务ID是当前事务的标识,事务的id每次都会增加。为trx的n清除完成:o 是指净化(purge)线程已经完成的事务数.Innodb只清除那些被当前事务认为不再需要的旧版本数据。那些未提交的旧事务可能会阻塞净化线程并且消耗资源。通过查看2次清除事务数之差,就可以知道是否发生了这种情况。少数情况下,净化线程可能难以跟上更新的速度,2次查看值之差可能会越来越大;那么,innodb_max_purge_lag 就派得上用场了。 “undo n:o” 显示了净化线程当前正在处理的回滚日志号,如果当前不处于活跃状态,那它的值是0。
历史列表长度6 是指在回滚空间中的未清除事务数。随着事务的提交,它的值会增加;随着清除线程的运行,它的值会减小。
行锁哈希表中 的锁结构总数是指事务分配过的行锁结构总数。它和曾经被锁住过的行总数不一定相等,通常是一个锁结构对应多行记录。
MySQL中,每个连接如果没有活动的事务,则它的状态是 不启动,如果有活动的事务,则是 ACTIVE。注意,尽管事务是活动的,但是其连接的状态却可能是“睡眠)“ - 如果是在一个有多条语句的事务里的话.Innodb会同时显示系统的线程号以及进程号,这有助于利用gdb来调试或者其他类似用途。另外,事务的状态也会根据当前实际状态来显示,例如 “读取记录(提取行)”,em>“更新(更新)”等等。“InnoDB 400内的线程” 的意思是Innodb内核正在运行该线程,并且还需要400个票.Innodb会根据 innodb_thread_concurrency参数 的值来限制同时并发的线程数不超过它。如果线程当前不在Innodb的的内核中运行,则它的状态可能是 “InnoDB的队列中等待” 或 “加入队列的InnoDB睡觉前”。这个可能的会导致Innodb内核中当前活跃的线程数可能比innodb_thread_concurrency 的值还小。某种负载环境下,这可能有助于减小线程进入队列的时间。可以通过调整innodb_thread_sleep_delay 来实现,它的单位是微妙。
mysql表在使用1,locked 0 是指事务中已经用过的数据表个数(已经访问过了的),以及被锁的个数.Innodb一般情况不会锁表,因此锁表数一般是0 ,除非是 ALTER TABLE 或者其他类似 LOCK TABLES 的语句。
除了Innodb相关的特定信息外,一些基本信息可以通过来查看,例如正在执行什么语句,查询ID号,查询状态等。
下面这部分显示的是跟IO相关的具体信息:
1 .-------- 2.FILE I / O 3 .-------- 4.I / O线程0状态:等待i / o请求(插入缓冲线程) 5.I / O线程1状态:等待i / o请求(日志线程) 6.I / O线程2状态:等待i / o请求(读线程) 7.I / O线程3状态:等待i / o请求(写线程) 正常aio读取:0,aio写:0, ibuf aio读取:0,log i / o‘s:0,sync i / o‘s:0 正常刷新(fsync)log:0; 缓冲池:0 11.17909940操作系统文件读取,22088963操作系统文件写入,1743764操作系统fsyncs 12.0.20读/秒,16384平均字节/读,5.00写/秒,0.80 fsyncs / s
本部分显示了IO助手线程状态 - 插入缓冲线程,日志线程,读,写线程。它们分别对应插入缓冲合并,异步日志刷新,预读以及刷新脏数据。源自查询的正常读取是由正在运行的查询执行的。在Unix / Linux平台下,总能看见4个线程,在Windows上可以通过 innodb_file_io_threads 来调整。每个线程准备好之后都能看到其状态:等待i / o请求 或者正在执行特定的操作。
每个线程都会显示正在进行的操作数量 - 同时正要执行或者正在执行的操作数量。另外,正在执行的fsync操作数量也会显示出来。有写数据时,Innodb需要确保数据最终被写到磁盘上,只是把它们放在系统缓存里是不够的。通常是调用fsync()来完成的。如果它的值一直很高,那意味这Innodb可能是处理IO负载较高状态。注意,由线程执行请求引发的IO请求是不计算在内的,因此尽管系统的IO负载较高,但是它们的值却可能为0。
接下来显示的是IO操作的平均统计值,它们对于图形显示或者监控很有用。
“16384 avg bytes / read” 是读请求的平均值。随机IO的话,每个页的大小是16K,全表扫描或索引扫描时的预读会导致这个值明显的增加。因此,它体现了预读的效率。
1 .------------------------------------- 2.安全缓冲区和自适应哈希指数 3 .------------------------------------- 空间空间0:大小1,免费列表len 887,段大小889,不为空 5.Ibuf for space 0:size 1,free list len 887,seg size 889, 6.2431891插入,2672643合并记录,1059730合并 7.表格大小为8850487,使用单元格2381348,节点堆有4091个缓冲区 8.2208.17哈希搜索/ s,175.05非哈希搜索/ s
本部分显示了插入缓冲以及自适应哈希索引的状态。第一行显示了插入缓冲的状态 - 段的大小以及空闲列表,以及缓冲中有多少记录。接下来显示了缓冲中已经完成了多少次插入,有多少记录已经合并,有多少次合并已经完成,合并次数除以插入次数得到的比率可以反映出插入缓冲的效率如何。
Innodb采用哈希索引建立内存页索引形成自适应哈希索引而不是采B-tree索引,得以加速行记录到内存页的检索。这里显示了哈希表的大小,以及自适应哈希索引使用了多少单元和缓冲。可以通过计算利用哈希索引检索的次数以及没利用它检索的次数来了解哈希索引的效率。
当前对自适应哈希索引基本没有什么办法可以调整它,主要还是用于查看。
1 .--- 2.登录 3 .--- 4.序号84 3000620880 5.记录刷新到84 3000611265 最后检查点为84 2939889199 7.0等待日志写入,0等待chkp写入 8.14073669 log i / o的完成,10.90 log i / o的/秒
接下来显示的是Innodb的日志子系统相关信息。可以看到当前的日志序列号 - 相当于Innodb自从表空间开始创建直到现在已经写入日志文件的总字节数。还可以看到日志已经刷新到哪个点,同样也可以根据最后检查点计算出还有多少日志没有刷新到文件中去.Innodb采用模糊检查点,因此这行显示的是已经从缓冲池中刷新到文件的日志序列号。由于更高的日志序列号可能不会被立刻刷新到日志文件中去,因此日志序列号不能被覆盖掉。通过监控刷新到哪个日志的日志序列,可以判定innodb_log_buffer_size 的设置是否合理,如果看到超过30 %的日志还没有刷新到日志文件中,则需要考虑增加它的值了。
另外,还能看到日志写入以及检查点的数目。根据日志I / O操作的数据可以区分开空间相关的IO请求和日志IO请求数量,进而可以确定到底需要几个日志文件。innodb_flush_log_at_trx_commit 的值可以影响到日志写操作的代价高或低如果innodb_flush_logs_at_trx_commit = 2,则日志是写到系统缓存,然后再顺序写到日志文件中,因此相对会快很多。
1 .---------------------- 2.缓冲池和存储器 3 .---------------------- 总内存分配4648979546; 在附加池中分配16773888 缓冲池大小262144 免费缓冲区0 数据库页面258053 8.修改数据库页37491 9.待定阅读0 10.待写:LRU 0,刷新列表0,单页0 11页阅读57973114,创建于251137,编号10761167 12.9.79读/ s,0.31创建/秒,6.00写/秒 缓冲池命中率999/1000
这部分显示了缓冲池和内存的利用率相关信息。可以看到Innodb的分配的所有内存(有些时候可能比你设置的还要多点),以及额外的内存池分配情况(可以检查它的大小是否正好),缓冲池总共有多少个内存页,有多少空闲内存页,数据库分配了多少个内存页以及有多少个脏内存页。从这些信息中,就可以判断内存缓冲池是否设定合理,如果总是有大量空闲内存页,则不需要设置那么多内存,可以适当减小一点。如果空闲内存页为0,这种情况下数据库内存页就不一定会和缓冲池的总数一致,因为缓冲池还需要保存锁信息,自适应哈希索引以及其他系统结构等信息。
等待中的读写是指内存缓冲池级别的请求.Innodb可能会把多个文件级别的请求合并到一个上,因此各不相同。我们还可以看到Innodb的提交的各种不同类型的IO,LRU内存页中需要刷新页面 - 脏内存页,它们不会被长时间存取;刷新列表 -
检查点进程处理完后需要刷新的旧内存页;独立内存页 - 独立的写内存页。
我们还可以看到内存页总共读写了多少次。已经创建的内存页是当前一个内存页中的内容没有读取到内存缓冲池中时,专门为新数据创建的空内存页。
最后我们可以看到缓冲池的命中率,它预示着缓冲池的效率.1000 / 1000相当于100%的命中率。不过这样也很难说明缓冲池的命中率就足够高了,这要需要根据不同的负载环境而定。通常情况下,950/1000就够了,有些时候在IO负载较高的环境下,命中率可能为995/1000。
1 .-------------- 2.操作操作 3 .-------------- InnoDB中的4.0查询,队列中的0个查询 5.1阅读在InnoDB内开放的视图 主线程过程号 10099,id 88021936,状态:等待服务器活动 7.插入行数143,更新3000041,删除0,读取24865563 8.0.00插入/秒,0.00更新/秒,0.00删除/秒,0.00读/秒
最后一部分,显示了数据行操作以及一些系统信息相关情况。
一开始显示了Innodb线程队列状态 - 有多少线程处于等待或活跃的.Innodb内部打开了多少读视图 -
这是在事务开始后,但是当前还没有活跃语句的情况时,InnoDB主线程的状态控制了系统操作调度的数量-刷新脏内存页,检查点,净化线程,刷新日志,合并插入缓冲等 “状态“ 的值则表示了主线程当前的状态。
接下来可以看到自从系统启动以来,所有的数据行操作数量及其平均值。它们可以很方便地用于监控以及画出系统状态图,数据行操作次数可以很好的衡量Innodb的的负载。不是所有的数据行操作带来的负载都是一样的,存取10字节的行比的10Mb的行相比会小了很多,不过相对于查询的总次数来说这个信息可是有用的多了,差别也很大。
还有一点需要注意的是,SHOW INNODB STATUS不是一成不变的,有些时间点上可能会不相符。是由于设计时需要由全局锁提供一致性信息,导致了大量的开销。