postgresql 性能優化

一個優化的SQL:
SELECT order_date,
      order_source,
      SUM(commodity_num) num,
      SUM(actual_charge) charge
  FROM (
  SELECT to_char(oc.create_date, 'yyyyMMdd') AS order_date,
              (CASE
                WHEN oo.event_type = 'ONLINE_COMMODITY_ORDER' THEN
                  '線上'
                ELSE
                  '線下'
              END) order_source,
              oc.commodity_num,
              oc.actual_charge actual_charge
          FROM ord.ord_commodity_hb_2017 AS oc, ord.ord_order_hb_2017 AS oo
        WHERE oc.order_id = oo.order_id
          AND oc.op_type = 3            -- 3個值 ,3->5000 大概1/20的數據
          AND oc.create_date BETWEEN '2017-02-05' AND '2017-12-07' -- 無用
          AND oc.corp_org_id = 106      -- 無用
          AND oo.trade_state = 11        -- 3個值  11 --> 71萬行,一半數據
          AND oo.event_type IN (values('ONLINE_COMMODITY_ORDER'),
                                ('USER_CANCEL'),
                                ('USER_COMMODITY_UPDATE'))    -- 大概1/10 數據
                                ORDER BY oc.create_date    -- 若是業務不強制,最好去掉排序,若是不能去掉,最好等過濾數據量到儘可能小時再排序
                                ) T
GROUP BY order_date, order_source;
View Code

 

 
 
 
下面默認以postgresql爲例:
 

1、排序:

1. 儘可能避免
2. 排序的數據量儘可能少,並保證在內存裏完成排序。
(至於具體什麼數據量能在內存中完成排序,不一樣數據庫有不一樣的配置:
    oracle是sort_area_size;
    postgresql是work_mem (integer),單位是KB,默認值是4MB。
    mysql是sort_buffer_size 注意:該參數對應的分配內存是每鏈接獨佔!
    )
 

2、索引:

1. 過濾的數據量比較少,通常來講<20%,應該走索引。20%-40% 可能走索引也可能不走索引。> 40% ,基本不走索引(會全表掃描)
2. 保證值的數據類型和字段數據類型要一直。
3. 對索引的字段進行計算時,必須在運算符右側進行計算。也就是 to_char(oc.create_date, 'yyyyMMdd')是沒用的
4. 表字段之間關聯,儘可能給相關字段上添加索引。
5. 複合索引,聽從最左前綴的原則,即最左優先。(單獨右側字段查詢沒有索引的)
 
 

3、鏈接查詢方式:

一、hash join
 
放內存裏進行關聯。
適用於結果集比較大的狀況。
好比都是200000數據
 
二、nest loop
 
從結果1 逐行取出,而後與結果集2進行匹配。
適用於兩個結果集,其中一個數據量遠大於另一個時。
結果集一:1000
結果集二:1000000
 

4、多表聯查時:

在多表聯查時,須要考慮鏈接順序問題。
    一、當postgresql中進行查詢時,若是多表是經過逗號,而不是join鏈接,那麼鏈接順序是多表的笛卡爾積中取最優的。若是有太多輸入的表, PostgreSQL規劃器將從窮舉搜索切換爲基因機率搜索,以減小可能性數目(樣本空間)。基因搜索花的時間少, 可是並不必定能找到最好的規劃。
   
    二、對於JOIN,
        LEFT JOIN / RIGHT JOIN 會必定程度上指定鏈接順序,可是仍是會在某種程度上從新排列:
        FULL JOIN 徹底強制鏈接順序。
        若是要強制規劃器遵循準確的JOIN鏈接順序,咱們能夠把運行時參數join_collapse_limit設置爲 1
    
 

5、PostgreSQL提供了一些性能調優的功能:

 
優化思路:
    0、爲每一個表執行 ANALYZE <table>。而後分析 EXPLAIN (ANALYZE, BUFFERS) sql。
    一、對於多表查詢,查看每張表數據,而後改進鏈接順序。
    二、先查找那部分是重點語句,好比上面SQL,外面的嵌套層對於優化來講沒有意義,能夠去掉。
    三、查看語句中,where等條件子句,每一個字段能過濾的效率。找出可優化處。
        好比oc.order_id = oo.order_id是關聯條件,須要加索引
        oc.op_type = 3 能過濾出1/20的數據,
        oo.event_type IN (...) 能過濾出1/10的數據,
        這兩個是優化的重點,也就是實現確保op_type與event_type已經加了索引,其次確保索引用到了。
 
優化方案:
 
a) 總體優化:
一、使用EXPLAIN
  EXPLAIN命令能夠查看執行計劃,這個方法是咱們最主要的調試工具。
 
二、及時更新執行計劃中使用的統計信息
       因爲統計信息不是每次操做數據庫都進行更新的,通常是在 VACUUM 、 ANALYZE 、 CREATE INDEX等DDL執行的時候會更新統計信息, 
所以執行計劃所用的統計信息頗有可能比較舊。 這樣執行計劃的分析結果可能偏差會變大。
如下是表tenk1的相關的一部分統計信息。
SELECT relname, relkind, reltuples, relpages
FROM pg_class
WHERE relname LIKE 'tenk1%';

      relname                  | relkind | reltuples | relpages
----------------------+---------+-----------+----------
  tenk1                            | r      |    10000 |      358
  tenk1_hundred              | i      |    10000 |      30
  tenk1_thous_tenthous    | i      |    10000 |      30
  tenk1_unique1              | i      |    10000 |      30
  tenk1_unique2              | i        |    10000 |      30
(5 rows)


其中 relkind是類型,r是自身表,i是索引index;reltuples是項目數;relpages是所佔硬盤的塊數。
 
估計成本經過  (磁盤頁面讀取【 relpages 】*seq_page_cost)+(行掃描【 reltuples 】*cpu_tuple_cost)計算。
默認狀況下, seq_page_cost是1.0,cpu_tuple_cost是0.01。
名字 類型 描述
relpages int4 以頁(大小爲BLCKSZ)的此表在磁盤上的形式的大小。 它只是規劃器用的一個近似值,是由VACUUM,ANALYZE 和幾個 DDL 命令,好比CREATE INDEX更新。
reltuples float4 表中行的數目。只是規劃器使用的一個估計值,由VACUUM,ANALYZE 和幾個 DDL 命令,好比CREATE INDEX更新。
三、使用臨時表(with)
對於數據量大,且沒法有效優化時,可使用臨時表來過濾數據,下降數據數量級。
 
四、對於會影響結果的分析,可使用 begin;...rollback;來回滾。
 
b) 查詢優化:
一、明確用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);
 
c) 插入更新優化
一、關閉自動提交(autocommit=false)
若是有多條數據庫插入或更新等,最好關閉自動提交,這樣能提升效率
 
二、屢次插入數據用copy命令更高效
  咱們有的處理中要對同一張表執行不少次insert操做。這個時候咱們用copy命令更有效率。由於insert一次,其相關的index都要作一次,比較花費時間。
 
三、臨時刪除index【具體能夠查看Navicat表數據生成sql的語句,就是先刪再建的】
  有時候咱們在備份和從新導入數據的時候,若是數據量很大的話,要好幾個小時才能完成。這個時候能夠先把index刪除掉。導入後再建index。
 
四、外鍵關聯的刪除
  若是表的有外鍵的話,每次操做都沒去check外鍵整合性。所以比較慢。數據導入後再創建外鍵也是一種選擇。
 
 
d) 修改參數:
選項 默認值 說明 是否優化 緣由
max_connections 100 容許客戶端鏈接的最大數目 由於在測試的過程當中,100個鏈接已經足夠
fsync on 強制把數據同步更新到磁盤 由於系統的IO壓力很大,爲了更好的測試其餘配置的影響,把改參數改成off
shared_buffers 24MB 決定有多少內存能夠被PostgreSQL用於緩存數據(推薦內存的1/4) 在IO壓力很大的狀況下,提升該值能夠減小IO
work_mem 1MB 使內部排序和一些複雜的查詢都在這個buffer中完成 有助提升排序等操做的速度,而且減低IO
effective_cache_size 128MB 優化器假設一個查詢能夠用的最大內存,和shared_buffers無關(推薦內存的1/2) 設置稍大,優化器更傾向使用索引掃描而不是順序掃描
maintenance_work_mem 16MB 這裏定義的內存只是被VACUUM等耗費資源較多的命令調用時使用 把該值調大,能加快命令的執行
wal_buffer 768kB 日誌緩存區的大小 能夠下降IO,若是趕上比較多的併發短事務,應該和commit_delay一塊兒用
checkpoint_segments 3 設置wal log的最大數量數(一個log的大小爲16M) 默認的48M的緩存是一個嚴重的瓶頸,基本上都要設置爲10以上
checkpoint_completion_target 0.5 表示checkpoint的完成時間要在兩個checkpoint間隔時間的N%內完成 能下降平均寫入的開銷
commit_delay 0 事務提交後,日誌寫到wal log上到wal_buffer寫入到磁盤的時間間隔。須要配合commit_sibling 可以一次寫入多個事務,減小IO,提升性能
commit_siblings 5 設置觸發commit_delay的併發事務數,根據併發事務多少來配置 減小IO,提升性能
autovacuum_naptime 1min 下一次vacuum任務的時間 提升這個間隔時間,使他不是太頻繁
autovacuum_analyze_threshold 50 與autovacuum_analyze_scale_factor配合使用,來決定是否analyze 使analyze的頻率符合實際
autovacuum_analyze_scale_factor 0.1 當update,insert,delete的tuples數量超過autovacuum_analyze_scale_factor*table_size+autovacuum_analyze_threshold時,進行analyze。 使analyze的頻率符合實際

下面介紹幾個我認爲重要的:
一、增長maintenance_work_mem參數大小
  增長這個參數能夠提高CREATE INDEX和ALTER TABLE ADD FOREIGN KEY的執行效率。
 
二、增長checkpoint_segments參數的大小
  增長這個參數能夠提高大量數據導入時候的速度。
 
三、設置archive_mode無效
  這個參數設置爲無效的時候,可以提高如下的操做的速度
  ・CREATE TABLE AS SELECT
  ・CREATE INDEX
  ・ALTER TABLE SET TABLESPACE
  ・CLUSTER等。
 
四、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_age200 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的累加值。
 
 
 
相關文章
相關標籤/搜索