慢查詢代碼分析

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)  
...

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章