【问题描述】
Queries_per_sec (QPS)是数据库两个比较重要的性能计数器指标。我们经常要求开发告知这个参数,以评估数据库的一个负载情况。下面的这段代码连上服务器,做一个简单的查询:
using (MySqlConnection conn = new MySqlConnection())
{
conn.ConnectionString = "Database=xx;Host=xx;Port=xx;User Id=xx; Password=xx; charset=utf8;pooling=true;";
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = conn;
conn.Open();
cmd.CommandText = " select * from test where ID = 3";
cmd.ExecuteNonQuery();
conn.Close();
}
我们加一个循环,执行200万次。可以看到Queries_per_sec 大约在930次/秒。
Questions_per_sec 大约在620次/秒
执行的时间从14:56:52开始到16:45:22结束,约6510秒,期间执行200万次。根据我们的理解,QPS应该在 200万/6510 = 310次/秒左右。但我们系统采集的Queries_per_sec或Questions_per_sec都和这个数据不符。Questions_per_sec是期望值的两倍,Queries_per_sec是期望值的三倍。这是为什么呢。
【问题分析】
性能计数器是我们从show global status采集而来。其中的Questions和Queries定义如下:
Questions
The number of statements executed by the server. This includes only statements sent to the server by clients and not statements executed within stored programs, unlike the Queries variable. This variable does not count COM_PING, COM_STATISTICS, COM_STMT_PREPARE, COM_STMT_CLOSE, or COM_STMT_RESET commands.
Queries
The number of statements executed by the server. This variable includes statements executed within stored programs, unlike the Questions variable. It does not count COM_PING or COM_STATISTICS commands.
这个定义有点复杂。我们在服务器上开启General Log, 就可以看到,上面的查询其实还包含Init DB的操作:
3499308 Init DB testdb
3499308 Query select * from test where ID = 3
3499308 Init DB testdb
3499308 Query select * from test where ID = 3
所以,这就解释了为何Questions_per_sec 比我们预期的多了一倍,这是因为有Init DB操作的缘故。
应该还有另外一个操作,使得Queries_per_sec 这个性能计数器是我们预期的QPS的三倍左右。我们跟踪show global status like 'com_%'; 这个命令,可以发现下面三个计数在增加:
1、Com_admin_commands
2、Com_change_db
3、Com_select
第二和第三比较好解释,Com_Change_DB相当于我们的Init DB, COM_Select就是我们的SELECT查询。而第一个Com_admin_commands就比较奇怪了。经查代码,这是下面的几计数器的集合。其他的一般都用不到,能用到的就剩下COM_PING了。
COM_CHANGE_USER
COM_SHUTDOWN
COM_PING
COM_DEBUG
COM_BINLOG_DUMP_GTID
COM_BINLOG_DUMP
所以问题就比较清楚了。
【结论】
Queries_per_sec 比我们预期的QPS高三倍,是由于驱动程序对连接有Ping的一个检验动作。这个动作应该也算作Queries。在Questions里体现不出来。