執行計劃沒變,執行時快時慢是怎么回事?
?今天遇到D-SMART產品本身的一個性能問題,我準備用D-SMART給一套Oracle數據庫做個巡檢,發現居然任務因為一條SQL超時而異常了。通過日志發現是一條分析某個指標的SQL。
執行時間居然高達229秒,巡檢報告中設定了SQL超時時間是180秒,而如果巡檢的時間區間超過一個半月,則這條sql的執行時間介于170秒到250秒之間,就經常會超時了。
D-SMART的后臺數據庫是PG,這張表是一張TIMESCALEDB的表。表上也創建了適當的索引。通過explain分析看,執行計劃也是正常的,通過這個分區索引做范圍掃描,然后做聚合(Timescaledb會按照時間戳自動做數據分區)。通過D-SMART的PG數據庫等待事件分析工具可以發現,數據文件讀是排在前面的。
剛開始的時候我也沒有仔細分析,通過EXPAIN發現sort buffer使用量接近20M,明顯超出了WORK_MEM參數。于是我調整了WORK_MEM參數,重新執行了這條SQL。發現原來需要200多秒的SQL不到50毫秒就完成了。不過我還是留了個心眼,因為D-SMART分析工具里可以看出文件讀占了比較靠前的位置。于是我重啟了一下PG數據庫,再次執行這條SQL。比剛才稍微慢了一點,大概80多毫秒。不過比起200多秒來,也提升不少。于是我和同事說,這條SQL的性能問題解決了,加大WORK_MEM參數就可以了。
老儲還是在PG上有豐富的實戰經驗,他提醒我,驗證PG的問題,重啟數據庫是沒用的,文件緩沖會影響SQL的性能。搞了二十多年Oracle,總是用Oracle的思維來思考現在的數據庫問題,這回又犯了類似的錯誤。于是我重新做了測試,關閉數據庫,然后使用echo 3 > drop_caches命令清除OS緩沖,然后再進行測試。
令人遺憾的是,SQL的性能又回到了從前,看樣子加大WORK_MEM并沒有有效的改善SQL性能。回過頭來想想也是,哪怕因為排序緩沖超了一點,做了硬盤排序,也不可能有20秒的性能影響。
公司的這套PG 14.4的環境是裝在一臺虛擬機上的,磁盤是SATA盤,性能確實不行。對于PG這樣使用DOUBLE CACHE的數據庫,文件緩沖確實可以對SQL性能有明顯的幫助。而這種特性也會讓PG數據庫的同一條SQL語句在OS的不同狀態下執行性能有較大的波動。下面我們通過一個例子來驗證一下。
在做這個測試之前,我們先要安裝一個插件-pgfincore,對這個插件有興趣的朋友可以去https://github.com/klando/pgfincore 下載。Pgfincore是針對PG數據庫的OS緩沖分析與操作的插件,一般被用戶用來分析OS緩沖中的數據庫表或者索引,也被部分用戶用來預熱數據,讓部分熱數據總是被緩沖在FILE CACHE中,從而讓OS CACHE能夠更好的發揮作用。
Pgfincore的功能十分強大,首先可以用來查看某張表或者索引在OS緩沖中的情況。比如:
我檢查的一個timescaledb的索引分區,總共有15.7萬個page,其中13.9萬個page在OS緩沖里了。
第二個功能是把某張表或者索引的數據預熱到OS CACHE里。這里要注意的是如果表是分區表,一定要直接預熱分區,而不要使用表的名字,pgfincore不支持自動識別表分區。Timescaledb的一個表分區,原本這張表并沒有完全被緩沖到內存里,通過調用pgfadvise_willneed函數,把這張表的所有數據都調用到OS緩沖中了。
第三個功能是備份和恢復某個場景下的OS CACHE。這對于一些十分關鍵的系統的預熱十分有價值。比如說某個系統的某些熱數據對于系統性能十分關鍵。當系統重啟(特別是服務器重啟)后的某個時間段里,數據沒有預熱完成之前,系統性能是會有較大影響的。如果我們在停機重啟前,先備份OS CACHE中某些熱表的緩沖情況,系統重啟后立即預熱這部分數據,則可以確保系統重啟后立即恢復重啟前的性能。
首先在系統重啟前將pgfincore的數據保存在pgfincore_snapshot表中,系統重啟后使用pgfadvise_loader重新裝載緩沖數據。
有了上面的基礎知識,我們下面就來做一個實驗。
首先對OS緩沖做一個完全的清理。然后啟動PG數據庫。執行剛才有問題的那條SQL語句。
我只截取了部分執行計劃,因為針對每個分區,都是相同的掃描方式,先對索引做掃描,然后再回表。這條SQL執行了34秒多。
接下來我們先按照上面的流程再次關閉數據庫,清理緩沖,然后把所有的索引分區都先預熱一下,看看效果如何。
可以看出,現在所有索引的OS緩沖項都是0,說明沒有任何索引數據被緩存了。接下來預熱,然后再次執行這條SQL。
大家可以看到,預熱后,這些索引分區都在OS緩沖里了,同樣再把所有的表的數據也預熱一下。再來執行剛才的SQL語句:
大家可以看到,執行時間從34秒變成了31毫秒。實際上對于使用double cache的數據庫來說,此類問題是十分常見的。此類數據庫產品的同一條SQL在不同時間里執行的性能可能差異上百倍,但是其執行計劃是完全相同的。這是因為DOUBLE CACHE的原因。Pgfincore插件為解決此類問題提供了一個很好的解決方案。利用snapshot/restore的方式,如果做一些適當的精細化管理,可以起到十分好的穩定關鍵業務SQL執行效率的作用。希望我的這個性能故障的案例能夠給大家一些啟示。?