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