背景
數據庫運維過程中,dba都比較關注sql的執行時間。研發在數據庫應用開發上,速度慢的sql比比皆是,很多速度很慢都是sql寫得不好,效率不高,執行過程中也會造成數據庫的負載過大。比如無用的去重,無效的條件,不必要的子查詢,sql用不上的索引。而對於這些不符合要求的sql,首先要去把這些sql找出來。
措施
pg數據庫提供了統計信息的功能來查找,下面介紹兩種辦法:
- 修改日志參數,記錄超過指定時間的sql,以及當時的執行時間
- 通過pg_stat_statements統計
修改日志參數
log_min_duration_statement:從log中找出執行超過一定時間的sql。這個參數是設置執行最小多長時間的sql輸出到log,例如輸出執行超過3秒的sql,可以設置log_min_duration_statement = 3s。這個參數設置為-1是無效,默認為-1。設置為0是輸出所有的sql,但這樣會增加服務器的負擔,一般不要設置太低的值。
auto_explain功能:在Postgresql8.4版本后新增了該功能。默認這個功能是不可用的,需要配置如下。這樣系統在執行的時候遇到超過2秒的SQL的話,,會自動把sql輸出到log,這樣看log就更容易找到問題點了。
shared_preload_libraries = 'auto_explain'
custom_variable_classes = 'auto_explain' #PostgreSQL9.2版本后此參數已取消,不需要設置
auto_explain.log_min_duration = 2s
實際log查看:
< 2019-11-12 15:40:30.284 CST > 日志: 執行時間: 3048.397 ms 語句: SELECT * FROM indexedresult WHERE searchtitle LIKE '%好%' ORDER BY searchtitle
加載pg_stat_statements模塊
pg_stat_statements模塊提供了一種方法,用於跟蹤所有由服務器執行的sql語句的統計,例如,語句總調用次數,總執行時間,從內存中讀取的塊數,從磁盤讀取的塊數等信息。在添加或刪除模塊pg_stat_statements模塊時,需要額外的共享內存,所以必須重啟數據庫。pg_stat_statements模塊加載會消耗部分的內存,可以通過pg_stat_statements.max * track_activity_query_size來計算。這個值是比較小的,假如pg_stat_statements.max 值為 10000, track_activity_query_size值為4096,也就消耗了40M內存。
參考配置如下:
shared_preload_libraries = 'pg_stat_statements '
track_activity_query_size = 4096 #SQL文本的最大大小,4K
custom_variable_classes = 'pg_stat_statements ' #PostgreSQL9.2版本后此參數已取消,不需要設置
pg_stat_statements.max = 10000 #跟蹤模塊中的語句的最大數目
pg_stat_statements.track = all
參數配置好后,需要重啟數據庫。注意該模塊是區分數據庫的,不是全局共享的。如果無法查詢,可能需要在對應的數據庫下面加載pg_stat_statements模塊。運行如下語句:
CREATE EXTENSION pg_stat_statements;
配置好pg_stat_statements模塊后,經過一段時間的運行,我們就可以通過pg_stat_statements視圖來統計效率低的SQL,語句如下:
--查詢語句總調用次數大於10次,平均運行時間倒序的SQL
SELECT t.userid,
t.dbid,
t.query || ';',
t.calls,
t.total_time,
t.rows,
t.total_time / t.calls
FROM pg_stat_statements t
WHERE (t.calls IS NOT NULL OR t.calls <> 0)
AND t.query !~ '^COPY|<insufficient privilege'
AND t.calls > 10
ORDER BY 7 DESC;
總結
上面兩種方法可以根據實際業務需要來進行,比如僅僅需要查看問題sql的情況可以用第一種,如果需要深入分析sql的類別,執行次數,執行時間等更豐富的信息可以采用第二種方式,根據調用的次數來設計緩存也是非常重要的依據。