最近正在進行ETL后臺系統數據的日志分析,查看運行耗時長的TASK,并找出耗時長的JOB,進行邏輯層面和數據庫層面的優化.本文僅從數據庫層面上的優化著手(包括SQL語句的調整以及greenplum table dk的調整).查看一個耗時30分鐘左右的JOB,找到相應的源表,進行如下分析:
dw=#select gp_segment_id, count ( * ) from tb_name group by gp_segment_id order by count ( * ) desc
gp_segment_id count
----------------------
65 16655
說明:gp_segment_id是greenplum table里面的一個隱藏列,用來標記該行屬于哪個節點.由此可見,該表只分布在一個節點65上(節點信息請查看gp_segment_configuration),而我的gp總共有96個節點,這顯然沒有利用到gp多節點運算能力,該表的DK值設置的有問題.因此,使用alter table tb_name set distributed by (col1,...)對表的DK值進行重新設置.然后重新運行上面的語句,一方面觀察節點數(是否每個節點都分布了),另一方面觀察節點的條數(分布是否平衡)。在上述二項觀察指標大致滿足要求后,請vacuum full、vacuum analyze一樣,徹底回收空間+收集統計信息。把耗時長JOB的源表抓出來,逐個分析,整個TASK的執行時長從3小時縮短到2小時左右(主要是之前表設計的太差,才導致有這么大的優化空間),后期就是對邏輯以及SQL的優化,以及提高并發度,這才是王道。
為了統計分析方便,設計了如下二張表和若干function,用來收集表的分布情況,并發現哪些表需要進行重新調整DK值。
-- 二張表 CREATE TABLE " public "."table_segment_statistics" ( "table_name" varchar ( 200 ) DEFAULT NULL , "segment_count" int4 DEFAULT NULL , "table_rows" int8 DEFAULT NULL ); CREATE TABLE " public "."table_segment_statistics_balance" ( "table_name" varchar ( 200 ) DEFAULT NULL , "segment_id" int4 DEFAULT NULL , "segment_count" int8 DEFAULT NULL ); -- function CREATE OR REPLACE FUNCTION " public "."analyze_table_dk_balance"(v_schemaname varchar ) RETURNS "pg_catalog"."int4" AS $BODY$ DECLARE v_tb varchar ( 200 ); v_cur_tb cursor for select schemaname || ' . ' || tablename from pg_tables where schemaname <> ' information_schema ' and schemaname <> ' pg_catalog ' and schemaname <> ' gp_toolkit ' and tablename not like ' %prt% ' and schemaname = v_schemaname; BEGIN truncate table public .table_segment_statistics; truncate table public .table_segment_statistics_balance; open v_cur_tb; loop fetch v_cur_tb into v_tb; if not found THEN exit ; end if ; execute ' insert into public.table_segment_statistics select ''' || v_tb || ''' as table_name,count(*) as segment_id,sum(num) as table_rows from (select gp_segment_id,count(*) num from ' || v_tb || ' group by gp_segment_id) t ' ; execute ' insert into public.table_segment_statistics_balance select ''' || v_tb || ''' as table_name,gp_segment_id,count(*) as cnt from ' || v_tb || ' group by gp_segment_id order by gp_segment_id ' ; end loop; RETURN 0 ; end ; $BODY$ LANGUAGE ' plpgsql ' VOLATILE;
分析的語句如下:
-- 96指的是greenplum的節點(我的機器是96個) select * from public .table_segment_statistics where table_rows is not null and segment_count < 96 and table_rows > 10000 order by table_rows desc ; -- 找出比平均值超出10%的節點,這個閥值可以自行調整,另:只統計超過1萬行的表,小表沒有太大的分析意義 select a."table_name",b.segment_id,a.table_rows / a.segment_count as reldk,b.segment_count from " public ".table_segment_statistics a inner join " public ".table_segment_statistics_balance b on a."table_name" = b."table_name" where a."table_name" is not null and a.table_rows > 10000 and abs (a.table_rows / a.segment_count - b.segment_count) / (a.table_rows / a.segment_count) > 0.1
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
