Greenplum優化總結html
GP優化須要瞭解清理緩存、性能監控、執行計劃分析等知識。優化主要包含如下四方面:
表、字段,SQL,GP配置、服務器配置,硬件及節點資源。linux
1、 清理緩存:git
#!/usr/bin/sudo bash gpstop -r #快速中止GP數據庫 sync #清空高速緩存前嘗試將數據刷新至磁盤 #釋放linux內存 echo 1 > /proc/sys/vm/drop_caches echo 2 > /proc/sys/vm/drop_caches echo 3 > /proc/sys/vm/drop_caches gpstart #啓動GP數據庫
2、 性能監控Performance Monitorgithub
Greenplum監控管理平臺Pivotal Greenplum Command Center (GPCC)和Pivotal Greenplum (GPDB)。實際使用過程當中發現對於6-8秒的查詢(單表億級數據),GPCC反應比較慢,CPU、IO等信息爲0,能夠採用其餘方式實時監控CPU、內存、IO、網絡等信息。redis
3、 執行計劃分析
EXPLAIN 會爲查詢顯示其查詢計劃和估算的代價,可是不執行該查詢。
EXPLAIN ANALYZE除了顯示查詢的查詢計劃以外,還會執行該查詢。EXPLAIN ANALYZE會丟掉任何來自SELECT語句的輸出,可是該語句中的其餘操做會被執行(例如INSERT、UPDATE或者DELETE)。sql
slice、motion
GPDB 有一個特有的算子:移動( motion )。移動操做涉及到查詢處理期間在 Segment 之間移動數據。motion 分爲廣播( broadcast )、重分佈( redistribute motion )、Gather motion。正是 motion 算子將查詢計劃分割爲一個個 slice ,上一層 slice 對應的進程會讀取下一層各個 slice 進程廣播或重分佈的數據,而後進行計算。每個廣播或重分佈或gather會產生一個slice。每個切片在每一個數據節點會對應發起一個進程來處理該slice負責的數據。SQL中要控制切片的數量,若是太多,應適當將sql拆分,避免因爲進程太多,給數據庫、機器帶來太多的負擔,也容易致使sql失效。數據庫
Gather motion的做用就在於將每一個節點上面的中間結果集中到主節點上面。GP中的數據遷移方式爲數據廣播和數據重分佈。數組
OLAP的基本多維分析操做有鑽取(Drill-up和Drill-down)、切片(Slice)和切塊(Dice)、以及旋轉(Pivot)緩存
4、優化Greenplum鏈接bash
1.分解查詢,去除join或者減少join數據量
2.緩存映射關係
3.創建索引,分部鍵
4.使用官方驅動包
數據查詢去重
鏈接查詢:創建兩個臨時表,經過關鍵字段篩選
鏈接查詢:創建兩個臨時表,經過獲取最大關鍵字段,再比較
鏈接查詢:分組排序,添加序號,獲取序號最大值
5、優化表結構
一、表字段設計
表字段選擇恰當的字段類型,例如:數字類型選擇int4或int8,浮點數選擇float8,字符串選擇varchar(32)等。
二、表存儲方式
Heap 或 Append-Only存儲:GP默認使用堆表。堆表最好用在小表,如:維表(初始化後常常更新)。Append-Only表不能update和delete。通常用來作批量數據導入。 不建議單行插入。
多列查詢請求
行存儲 => 在select或where子句中,查詢全部列或大部分列
列存儲 => 在where或having子句中,查詢單列的值彙總或單行過濾
若數據須要頻繁地更新或者插入,則使用行存儲。
若須要同時訪問一個表的不少字段,則使用行存儲。
對於通用或者混合型業務,建議使用行存儲。
若查詢訪問的字段數目較少,或者僅在少許字段上進行聚合操做,則使用列存儲。
若僅經常修改表的某一字段而不修改其餘字段,則使用列存儲。
三、壓縮
對於大AO表和分區表使用壓縮,以提升系統I/O。在字段級別配置壓縮。考慮壓縮比和壓縮性能之間的平衡。壓縮的性能取決於硬件、查詢調優設置、其它因素。
QuickLZ - 低壓縮率、低cpu消耗、壓縮數據塊
zlib - 高壓縮率、低速
四、列存儲
列存裏面能夠啓動壓縮。只適合append-only表。
五、索引
高基數的列(惟一值多)通常來講,在Greenplum數據庫中索引不是必需的。對於高基數的列存儲表,若是須要遍歷且查詢選擇性較高,則建立單列索引。頻繁更新的列不要創建索引。
在加載大量數據以前刪除索引,加載結束後再從新建立索引。優先使用 B 樹索引。不要爲須要頻繁更新的字段建立位圖索引。不要爲惟一性字段、基數很是高或者很是低的字段建立位圖索引。不要爲事務性負載建立位圖索引。通常來講不要索引分區表。若是須要創建索引,則選擇與分區鍵不一樣的字段。可優化部分小結果集查詢。
六、 分組擴展
Greenplum數據庫的GROUP BY擴展能夠執行某些經常使用的計算,且比應用程序或者存儲過程效率高。
GROUP BY ROLLUP(col1, col2, col3)
GROUP BY CUBE(col1, col2, col3)
GROUP BY GROUPING SETS((col1, col2), (col1, col3))
ROLLUP 對分組字段(或者表達式)從最詳細級別到最頂級別計算聚合計數。ROLLUP的參數是一個有序分組字段列表,它計算從右向左各個級別的聚合。例如 ROLLUP(c1, c2, c3) 會爲下列分組條件計算彙集:
(c1, c2, c3)
(c1, c2)
(c1)
()
CUBE 爲分組字段的全部組合計算聚合。例如 CUBE(c1, c2, c3) 會計算一下聚合:
(c1, c2, c3)
(c1, c2)
(c2, c3)
(c1, c3)
(c1)
(c2)
(c3)
()
GROUPING SETS 指定對那些字段計算聚合,它能夠比ROLLUP和CUBE更精確地控制分區條件。
七、分區
黃金法則
目前Greenplum支持LIST和RANGE兩種分區類型。分區的目的是儘量的縮小QUERY須要掃描的數據量,所以必須和查詢條件相關聯。只爲大表設置分區,不要爲小表設置分區。僅在根據查詢條件能夠實現分區裁剪時使用分區表。建議優先使用範圍 (Range) 分區,不然使用列表 (List) 分區。根據查詢特色合理設置分區。不要使用相同的字段既作分區鍵又作分佈鍵。不要使用默認分區。避免使用多級分區;儘可能少地建立分區,每一個分區的數據會多些。經過查詢計劃的 EXPLAIN 結果來確保對分區表執行的查詢是選擇性掃描(分區裁剪)。對於列存儲的表,不要建立過多的分區,不然會形成物理文件過多:
Physical files = Segments * Columns * Partitions。
八、根據監控定位資源佔用較多的狀況:
CPU、內存、IO、網絡
#檢查磁盤空間使用,GP裏面就能夠查看到對應分區的使用狀況
# SELECT dfsegment,dfhostname,dfdevice,dfspace FROM gp_toolkit.gp_disk_free ORDER BY dfsegment;
# SELECT sodddatname,pg_size_pretty(sodddatsize) FROM gp_toolkit.gp_size_of_database ORDER BY sodddatname;
#查看現有配置值
# gpconfig -s work_mem;
Greenplum配置參數優化:5.10.2
GP數據庫參數配置,配置文件 postgresql.conf參數
shared_buffers:剛開始能夠設置一個較小的值,好比總內存的15%,而後逐漸增長,過程當中監控性能提高和swap的狀況。
effective_cache_size : 這個參數告訴PostgreSQL的優化器有多少內存能夠被用來緩存數據,以及幫助決定是否應該使用索引。這個數值越大,優化器使用索引的可能性也越大。 所以這個數值應該設置成shared_buffers加上可用操做系統緩存二者的總量。一般這個數值會超過系統內存總量的50%。
work_mem: 當PostgreSQL對大表進行排序時,數據庫會按照此參數指定大小進行分片排序,將中間結果存放在臨時文件中,這些中間結果的臨時文件最終會再次合併排序,因此增長此參數能夠減小臨時文件個數進而提高排序效率。固然若是設置過大,會致使swap的發生,因此設置此參數時仍需謹慎,剛開始可設定爲總內存的5%。
temp_buffers: 即臨時緩衝區,擁有數據庫訪問臨時數據,GP中默認值爲1M,在訪問比較到大的臨時表時,對性能提高有很大幫助。
gp_fts_probe_threadcount: 設置ftsprobe線程數,此參數建議大於等於每臺服務器segments的數目。
gp_hashjoin_tuples_per_bucket: 此參數越小,hash_tables越大,可提高join性能。
gp_interconnect_setup_timeout: 此參數在負載較大的集羣中,應該設置較大的值。
gp_vmem_protect_limit: 控制了每一個段數據庫爲全部運行的查詢分配的內存總量。若是查詢須要的內存超過此值,則會失敗。使用下面公式肯定合適的值:
(swap + (RAM * vm.overcommit_ratio)) * .9 / number_of_Segments_per_server
例如:8GB 交換空間,128GB 內存,vm.overcommit_ratio = 50,8 個段數據庫
(8 + (128 * .5)) * .9 / 8 = 8 GB, 則設置gp_vmem_protect_limit爲 8GB
gp_statement_mem: 服務器配置參數 gp_statement_mem 控制段數據庫上單個查詢可使用的內存總量。若是語句須要更多內存,則會溢出數據到磁盤。用下面公式肯定合適的值
(gp_vmem_protect_limit * .9) / max_expected_concurrent_queries
例如,若是併發度爲40, gp_vmeme_protect_limit爲8GB,則 gp_statement_mem 爲:
(8192MB * .9) / 40 = 184MB,每一個查詢最多可使用 184MB 內存,以後將溢出到磁盤。
gp_workfile_limit_files_per_query
若是爲SQL查詢分配的內存不足,Greenplum數據庫會建立溢出文件(也叫工做文件)。在默認狀況下,一個SQL查詢最多能夠建立 100000 個溢出文件,這足以知足大多數查詢。 該參數決定了一個查詢最多能夠建立多少個溢出文件。0 意味着沒有限制。限制溢出文件數據能夠防止失控查詢破壞整個系統。 若是分配內存不足或者出現數據傾斜,則一個SQL查詢可能產生大量溢出文件。若是超過溢出文件上限,Greenplum數據庫報告以下錯誤:
ERROR: number of workfiles per query limit exceeded
在嘗試增大gp_workfile_limit_files_per_query前,先嚐試經過修改 SQL、數據分佈策略或者內存配置以下降溢出文件個數。
max_connections: 最大鏈接數,Segment建議設置成Master的5-10倍。
6、數據庫查詢分析
1. VACUUM
vacuum只是簡單的回收空間且令其能夠再次使用,沒有請求排它鎖,仍舊能夠對錶讀寫
vacuum full執行更普遍的處理,包括跨塊移動行,以便把表壓縮至使用最少的磁盤塊數目存儲。相對vacuum要慢,並且會請求排它鎖。
按期執行:在平常維護中,須要對數據字典按期執行vacuum,能夠天天在數據庫空閒的時候進行。而後每隔一段較長時間(兩三個月)對系統表執行一次vacuum full,這個操做須要停機,比較耗時,大表可能耗時幾個小時。
reindex:執行vacuum以後,最好對錶上的索引進行重建
2. ANALYZE
命令:analyze [talbe [(column,..)]]
收集表內容的統計信息,以優化執行計劃。如建立索引後,執行此命令,對於隨即查詢將會利用索引。
自動統計信息收集,在postgresql.conf中有控制自動收集的參數gp_autostats_mode設置,gp_autostats_mode三個值:none、no_change、on_no_stats(默認)
none:禁止收集統計信息
on change:當一條DML執行後影響的行數超過gp_autostats_on_change_threshold參數指定的值時,會執行完這條DML後再自動執行一個analyze 的操做來收集表的統計信息。
no_no_stats:當使用create talbe as select 、insert 、copy時,若是在目標表中沒有收集過統計信息,那麼會自動執行analyze 來收集這張表的信息。gp默認使用on_no_stats,對數據庫的消耗比較小,可是對於不斷變動的表,數據庫在第一次收集統計信息以後就不會再收集了。須要人爲定時執行analyze.
若是有大量的運行時間在1分鐘如下的SQL,你會發現大量的時間消耗在收集統計信息上。爲了下降這一部分的消耗,能夠指定對某些列不收集統計信息,以下所示:
1. create table test(id int, name text,note text);
上面是已知道表列note不需出如今join列上,也不會出如今where語句的過濾條件下,由於能夠把這個列設置爲不收集統計信息:
1. alter table test alter note SET STATISTICS 0;
3. EXPLAIN執行計劃
顯示規劃器爲所提供的語句生成的執行規劃。
cost:返回第一行記錄前的啓動時間, 和返回全部記錄的總時間(以磁盤頁面存取爲單位計量)
rows:根據統計信息估計SQL返回結果集的行數
width:返回的結果集的每一行的長度,這個長度值是根據pg_statistic表中的統計信息來計算的。
4. 兩種聚合方式
hashaggregate 根據group by字段後面的值算出hash值,並根據前面使用的聚合函數在內存中維護對應的列表,幾個聚合函數就有幾個數組。相同數據量的狀況下,聚合字段的重複度越小,使用的內存越大。
groupaggregate 先將表中的數據按照group by的字段排序,在對排好序的數據進行全掃描,並進行聚合函數計算。消耗內存基本是恆定的。
選擇方式,在SQL中有大量的聚合函數,group by的字段重複值比較少的時候,應該用groupaggregate
5. 關聯
分爲三類:hash join、nestloop join、merge join,在保證sql執行正確的前提下,規劃器優先採用hash join。
hash join: 先對其中一張關聯的表計算hash值,在內存中用一個散列表保存,而後對另一張表進行全表掃描,以後將每一行與這個散列表進行關聯。
nestedloop:關聯的兩張表中的數據量比較小的表進行廣播,如笛卡爾積:select * fromtest1,test2
merge join:將兩張表按照關聯鍵進行排序,而後按照歸併排序的方式將數據進行關聯,效率比hash join差。full outer join只能採用merge join來實現。
關聯的廣播與重分佈解析P133,通常規劃器會自動選擇最優執行計劃。有時會致使重分佈和廣播,比較耗時的操做。
6. 重分佈
一些sql查詢中,須要數據在各節點從新分佈,受制於網絡傳輸、磁盤I/O,重分佈的速度比較慢。
關聯鍵強制類型轉換
通常,表按照指定的分佈鍵做hash分部。若是兩個表按照id:intege、id:numericr分佈,關聯時,須要有一個表id做強制類型轉化,由於不一樣類型的hash值不同,於是致使數據重分佈。
關聯鍵與分部鍵不一致
group by、開窗函數、grouping sets會引起重分佈
查詢優化
經過explain觀察執行計劃,從而肯定若是優化SQL。
7. 選擇合適分佈鍵
分佈鍵選擇不當會致使重分佈、數據分佈不均等,而數據分佈不均會使SQL集中在一個segment節點的執行,限制了gp總體的速度。使全部節點數據存放是均勻的,數據分佈均勻才能充分利用多臺機器查詢,發揮分佈式的優點。join、開窗函數等儘可能以分佈鍵做爲關聯鍵、分區鍵。尤爲須要注意的是join、開窗函數會依據關聯鍵、分區鍵作重分佈或者廣播操做,於是若分佈鍵和關聯鍵不一致,不論如何修改分佈鍵,也是須要再次重分佈的。儘可能保證where條件產生的結果集的存儲也儘可能是均勻的。
查看某表是否分佈不均: select gp_segment_id,count(*) from fact_tablegroup by gp_segment_id;
在segment一級,能夠經過 select gp_segment_id,count(*) from fact_table group by gp_segment_id; 的方式檢查每張表的數據是否均勻存放在系統級,能夠直接用 df -h 或 du -h檢查磁盤或者目錄數據是否均勻
查看數據庫中數據傾斜的表
首先定義數據傾斜率爲:最大子節點數據量/平均節點數據量。爲避免整張表的數據量爲空,同時對結果的影響很小,在平均節點數據量基礎上加上一個很小的值,SQL以下:
SELECT tabname, max(SIZE)/(avg(SIZE)+0.001) AS max_div_avg, sum(SIZE) total_size FROM (SELECT gp_segment_id, oid::regclass tabname, pg_relation_size(oid) SIZE FROM gp_dist_random('pg_class') WHERE relkind='r' AND relstorage IN ('a','h')) t GROUP BY tabname ORDER BY 2 DESC;
8. 分區表
按照某字段進行分區,不影響數據在數據節點上的分佈,可是,僅在單個數據節點上,對數據進行分區存儲。能夠加快分區字段的查詢速度。
9. 壓縮表
對於大AO表和分區表使用壓縮,以節省存儲空間並提升系統I/O,也能夠在字段級別配置壓縮。應用場景:
不須要對錶進行更新和刪除操做、訪問表的時候基本上是全表掃描,不須要創建索引、不能常常對錶添加字段或者修改字段類型。
9. 窗口函數
窗口函數能夠實如今結果集的分組子集上的聚合或者排名函數,例如 sum(population) over (partition by city)。窗口函數功能強大,性能優異。由於它在數據庫內部進行計算,避免了數據傳輸。
窗口函數row_number()計算一行在分組子集中的行號,例如 row_number() over (order by id)。若是查詢計劃顯示某個表被掃描屢次,那麼經過窗口函數可能能夠下降掃描次數。窗口函數一般能夠避免使用自關聯。
10. 列存儲和行存儲
列存儲亦即同一列的數據都連續保存在一個物理文件中,有更高的壓縮率,適合在寬表中對部分字段進行篩選的場景。須要注意的是:若集羣中節點較多,並且表的列也較多,每一個節點的每一列將會至少產生一個文件,那麼整體上將會產生比較多的文件,對錶的DDL操做就會比較慢。在和分區表使用時,將會產生更多文件,甚至可能超過linux的文件句柄限制,要尤爲注意。
行存儲:若是記錄須要 update/delete,那麼只能選擇非壓縮的行存方式。對於查詢,若是選擇的列的數量常常超過30個以上的列,那麼也應該選擇行存方式。
列存儲:若是選擇列的數量很是有限,而且但願經過較高的壓縮比換取海量數據查詢時的較好的 IO性能,那麼就應該選擇列存模式。其中,列存分區表,每一個分區的每一個列都會有一個對應的物理文件,因此要注意避免文件過多,致使可能超越linux上容許同時打開文件數量的上限以及DDL命令的效率不好。
11. 函數和存儲過程
雖然支持遊標可是,儘可能不要使用遊標方式處理數據,而是應該把數據做爲一個總體進行操做。
12. 索引使用
若是是從超大結果集合中返回很是小的結果集(不超過5%),建議使用BTREE索引(非典型數據倉庫操做),表記錄的存儲順序最好與索引一致,能夠進一步減小IO(好的index cluster)
where條件中的列用or的方式進行join,能夠考慮使用索引。鍵值大量重複時,比較適合使用bitmap索引。
參考資料:
Greenplum 的分佈式框架結構:http://www.javashuo.com/article/p-mynyvdxx-eh.html
Greenplum函數參考:https://gp-docs-cn.github.io/docs/ref_guide/function-summary.html#top