慢查询代码分析

1. 慢查询功能实现

数据库一般都带慢查询功能,PostgreSQL数据库可以通过加载插件 pg_stat_statements
实现慢日志功能,对应数据库中的一个表pg_stat_statements,可以通过查看该表获取某个SQL
执行的次数,总花费时间等信息;MySQL带慢查询功能,通过参数设置即可打开慢查询功能。

mysql 慢查询参数设置
slow_query_log = 1 – 慢日志开关
long_query_time = 1 – sql阈值,单位为秒
slow_query_log_file = /home/wl/mysqlcluster/app5726/slowlog/mysql-slow.log – 日志文件名

2. 功能实现思路

2.1 要做什么

慢查询主要功能如下:设定sql执行阈值,超过该阈值的sql语句需要记录到对应的表或者文件
中,那么需要的内容如下:
(1) 慢日志开关
(2) sql执行时间阈值
(3) 慢日志记录的文件名称
(4) 记录对应的格式:一般需要包括:时刻、用户名、ip、端口号、库名、sql语句、执行总时间、
开始时间、结束时间。

2.2 如何做

(1) 主要是如何记录开始时间、结束时间。需要在类 class THD中添加2个变量:start_time,
end_time;
(2) 在语句开始处理时(语句解析前,也就是从客户端发送的语句在数据库最开始处理时)用
thd->start_time记录当前时刻,精确到us,使用函数gettimeofday;在语句执行结束时用thd->end_time
记录结束时间,然后将时间差与sql语句阈值进行比较。
(3) 对于日志文件,如慢日志开关打开,则open 打开该日志文件;写日志用write,刷盘 fflush 函数
,close函数关闭文件

3. MySQL 代码对应的慢日志实现

3.1 系统参数

slow_query_log
long_query_time
slow_query_log_file

如何添加系统参数见对用文件介绍。

3.2 记录开始时间 thd->set_time()

dispatch_command 函数 中调用
thd->enable_slow_log= TRUE; 

thd->set_time();  -- 记录时间

set_time 实现如下:
inline void set_time()
  {
    start_utime= utime_after_lock= my_micro_time();
    if (user_time.tv_sec || user_time.tv_usec)
    {
      start_time= user_time;
    }
    else
      my_micro_time_to_timeval(start_utime, &start_time);

#ifdef HAVE_PSI_THREAD_INTERFACE
    PSI_THREAD_CALL(set_thread_start_time)(start_time.tv_sec);
#endif
  }
:: start_time 是 class Thd 中的成员变量。
结构体 start_time 能直接赋值?
:: 可以直接赋值,是浅拷贝。


my_micro_time 函数实现如下:
ulonglong my_micro_time()
{
#ifdef _WIN32
  ulonglong newtime;
  my_get_system_time_as_file_time((FILETIME*)&newtime);
  newtime-= OFFSET_TO_EPOCH;
  return (newtime/10);
#else
  ulonglong newtime;
  struct timeval t;
  /*
    The following loop is here because gettimeofday may fail on some systems
  */
  while (gettimeofday(&t, NULL) != 0)
  {}
  newtime= (ulonglong)t.tv_sec * 1000000 + t.tv_usec;
  return newtime;
#endif
}


需要再仔细看下 class THD 的定义

3.2 标识是否是慢查询

见函数 void update_server_status()

  /**
   Update server status after execution of a top level statement.

   Currently only checks if a query was slow, and assigns
   the status accordingly.
   Evaluate the current time, and if it exceeds the long-query-time
   setting, mark the query as slow.
  */
  void update_server_status()
  {
    ulonglong end_utime_of_query= current_utime();
    if (end_utime_of_query > utime_after_lock + variables.long_query_time)
      server_status|= SERVER_QUERY_WAS_SLOW;
  }

其中 start_utime= utime_after_lock 见上面的thd->set_time()

3.3 慢查询实现的相关函数

log_slow_statement(thd);

bool File_query_log::write_slow(THD *thd, ulonglong current_utime,
                                ulonglong query_start_arg,
                                const char *user_host,
                                size_t user_host_len, ulonglong query_utime,
                                ulonglong lock_utime, bool is_command,
                                const char *sql_text, size_t sql_text_len)
...


bool Query_logger::slow_log_write(THD *thd, const char *query,  
                                  size_t query_length)  
...

你可能感兴趣的:(mysql,数据库,mysql)