首頁 > 軟體

PostgreSQL資料庫效能調優的注意點以及pg資料庫效能優化方式

2023-03-17 06:06:57

PostgreSQL 優化思路

優化思路:

0、為每個表執行 ANALYZE

然後分析 EXPLAIN (ANALYZE,BUFFERS) sql。

1、對於多表查詢,檢視每張表資料,然後改進連線順序。

2、先查詢那部分是重點語句,比如上面SQL,外面的巢狀層對於優化來說沒有意義,可以去掉。

3、檢視語句中,where等條件子句,每個欄位能過濾的效率。找出可優化處。

比如oc.order_id = oo.order_id是關聯條件,需要加索引

  • oc.op_type = 3 能過濾出1/20的資料,
  • oo.event_type IN (…) 能過濾出1/10的資料,

這兩個是優化的重點,也就是實現確保op_type與event_type已經加了索引,其次確保索參照到了。

一、排序

  • 儘量避免
  • 排序的資料量儘量少,並保證在記憶體裡完成排序。

(至於具體什麼資料量能在記憶體中完成排序,不同資料庫有不同的設定:oracle是sort_area_size;postgresql是work_mem (integer),單位是KB,預設值是4MB。mysql是sort_buffer_size 注意:該引數對應的分配記憶體是每連線獨佔!)

二、索引

  • 過濾的資料量比較少,一般來說<20%,應該走索引。20%-40% 可能走索引也可能不走索引。> 40% ,基本不走索引(會全表掃描)
  • 保證值的資料型別和欄位資料型別要一直。
  • 對索引的欄位進行計算時,必須在運運算元右側進行計算。也就是 to_char(oc.create_date, ‘yyyyMMdd’)是沒用的
  • 表欄位之間關聯,儘量給相關欄位上新增索引。
  • 複合索引,遵從最左字首的原則,即最左優先。(單獨右側欄位查詢沒有索引的)

三、連線查詢方式

1、hash join

  • 放記憶體裡進行關聯。
  • 適用於結果集比較大的情況。
  • 比如都是200000資料

2、nest loop

  • 從結果1 逐行取出,然後與結果集2進行匹配。
  • 適用於兩個結果集,其中一個資料量遠大於另外一個時。
  • 結果集一:1000
  • 結果集二:1000000

四、多表聯查時

在多表聯查時,需要考慮連線順序問題。

1、當postgresql中進行查詢時,如果多表是通過逗號,而不是join連線,那麼連線順序是多表的笛卡爾積中取最優的。如果有太多輸入的表, PostgreSQL規劃器將從窮舉搜尋切換為基因概率搜尋,以減少可能性數目(樣本空間)。基因搜尋花的時間少, 但是並不一定能找到最好的規劃。

2、對於JOIN

  • LEFT JOIN / RIGHT JOIN 會一定程度上指定連線順序,但是還是會在某種程度上重新排列:
  • FULL JOIN 完全強制連線順序。

如果要強制規劃器遵循準確的JOIN連線順序,我們可以把執行時引數join_collapse_limit設定為 1

PostgreSQL提供了一些效能調優的功能

主要有如下幾個方面。

1.使用EXPLAIN

EXPLAIN命令可以檢視執行計劃,這個方法是我們最主要的偵錯工具。

2.及時更新執行計劃中使用的統計資訊

由於統計資訊不是每次運算元據庫都進行更新的,一般是在 VACUUM 、 ANALYZE 、 CREATE INDEX等DDL執行的時候會更新統計資訊,

因此執行計劃所用的統計資訊很有可能比較舊。 這樣執行計劃的分析結果可能誤差會變大。

以下是表tenk1的相關的一部分統計資訊。

SELECT relname, relkind, reltuples, relpages FROM pg_class WHERE relname LIKE 'tenk1%';
relnamerelkindreltuplesrelpages
tenk1r10000358
tenk1_hundredi1000030
tenk1_thous_tenthousi1000030
tenk1_unique1i1000030
tenk1_unique2i1000030

(5 rows)

其中 relkind是型別,r是自身表,i是索引index;reltuples是專案數;relpages是所佔硬碟的塊數。

3.明確用join來關聯表

一般寫法:

SELECT * FROM a, b, c WHERE a.id = b.id AND b.ref = c.id;

如果明確用join的話,執行時候執行計劃相對容易控制一些。

例子:

SELECT * FROM a CROSS JOIN b CROSS JOIN c WHERE a.id = b.id AND b.ref = c.id;
SELECT * FROM a JOIN (b JOIN c ON (b.ref = c.id)) ON (a.id = b.id);

4.關閉自動提交

(autocommit=false)

5.多次插入資料用copy命令更高效

我們有的處理中要對同一張表執行很多次insert操作。這個時候我們用copy命令更有效率。因為insert一次,其相關的index都要做一次,比較花費時間。

6.臨時刪除index

有時候我們在備份和重新匯入資料的時候,如果資料量很大的話,要很幾個小時才能完成。這個時候可以先把index刪除掉。匯入在建index。

7.外來鍵關聯的刪除

如果表的有外來鍵的話,每次操作都沒去check外來鍵整合性。因此比較慢。資料匯入後在建立外來鍵也是一種選擇。

8.增加maintenance_work_mem引數大小

增加這個引數可以提升CREATE INDEX和ALTER TABLE ADD FOREIGN KEY的執行效率。

9.增加checkpoint_segments引數的大小

增加這個引數可以提升大量資料匯入時候的速度。

10.設定archive_mode無效

這個引數設定為無效的時候,能夠提升以下的操作的速度

  • CREATE TABLE AS SELECT
  • CREATE INDEX
  • ALTER TABLE SET TABLESPACE
  • CLUSTER等。

11.最後執行VACUUM ANALYZE

表中資料大量變化的時候建議執行VACUUM ANALYZE。

對生產執行的資料庫要用定時任務crontb執行如下操作:

psql -U username -d databasename -c "vacuum verbose analyze tablename;"

PostgreSQL 引數設定

autovacuum 相關引數

autovacuum:
預設為on,表示是否開起autovacuum。預設開起。特別的,當需要凍結xid時,儘管此值為off,PG也會進行vacuum。 

autovacuum_naptime:
下一次vacuum的時間,預設1min。 這個naptime會被vacuum launcher分配到每個DB上。autovacuum_naptime/num of db。 

log_autovacuum_min_duration:
記錄autovacuum動作到紀錄檔檔案,當vacuum動作超過此值時。 「-1」表示不記錄。「0」表示每次都記錄。 

autovacuum_max_workers:
最大同時執行的worker數量,不包含launcher本身。 

autovacuum_work_mem:
每個worker可使用的最大記憶體數。

autovacuum_vacuum_threshold:
預設50。與autovacuum_vacuum_scale_factor配合使用,autovacuum_vacuum_scale_factor預設值為20%。當update,delete的tuples數量超過autovacuum_vacuum_scale_factor*table_size+autovacuum_vacuum_threshold時,進行vacuum。如果要使vacuum工作勤奮點,則將此值改小。 

autovacuum_analyze_threshold:
預設50。與autovacuum_analyze_scale_factor配合使用。

autovacuum_analyze_scale_factor:
預設10%。當update,insert,delete的tuples數量超過autovacuum_analyze_scale_factor*table_size+autovacuum_analyze_threshold時,進行analyze。 

autovacuum_freeze_max_age:200 million。離下一次進行xid凍結的最大事務數。 

autovacuum_multixact_freeze_max_age:
400 million。離下一次進行xid凍結的最大事務數。 

autovacuum_vacuum_cost_delay:
如果為-1,取vacuum_cost_delay值。 

autovacuum_vacuum_cost_limit:
如果為-1,到vacuum_cost_limit的值,這個值是所有worker的累加值。
選項預設值說明是否優化原因
max_connections100允許使用者端連線的最大數目因為在測試的過程中,100個連線已經足夠
fsyncon強制把資料同步更新到磁碟因為系統的IO壓力很大,為了更好的測試其他設定的影響,把改引數改為off
shared_buffers24MB決定有多少記憶體可以被PostgreSQL用於快取資料(推薦記憶體的1/4)在IO壓力很大的情況下,提高該值可以減少IO
work_mem1MB使內部排序和一些複雜的查詢都在這個buffer中完成有助提高排序等操作的速度,並且減低IO
effective_cache_size128MB優化器假設一個查詢可以用的最大記憶體,和shared_buffers無關(推薦記憶體的1/2)設定稍大,優化器更傾向使用索引掃描而不是順序掃描
maintenance_work_mem16MB這裡定義的記憶體只是被VACUUM等耗費資源較多的命令呼叫時使用把該值調大,能加快命令的執行
wal_buffer768kB紀錄檔快取區的大小可以降低IO,如果遇上比較多的並行短事務,應該和commit_delay一起用
checkpoint_segments3設定wal log的最大數量數(一個log的大小為16M)預設的48M的快取是一個嚴重的瓶頸,基本上都要設定為10以上
checkpoint_completion_target0.5表示checkpoint的完成時間要在兩個checkpoint間隔時間的N%內完成能降低平均寫入的開銷
commit_delay0事務提交後,紀錄檔寫到wal log上到wal_buffer寫入到磁碟的時間間隔。需要配合commit_sibling能夠一次寫入多個事務,減少IO,提高效能
commit_siblings5設定觸發commit_delay的並行事務數,根據並行事務多少來設定減少IO,提高效能
autovacuum_naptime1min下一次vacuum任務的時間提高這個間隔時間,使他不是太頻繁
autovacuum_analyze_threshold50與autovacuum_analyze_scale_factor配合使用,來決定是否analyze使analyze的頻率符合實際
autovacuum_analyze_scale_factor0.1當update,insert,delete的tuples數量超過autovacuum_analyze_scale_factor*table_size+autovacuum_analyze_threshold時,進行analyze。使analyze的頻率符合實際

pg中效能相關常調引數

引數名稱引數意義優化思路
shared_buffers資料庫伺服器將使用的共用記憶體緩衝區大小,該緩衝區為所有連線共用。從磁碟讀入的資料(主要包括表和索引)都快取在這裡。提高該值可以減少資料庫的磁碟IO。
work_mem宣告內部排序和雜湊操作可使用的工作記憶體大小。該記憶體是在開始使用臨時磁碟檔案之前使用的記憶體數目。數值以kB為單位的,預設是 1024 (1MB)。請注意對於複雜的查詢,可能會同時並行執行好幾個排序或者雜湊操作,每個都會使用這個引數宣告的這麼多記憶體,然後才會開始求助於臨時檔案。同樣,好幾個正在執行的對談可能會同時進行排序操作。因此使用的總記憶體可能是 work_mem 的好幾倍。ORDER BY, DISTINCT 和mergejoin都要用到排序操作,而雜湊操作在雜湊連線、雜湊聚集和以雜湊為基礎的 IN 子查詢處理中都會用到。該引數是對談級引數。執行排序操作時,會根據work_mem的大小決定是否將一個大的結果集拆分為幾個小的和 work_mem差不多大小的臨時檔案寫入外存。顯然拆分的結果是導致了IO,降低了排序的速度。因此增加work_mem有助於提高排序的速度。通常設定時可以逐漸調大,知道資料庫在排序的操作時不會有大量的寫檔案操作即可。該記憶體每個連線一份,當並行連線較多時候,該值不宜過大。
effective_cache_size優化器假設一個查詢可以使用的最大記憶體(包括pg使用的和作業系統快取),和shared_buffer等記憶體無關,只是給優化器生成計劃使用的一個假設值。設定稍大,優化器更傾向使用索引掃描而不是順序掃描,建議的設定為可用空閒記憶體的25%,這裡的可用空閒記憶體指的是主機實體記憶體在執行pg時得空閒值。
maintenance_work_mem這裡定義的記憶體只是在CREATE INDEX, VACUUM等時用到,因此用到的頻率不高,但是往往這些指令消耗比較多的資源,因此應該儘快讓這些指令快速執行完畢。在資料庫匯入資料後,執行建索引等操作時,可以調大,比如512M。
wal_buffers紀錄檔緩衝區,紀錄檔緩衝區的大小。兩種情況下要酌情調大:1.單事務的資料修改量很大,產生的紀錄檔大於wal_buffers,為了避免多次IO,調大該值。
2.系統中並行小資料量修改的短事務較多,並且設定了commit_delay,此時wal_buffers需要容納多個事務(commit_siblings個)的紀錄檔,調大該值避免多次IO。
commit_delay事務提交後,紀錄檔寫到wal_buffer上到wal_buffer寫到磁碟的時間間隔。如果並行的非唯讀事務數目較多,可以適當增加該值,使紀錄檔緩衝區一次刷盤可以刷出較多的事務,減少IO次數,提高效能。需要和commit_sibling配合使用。
commit_siblings觸發commit_delay等待的並行事務數,也就是系統的並行活躍事務數達到了該值事務才會等待commit_delay的時間才將紀錄檔刷盤,如果系統中並行活躍事務達不到該值,commit_delay將不起作用,防止在系統並行壓力較小的情況下事務提交後空等其他事務。應根據系統並行寫的負載設定。例如統計出系統並行執行增刪改操作的平均連線數,設定該值為該平均連線數。
fsync設定為on時,紀錄檔緩衝區刷盤時,需要確認已經將其寫入了磁碟,設定為off時,由作業系統排程磁碟寫的操作,能更好利用快取機制,提高IO效能。該效能的提高是伴隨了資料丟失的風險,當作業系統或主機崩潰時,不保證刷出的紀錄檔是否真正寫入了磁碟。應依據作業系統和主機的穩定性來設定。
autovacuum是否開啟自動清理程序(如開啟需要同時設定引數stats_start_collector = on,stats_row_level = on,),整理資料檔案碎片,更新統計資訊。如果系統中有大量的增刪改操作,建議開啟自動清理程序,這樣一方面可以增加資料檔案的物理連續性,減少磁碟的隨機IO,一方面可以隨時更新資料庫的統計資訊,使優化器可以選擇最優的查詢計劃得到最好的查詢效能。如果系統中只有唯讀的事務,那麼關閉自動清理程序。
autovacuum_naptime自動清理程序執行清理分析的時間間隔應該根據資料庫的單位時間更新量來決定該值,一般來說單位時間的更新量越大該時間間隔應該設定越短。由於自動清理對系統的開銷較大,該值應該謹慎設定(不要過小)。
bgwriter_delay後臺寫程序的自動執行時間後臺寫程序的作用是將shared_buffer裡的髒頁面寫回到磁碟,減少checkpoint的壓力,如果系統資料修改的壓力一直很大,建議將該時間間隔設定小一些,以免積累的大量的髒頁面到checkpoint,使checkpoint時間過長(checkpoint期間系統響應速度較慢)。
bgwriter_lru_maxpages後臺寫程序一次寫出的髒頁面數依據系統單位時間資料的增刪改量來修改
bgwriter_lru_multiplier後臺寫程序根據最近服務程序需要的buffer數量乘上這個比率估算出下次服務程序需要的buffer數量,在使用後臺寫程序寫回髒頁面,使緩衝區能使用的乾淨頁面達到這個估計值。依據系統單位時間資料的增刪改量來修改。

總結

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com