MySQL源代码:由参数query_response_time_stats想到的

来源:互联网 发布:新闻小偷源码 编辑:程序博客网 时间:2024/06/06 01:31

转载请署名:印风

---------------------------------------------

Percona提供了一个参数query_response_time_stats用于在服务器端观察数据库的响应时间

root@test 02:29:35>show variables like'query_response_time_stats';

+---------------------------+-------+

| Variable_name             | Value |

+---------------------------+-------+

| query_response_time_stats | OFF   |

+---------------------------+-------+

1 row in set (0.00 sec)

 

将这个全局变量设置为‘ON’即可观察响应时间

root@test 02:29:47>set globalquery_response_time_stats = 'ON';

Query OK, 0 rows affected (0.00 sec)

 

响应时间信息被记录在一个内建的I_S 插件中:QUERY_RESPONSE_TIME,其结构如下,包含3个字段:

root@information_schema 02:56:37>desc QUERY_RESPONSE_TIME;

+-------+------------------+------+-----+---------+-------+

| Field | Type            | Null | Key | Default | Extra |

+-------+------------------+------+-----+---------+-------+

| time  | varchar(14)      | NO  |     |         |      |

| count | int(11) unsigned | NO   |    | 0       |       |

| total | varchar(14)     | NO   |     |        |       |

+-------+------------------+------+-----+---------+-------+

3 rows in set (0.00 sec)

 

root@information_schema 04:28:01>select * from QUERY_RESPONSE_TIME;

+----------------+-------+----------------+

| time           |count | total          |

+----------------+-------+----------------+

|       0.000001|     0 |       0.000000 |

|       0.000010|     0 |       0.000000 |

|       0.000100|    16 |       0.000697 |

|       0.001000|    11 |       0.002144 |

|       0.010000|     0 |       0.000000 |

|       0.100000|     0 |       0.000000 |

|       1.000000|     0 |       0.000000 |

|      10.000000|     0 |       0.000000 |

|     100.000000|     0 |       0.000000 |

|    1000.000000|     0 |       0.000000 |

|   10000.000000|     0 |       0.000000 |

|  100000.000000|     0 |      0.000000 |

| 1000000.000000 |    0 |       0.000000 |

| TOO LONG      |     0 | TOO LONG       |

+----------------+-------+----------------+

 

其中time代表RT区间(可以通过参数query_response_time_range_base)来设置,count表示该区间里收集的SQL数,total表示这些SQL的执行总时间

在代码sql/query_response_time.cc里实现了该i_s表。在系统启动时(init_server_components函数)进行初始化(空函数),在sql_show.cc里声明内建i_s表

字段定义:

ST_FIELD_INFO  query_response_time_fields_info[]

在i_s表描述数组(ST_SCHEMA_TABLEschema_tables[])中的定义如下:

#ifdef  HAVE_RESPONSE_TIME_DISTRIBUTION

  {"QUERY_RESPONSE_TIME",query_response_time_fields_info, create_schema_table,

   query_response_time_fill, make_old_format,0, -1, -1, 0, 0},

#else

  {"QUERY_RESPONSE_TIME",query_response_time_fields_info, create_schema_table,

   0, make_old_format, 0, -1, -1, 0, 0},

#endif //HAVE_RESPONSE_TIME_DISTRIBUTION

这里有一个有趣的现象,即使用宏HAVE_RESPONSE_TIME_DISTRIBUTION来定义。这取决于具体的Percona Server版本

那么RT到底是如何计算的呢,这里有两个关键函数:

query_response_time_fill

query_response_time_collect

后者用于收集统计信息,我们注意到在函数log_slow_statement函数中调用到了该函数,但注意,如果定义了log_slow_filter选项,可能会导致不收集信息

RT收集函数实际调用为:

query_response_time::g_collector.collect(query_time);

其中query_time代表当前sql的执行时间

计算的方式也很简单,对于query_time属于的那个时间区间,执行:

     if(m_utility->bound(i) > time)      {       my_atomic_rwlock_wrlock(&time_collector_lock);       my_atomic_add32((int32*)(&m_count[i]), 1);       my_atomic_add64((int64*)(&m_total[i]), time);       my_atomic_rwlock_wrunlock(&time_collector_lock);        break;      }

可以看到其实现还是相当简单的。

query_response_time_fill函数是在每次去select或show QUERY_RESPONSE_TIME的时候被调用,用于向I_S表中填充数据,具体可以参考如何编写I_S插件

话说最后一行显示的字符串看起来有点不爽,这里我们可以做一个简单的修改,使得表中的最后一行显示之前的总和值

当然啦,我们也可以以自己想要的其他方式来对数据进行呈现,开放的源代码赋予了无限的可能。这里的修改只是娱乐一番:)

效果:

root@information_schema 07:50:46>select * fromQUERY_RESPONSE_TIME where time = 'sum';

+------+-------+----------------+

| time | count | total          |

+------+-------+----------------+

| sum  |     9 |      0.006465 |

+------+-------+----------------+

1 row in set (0.00 sec)

Patch如下:

---Percona-Server-5.5.18.stock/sql/query_response_time.cc     2012-01-07 16:38:37.000000000 +0800+++Percona-Server-5.5.18.rt/sql/query_response_time.cc 2012-01-07 19:28:07.000000000 +0800@@-222,7 +222,9 @@    DBUG_ENTER("fill_schema_query_response_time");     TABLE        *table=static_cast<TABLE*>(tables->table);     Field        **fields= table->field;-    for(uint i= 0, count= bound_count() + 1 /*with overflow */; count > i; ++i)+    uint64 sum_total=0;+      uint32 sum_count=0;+      for(uint i= 0, count= bound_count() + 1 /*with overflow */; count > i; ++i)     {       char time[TIME_STRING_BUFFER_LENGTH];       char total[TOTAL_STRING_BUFFER_LENGTH];@@-230,17 +232,24 @@       {                assert(sizeof(TIME_OVERFLOW) <=TIME_STRING_BUFFER_LENGTH);         assert(sizeof(TIME_OVERFLOW) <=TOTAL_STRING_BUFFER_LENGTH);-       memcpy(time,TIME_OVERFLOW,sizeof(TIME_OVERFLOW));-       memcpy(total,TIME_OVERFLOW,sizeof(TIME_OVERFLOW));+             print_time(total, sizeof(total),TOTAL_STRING_FORMAT, sum_total);+             bzero(time, sizeof(time));+             memcpy(time,"sum", 4);+             fields[0]->store(time,strlen(time),system_charset_info);+             fields[1]->store(sum_count);+             fields[2]->store(total,strlen(total),system_charset_info);       }       else       {         print_time(time, sizeof(time),TIME_STRING_FORMAT, this->bound(i));         print_time(total, sizeof(total),TOTAL_STRING_FORMAT, this->total(i));-      }-     fields[0]->store(time,strlen(time),system_charset_info);-      fields[1]->store(this->count(i));-     fields[2]->store(total,strlen(total),system_charset_info);+             my_atomic_add32((int32*)(&sum_count),this->count(i));+             my_atomic_add64((int64*)(&sum_total),this->total(i));+     +      fields[0]->store(time,strlen(time),system_charset_info);+      fields[1]->store(this->count(i));+      fields[2]->store(total,strlen(total),system_charset_info);+        }       if (schema_table_store_record(thd,table))       {       DBUG_RETURN(1);