linux-8tpn:/home/kevin/perl # perl mysqlreport --help
mysqlreport v3.5 Apr 16 2008
mysqlreport makes an easy-to-read report of important MySQL status values.
Command line opti** (abbreviati** work):
--user USER Connect to MySQL as USER
--password PASS Use PASS or prompt for MySQL user's password
--host ADDRESS Connect to MySQL at ADDRESS
--port PORT Connect to MySQL at PORT
--socket SOCKET Connect to MySQL at SOCKET
--no-mycnf Don't read ~/.my.cnf
--infile FILE Read status values from FILE instead of MySQL
--outfile FILE Write report to FILE
--email ADDRESS Email report to ADDRESS (doesn't work on Windows)
--flush-status Issue FLUSH STATUS; after getting current values
--relative X Generate relative reports. If X is an integer,
reports are live from the MySQL server X seconds apart.
If X is a list of infiles (file1 file2 etc.),
reports are generated from the infiles in the order
that they are given.
--report-count N Collect N number of live relative reports (default 1)
--detach Fork and detach from terminal (run in background)
--help Prints this
--debug Print debugging information
Visit http://hackmysql.com/mysqlreport for more information.
Use of uninitialized value in multiplication (*) at /usr/local/mysql/bin/mysqlreport line 829. Use of uninitialized value in formline at /usr/local/mysql/bin/mysqlreport line 1227. MySQL 5.1.34-log uptime 0 1:31:10 Fri Jan 15 12:39:12 2010 __ Key _________________________________________________________________ Buffer used 12.33M of 256.00M %Used: 4.81 Current 41.80M %Usage: 16.33 Write hit 52.74% Read hit 99.74% __ Questi** ___________________________________________________________ Total 434.70k 79.5/s DMS 265.94k 48.6/s %Total: 61.18 QC Hits 166.09k 30.4/s 38.21 +Unknown 1.09k 0.2/s 0.25 Com_ 1.08k 0.2/s 0.25 COM_QUIT 495 0.1/s 0.11 Slow 1 s 89 0.0/s 0.02 %DMS: 0.03 Log: ON DMS 265.94k 48.6/s 61.18 SELECT 149.52k 27.3/s 34.40 56.22 UPDATE 115.33k 21.1/s 26.53 43.37 INSERT 899 0.2/s 0.21 0.34 DELETE 193 0.0/s 0.04 0.07 REPLACE 0 0/s 0.00 0.00 Com_ 1.08k 0.2/s 0.25 change_db 446 0.1/s 0.10 set_option 396 0.1/s 0.09 show_status 115 0.0/s 0.03 __ SELECT and Sort _____________________________________________________ Scan 190 0.0/s %SELECT: 0.13 Range 45.43k 8.3/s 30.38 Full join 0 0/s 0.00 Range check 0 0/s 0.00 Full rng join 0 0/s 0.00 Sort scan 11 0.0/s Sort range 8.39k 1.5/s Sort mrg pass 0 0/s __ Query Cache _________________________________________________________ Memory usage 63.62M of 256.00M %Used: 24.85 Block Fragmnt 6.68% Hits 166.09k 30.4/s Inserts 149.29k 27.3/s Insrt:Prune 149.29k:1 27.3/s Hit:Insert 1.11:1 __ Table Locks _________________________________________________________ Waited 3.76k 0.7/s %Total: 1.41 Immediate 262.48k 48.0/s __ Tables ______________________________________________________________ Open 40 of 512 %Cache: 7.81 Opened 58 0.0/s __ Connecti** _________________________________________________________ Max used 8 of 500 %Max: 1.60 Total 497 0.1/s __ Created Temp ________________________________________________________ Disk table 1 0.0/s Table 144 0.0/s Size: 256.0M File 6 0.0/s __ Threads _____________________________________________________________ Running 1 of 5 Cached 3 of 32 %Hit: 98.39 Created 8 0.0/s Slow 0 0/s __ Aborted _____________________________________________________________ Clients 0 0/s Connects 6 0.0/s __ Bytes _______________________________________________________________ Sent 173.88M 31.8k/s Received 49.21M 9.0k/s __ InnoDB Buffer Pool __________________________________________________ Usage 304.00k of 8.00M %Used: 3.71 Read hit 84.81% Pages Free 493 %Total: 96.29 Data 19 3.71 %Drty: 0.00 Misc 0 0.00 Latched 0.00 Reads 79 0.0/s From file 12 0.0/s 15.19 Ahead Rnd 1 0.0/s Ahead Sql 0 0/s Writes 0 0/s Flushes 0 0/s Wait Free 0 0/s __ InnoDB Lock _________________________________________________________ Waits 0 0/s Current 0 Time acquiring Total 0 ms Average 0 ms Max 0 ms __ InnoDB Data, Pages, Rows ____________________________________________ Data Reads 25 0.0/s Writes 3 0.0/s fsync 3 0.0/s Pending Reads 0 Writes 0 fsync 0 Pages Created 0 0/s Read 19 0.0/s Written 0 0/s Rows Deleted 0 0/s Inserted 0 0/s Read 0 0/s Updated 0 0/s
Report Header: Line 1
报表的第一行包含了三样不同的资讯:MySQL Server 的版本、自上次啟动后已经过多少时间、目前 Server 的日期与时间。有些人会定时让系统自动产生报表(eg. cron)然后用程序去分析进行分析,此时表头将可用来协助您辨识出不同时间点的报表。对於那些租用或使用虚拟主机的管理者,表头可以协助您了解自己所需面对的是什么样的 Server。MySQL Server 版本可以指出该 Server 有提供或没有提供那些功能,而它的 Uptime 则表示该报表具有多大的代表性。Uptime 是重要的指标,可让您了解此份报表所包含的资讯是否可能有偏误,一般来说 Uptime 最少要有一小时会比较适当,甚至光是一小时其实也还不够。例如您的 Server 可能已执行了六个小时,但此六小时皆是在使用率最低的午夜,此时产生出的报表就很不具有代表性。最理想的情况下,你会希望 MySQL Server 至少已经执行了一整天,这样子一来你就可以确定报表中的资讯已包含了 Server 负载的高峰与低峰期,而不是只包含其中之一。在范例报表中 Server 只执行了 34 分鐘,因此该报表的代表性是不足的,但因为这只是用来做范例,也就没什么关係。
身为 MySQL 的管理者您通常会问的第一个问题是:『Server 到底用掉了多少 key buffer?』。如果您发现 MySQL 只使用了一小部份的 Key Buffer,这并不是什么需要注意的问题,因为 MySQL 只会在需要的时候才实际分配与使用 System RAM。也就是说,当你设定 MySQL 可使用 512MB 的 RAM 时,并不代表 MySQL 啟动的时候将佔用 512MB 的 RAM(只有在 MySQL 认为需要这么做的时候才会)。报表中的第四行(Buffer used)指出 MySQL "曾经" 耗用过的最大记忆体数量,因此目前 "正在使用" 的记忆体数量有可能少於(甚至大於)这个数字。MySQL 称此数值为 "High Water Mark",但在报表的下一行我们将会看到它并不总是如此。无论如何,从 Buffer used 我们通常可以看出 key_buffer_size 这个系统变数值是否设定的够大,如果你的 MySQL 已经使用了 80~90% 以上的 Key Buffer,你就应该要调高 key_buffer_size。注意,Buffer used 永远不会有使用率超过 95% 的情况,因为 MySQL 的官方文件中指出 Share Key Buffer 中有部份将会挪用给内部资料结构使用,因此当 Buffer used 指出 Share Key Buffer 的使用率高达 95% 时,其实在实务上等於是已使用了 100% 的 Share Key Buffer。在这个例子中 Server 只使用了 380KB(0.07%) 的 Share Key Buffer,看到这里也许您会判断 Server 的 Share Key Buffer 是十分充足的,但请勿太早下定论,我们必须要接著考量报表中的下一行才能做出客观的判断......。
Current: Line 5
mysqlreport 使用 Key_blocks_unused 这个系统变数来决定目前 MySQL "正在使用" 的 Share Key Buffer 大小,只有在 MySQL Server 4.1.2 以上的版本才会有这个功能。如果报表中的上一行(Buffer used)真的有如 MySQL 官方文件中所说的是 "High Water Mark",那么 Current 所载明的数值应该永远会小於或等於它。但在接下来的例子中我们将会看到,事情并不总是如此。目前这台 Server 已经使用了大约 60MB(12%) 的 Share Key Buffer,这是一个好现象因为它代表了你的 Share Key Buffer 仍然十分充足。Current 与 Buffer used 合在一起看即可提供一个很有用的指标,告诉您目前的 key_buffer_size 是否充足。
设定 key_buffer_size 的方式也很简单,只要直接修改 MySQL 的设定档然后重新啟动 Server 即可。例如若要将 Key Buffer 设定为 2000MB,则只要在 /etc/my.cnf 中加上:
[mysqld]
key_buffer_size=2000M
Write ratio: Line 6
索引(Indexes, Keys)主要是在记忆体内(RAM-Based)进行操作的,索引之所以如此有用有部份原因就归功於它们主要是在 RAM 里面运作,因此拥有极高的存取性能,不像储存在硬盘中的资料存取速度非常慢。然而,不可否认的是 MySQL 终究还是必须从硬盘中将索引读入 RAM 或是将储存在 RAM 中的索引写回硬盘之中。Write ratio 标示著 MySQL 将索引写入硬盘与 MySQL 将索引写入 RAM 的比值(Write Ratio = MySQL 将索引写入硬盘的次数 / MySQL 将索引写入 RAM 的次数)。具有接近於 1 的 Write Ratio 并不是一件很罕见的事,就像 MySQL 官方手册中所说的,如果你的 MySQL 最主要的活动是 Update、Insert 等等,那么 Write Ratio 将会很接近於 1。Write Ratio 若大於 1 表示 MySQL 将索引写入硬盘的次数大於将索引写入 RAM 的次数,很少有 MySQL Server 的 Write Ratio 会大於 1,绝大部份都应该会小於 1,即便是负载非常重的 Server。
Read ratio: Line 7
Read Ratio 比 Write Ratio 来得重要一些,它标示了 MySQL 从硬盘读取索引与从 RAM 读取索引的比值(Read Ratio = MySQL 从硬盘读取索引的次数 / MySQL 从 RAM 读取索引的次数)。Read Ratio 的值应该要是 0.00 或 0.01,若大於这个值则表示 Server 有问题需要进一步的调查,通常此问题的成因是 Share Key Buffer 设得太小造成 MySQL 需要不断地从硬盘中读取所需要的索引资讯,而这个动作是十分没有效率的并且完全抵消了使用索引可以带来的好处。在 Server 刚啟动的头一个小时 Read Ratio 很常会出现大於 0.01 的数值,但 Server 执行过一阵子后它应该(也必须)降低至 0.01 或是 0.00。
Questi** Report: Lines 9 - 26
第二个主要的报表区块,Questi**,是第二重要的资讯,因为它可以告诉你 MySQL 到底都在忙些什么事情。Questi** 包含了 SQL queries 以及 MySQL protocol communicati**。大部份的人都只在意 Server 每秒可以处理多少查询(Queries Per Second, QPS),但若以整个 Server 的观点来考量,QPS 其实是非常不精确的数值,它无法有效的告诉您 Server 的整体运作状况。而 Questi** 则提供了较完整的资讯,让您一窥 Server 的全貌。
Total: Line 10
第一个栏位单纯的记载 MySQL 总共回应过多少查询,第二个栏位则记录回应的频率(QPS),当大部份的人说『我的 Server 平均每秒处理 XXX 个查询』时,他们指的其实就是第二个栏位所记录的回应频率。此时你应该要反问他们『在那 XXX 个查询之中,MySQL 到底做了哪些事情?』,接下来 mysqlreport 将可以协助您回答此问题......。
Distribution of Total Queries (DTQ): Lines 11 - 15
COM_ 这个类别代表著所有 MySQL 所执行过的指令,通常与 MySQL protocol 相关。在正常的情况下,你会希望这个类别所佔的比例越低越好,因为当这个数值很高的时候就表示 MySQL 正忙碌於无关紧要的事情上。若这个数值很高通常代表 MySQL 正遭遇到某些很奇怪的问题,当我们深入讨论 COM_ 的子类别的时候,我们会在回来探讨这个问题。
Unknown 是推论出来的类别,在理想的状况下,之前所述的四个分类加总起来应该要等於 Questi** 总数,但它们通常不会刚好等於。这是因为有些 Questi** MySQL 在处理时会增加 Total Questi** 的计数器,但却没有相对应的系统变数用来记录所执行过的 Questi**。在不同的 Server 上这个数值的变异很大,在有些 Server 上这个数值非常的高,在有些 Server 上则非常的低,但在大部份的情况下它应该要维持在很低的水準才是。如果这个数值非常的高,可能代表 MySQL Server 有什么地方出了问题。
DMS 的子分类项目可以告诉我们,这台 MySQL Server 是属於哪一个类型的 MySQL Server,例如它是著重在 SELECT 操作或是 INSERT 操作,大部份的 MySQL Server 都是著重在 SELECT 操作。知道某台 Server 是属於哪一个类型的 MySQL Server 有助於我们思考报表中的其他资讯,例如一台著重在 SELECT 操作的 MySQL Server 的 Write Ratio 应该会非常的接近 1,并有著较高的 Lock 时间。同时它也隐含了一个意义,就是也许你可以考虑使用 InnoDB Storage Engine,因为 MySQL 预设採用的 MyISAM Storage Engine 所提供的 Lock 层级只有 Table Lock(只能针对整个资料表锁定),而 InnoDB 则提供 Row Lock 层级的锁定机制(可只针对特定的 ROW 进行锁定,减少等待时间)。若是著重在 SELECT 操作的 Server,它的 Read Ratio 应该会接近於零,并有著非常低的 Table Lock 时间。
Connecti** Report 所代表的意义与 Tables Report 相似,请各位以此类推。比较需要注意的是:若你发现 Connecti** 的使用率接近 100%,也许你会想调大 max_connecti** 的值以允许 MySQL 的 Client 建立更多连线。然而,这通常是一种错误。我们常常可以发现很多网路上的资料会教我们要调大 max_connecti**,但却从来没有给一个明确的理由。事实上,max_connecti** 的预设值(100),就算是对於负载十分沉重但有良好调校过的 Server 都已十分足够。MySQL 对於单一连线的资料处理通常只需要零点几秒的时间即可完成,就算是最大只能使用 100 个连线也够让你用上很长一段时间。若是您的 Server 有著非常高的最大连线数(max connecti**)或是单一连线需要很长时间才可完成,那么问题八成不是 max_connecti** 的值不够大而是在别的地方,例如 slow queries、索引设计不良、甚至是过於缓慢的 DNS 解析。在您将 max_connecti** 的值调到 100 以上之前,您应该要先确定真的是因为 Server 过於忙碌而需要调高此数值,而不是其他地方出了问题。每秒平均连线数有可能会很高,事实上,若这个值很高而且 Server 的运作十分顺畅,那么这通常会是一个好现象,无需担心。大部份 Server 的每秒平均连线数应该都会低於 5/s。
Created Temp Report: Lines 59 - 62
MySQL 可以建立暂时性的资料表,它可建立在硬盘中、档案里、或是 RAM 之中,而 Created Temp Report 则提供了相关的数据供您参考。这些数据大多是相对而言,没有一定的标準,但将暂时性的资料表建立在硬盘中是十分没有效率的,因此 Disk table 的值最好是三者中最小的一个。当暂时性的资料表被建立在硬盘中,表示此资料表没有办法被放进 RAM 里面(因为 tmp_table_size 的值设得不够大)。
Threads, Aborted, Bytes Reports: Lines 64 - 76
这几个部份大多没什么好解释的,只有一个项目值得特别说明:第 66 行的最后一个栏位(%Hit)。每一个连接到 MySQL 的连线都是由不同的 Thread 来处理,当 MySQL 啟动时会预先建立一些 Threads 并保留在 Thread Cache 中,如此一来 MySQL 就不用一直忙著建立与删除 Threads。但当每秒最大连线数大於 MySQL 的 Thread Cache 时,MySQL 就会进入 Thread Thrash 的状态:它不断地建立新的 Threads 以满足不断增加的连线的需求。当 Thread Thrash 发生时,%Hit 的数值就会降低。在本范例中 %Hit 的值为 0.05%,这是非常不好的,因为它表示几乎每一个新进来的连线都会造成 MySQL 建立新的 Thread。我们可以看到在此范例中造成此现象的原凶就在第 66 行的第一个栏位,我们可以发现 Thread Cache 的值为 0,因此 thread_cache_size 的值需要调大。
话说回来,究竟 %Hit 接近於零真的有什么关係吗?Jeremy Zawondy 曾在部落格上说到:Thread caching 并不是我们最需要关心的问题,但当你解决了所有其他更严重的问题之后,它就会是最严重的问题。(hread caching really wasn't the worst of our problems. But it became the worst after we had fixed all the bigger ones.)