PostgreSQL中的work_mem參數
在SQLServer中有一個內存授予(Memory Grant)的概念,意思是一個執行一個查詢語句所需的內存大小,如果獲取不到這個內存,則查詢申請等待內存,因此就會受到影響。PostgreSQL有一個類似于此的work_mem參數,該參數也是執行跟查詢所使用的內存有關的,那么work_mem的具體含義是什么呢?
work_mem參數
1,work_mem的定義
??查詢操作(例如排序或哈希表)可使用的最大內存容量,注意是一個操作節點的內存使用上限(比如一個SQL中包含了排序和聚合操作,這兩個操作最大可用內存都可以達到work_mem),而不是整個SQL語句的最大可用內存。
2,work_mem默認值
??默認值是4MB,該參數是最可能首先嘗試修改的參數之一,通常情況下,增加這個值的效果是 PostgreSQL 可以在內存中完成更多操作,而不必寫到磁盤上,這往往會加快查詢速度。
3,work_mem過大的副作用
如果work_meory設得太大,而系統又有大量并發,那么PostgreSQL會遭遇到OOM異常,并報出類似 “Out of memory: Killed process ... (postgres)” 的信息,Linux操作系統會自動kill掉占用內存最大的postmaster進程。解決這個問題的方法之一是使用 overcommit_memory 參數,并將其設為 2,從根本上防止 Linux 內核 過度分配內存。
4,如何評估work_men的設置
通常情況下,在確保系統不會因為OOM導致被kill掉的情況下,增加這個值的效果是 PostgreSQL可以在內存中完成更多操作,而不必寫到磁盤上,這往往會加快查詢速度。如果一個操作超出work_mem的大小,則會寫入磁盤的臨時文件,通過磁盤來替代內存的使用。
4.1,SQL內存占用
??work_mem是一個計算節點的最大內存使用限制,并不是SQL語句的最大內存使用限制,如果SQL語句中涉及多個計算,那么整個SQL語句耗費的內存將會是N個work_mem的總和
4.2,并行查詢內存占用
??對于并行查詢,如果你有4個并行 worker(max_parallel_workers_per_gather = 4)和1個leader,總共就是5個進程,每個進程都可以使用work_mem,最終是5*work_mem的內存占用
4.3,hash操作的內存占用
??參數為hash_mem_multiplier,默認值為2,哈希的操作可以使用兩倍的work_mem,如果想讓哈希操作比排序操作使用更多內存,也可以把這個值設得更高,同時保持 work_mem 不變。
??PostgreSQL 文檔建議 hash_mem_multiplier 可上調至 8.0。這樣做的動機是:
??保持 work_mem 低,避免大排序占用太多內存,讓哈希操作優先在內存中執行,提高哈希操作速度,大型排序操作可以容忍溢寫到磁盤
4.4,如何判斷work_mem不足
??當某個查詢需要用到 超過work_mem的內存 來進行排序或哈希操作時,PostgreSQL會在磁盤上創建臨時文件。
??log_temp_files 控制 哪些大小的臨時文件會被記錄到日志。
??可以這只log_temp_files=0,這樣所有遇到work_mem不足導致磁盤使用的情況,都會記錄到日志中,該參數默認值為-1,不記錄臨時文件的使用
如果非要用公式,可以參考:(average freeable memory * 4) / max_connections這只是一個 保守默認值參考,遠高于 4 MB 的默認值。實際上,更好的方法是 觀察臨時文件生成情況,并根據需要使用 hash_mem_multiplier 區分哈希操作和排序操作。
另一個參考公式:SharedBuffers + work_mem * 2 * max_connection + (memory for file system and operation system) < RAM
https://thebuild.com/blog/2023/03/13/everything-you-know-about-setting-work_mem-is-wrong/
參考:https://pganalyze.com/blog/5mins-postgres-work-mem-tuning
浙公網安備 33010602011771號