Amazon Redshift 是一個支持SQL查詢的、快速、可擴展的列式存儲數據庫,它支持PB級的數量查詢,是適用於企業級的數據倉庫。同時Redshift支持大規模併發查詢、支持結果集緩存,響應查詢時間最快至亞秒,比起其餘數據倉庫快將近十倍。藉助 Redshift,您的等待時間更少,可將更多時間用於獲取數據看法。node
ETL在計算機領域是一個很流行的概念,意指將數據從一個或多個源頭複製到目標系統的一個過程,其中包含三個步驟:
1,Extract 從數據源中選擇/提取須要導出的數據
2,Transform 將導出的數據根據業務須要進行必要的格式/表現形式上的轉換
3,Load 將轉換後的數據導入目標系統sql
在使用Redshift以前須要將數據導入Redshift,即Redshift的ETL。例如數據庫的遷移,將舊數據庫中的數據轉移到Redshift等等。
本文旨在分享咱們bosicloud在平常工做中關於Redshift ETL方面的一些技巧及建議:數據庫
1,使用COPY命令將多個、大小至關的文件加載到Redshift
Amazon Redshift是一個MPP數據庫,即大規模並行處理數據庫,Redshift的背後是一個EC2集羣,每一個計算節點(ec2)進一步細分爲slice,全部slice平分計算節點的處理能力。 每一個節點的slice數量取決於羣集的節點類型。 例如,每一個DS2.XLARGE計算節點都有兩個slice,而每一個DS2.8XLARGE計算節點有16個slice。
進行加載數據工做時,最好的狀況是整個工做量平分給全部的計算節點(EC2 node)的slice。當只加載一個大文件,或者加載多個大小差別較大的文件時,均可能致使計算節點工做量分配不均等,進而致使整個Redshift加載數據時性能低下。例如,咱們Redshift有兩個計算節點,在加載一個大文件時每一個節點的工做負載以下:
從上圖能夠看到,加載的任務落在了compute-0頭上,而compute-1則是閒置的,這是一個木桶原理,Redshift最終花費的時間等於工做時間最長的那個計算節點。
因此咱們最好將大文件切割爲多個大小相同的小文件,而且文件總數量正好是計算節點的整倍數,從而每一個計算節點能夠分到數目相同的小文件。另外,咱們還建議將這些小文件進行壓縮,例如gzip, lzop, or bzip2由於Redshift加載及存儲數據時都支持這幾種壓縮格式。顯然,壓縮後的數據更小了,加載的工做量也就更小了。緩存
2,使用workload management合理調整Redshift queue
Redshift經過workload management(WLM)管理着多個queue,用戶提交SQL查詢任務到Redshift時,SQL會根據提交者所在的group被分派到group對應的queue排隊等候執行。Redshift的內存及計算能力被分紅許多個單元/單位,一個slot表明一個單元的內存及計算能力,一個slot同一時間能夠執行一個SQL查詢任務,不一樣的queue擁有不一樣數量的slot,slot的數量決定該queue可以同時併發執行多少個SQL查詢任務。由於ETL每每伴隨着許多COMMIT 操做,而COMMIT 都很消耗計算資源。爲了進行ETL的同時不影響普通用戶提交SQL query,咱們bosicloud建議將ETL和普通用戶提交的SQL query分發到不一樣的queue中。不然普通用戶query可能因爲等待ETL COMMIT致使不能及時響應。
另外,爲了加快Redshift的COPY ETL過程,咱們還能夠經過wlm_query_slot_count參數調整ETL queue的slot數量,從而增長queue的內存、計算能力及SQL查詢併發數量。
安全
Redshift的WLM設置界面
3,使用」BEGIN…COMMIT」減小COMMIT次數前面咱們提到ELT是一個多步驟的任務,每一個步驟最後每每須要執行一個COMMIT,而COMMIT又是一個昂貴的操做。因此咱們bosicloud建議使用BEGIN…END 將可以合併的多個步驟儘可能合併爲一個步驟並只執行一次COMMIT,例如:
Begin
CREATE temporary staging_table;
INSERT INTO staging_table SELECT .. FROM source;
DELETE FROM table1 WHERE ???=???;
INSERT INTO table1 SELECT .. FROM staging_table;
DELETE FROM table2 WHERE ???=???;
INSERT INTO table2 SELECT .. FROM staging_table;
Commit架構
4,使用Redshift Spectrum for ad-hoc查詢
在以往,咱們能夠會爲了作ad-hoc查詢而將S3上的數據ETL加載到Redshift進行查詢。若是僅爲了偶爾的一兩次查詢而進行ETL,這個ETL將顯得很是昂貴、不划算。別忘了AWS最近推出了Redshift Spectrum新功能,即您能夠直接利用Redshift Spectrum查詢S3上的數據而無需將數據加載到Redshift中,雖然Specturm查詢相比普通Redshift查詢較慢,但比起ETL來講查詢速度仍然是大大提高了。併發
5,關於ETL健康檢查的SQL實用腳本:
返回過去1天內queue的統計信息,例如最大隊列長度和隊列時間
select startqueue,node, datediff(ms,startqueue,startwork) as queue_time, datediff(ms, startwork, endtime) as commit_time, queuelen
from stl_commit_stats
where startqueue >= dateadd(day, -1, current_Date)
order by queuelen desc , queue_time desc;
返回一個星期內所執行的COPY的相關信息,如COPY的開始時間(Starttime),所在queue的ID(query),SQL語句(querytxt),COPY的文件數量(n_files)及文件大小(size_mb)等等:
select q.starttime, s.query, substring(q.querytxt,1,120) as querytxt,
s.n_files, size_mb, s.time_seconds,
s.size_mb/decode(s.time_seconds,0,1,s.time_seconds) as mb_per_s
from (select query, count() as n_files,
sum(transfer_size/(10241024)) as size_MB, (max(end_Time) -
min(start_Time))/(1000000) as time_seconds , max(end_time) as end_time
from stl_s3client where http_method = 'GET' and query > 0
and transfer_time > 0 group by query ) as s
LEFT JOIN stl_Query as q on q.query = s.query
where s.end_Time >= dateadd(day, -7, current_Date)
order by s.time_Seconds desc, size_mb desc, s.end_time desc
limit 50;ide
創建view視圖查看每一個表空間使用狀況,請考慮將空間增加較快的表的內容unload到S3.oop
CREATE OR REPLACE VIEW admin.v_space_used_per_tbl
AS with info_table as ( SELECT TRIM(pgdb.datname) AS dbase_name
,TRIM(pgn.nspname) as schemaname
,TRIM(pgc.relname) AS tablename
,id AS tbl_oid
,b.mbytes AS megabytes
,CASE WHEN pgc.reldiststyle = 8
THEN a.rows_all_dist
ELSE a.rows END AS rowcount
,CASE WHEN pgc.reldiststyle = 8
THEN a.unsorted_rows_all_dist
ELSE a.unsorted_rows END AS unsorted_rowcount
,CASE WHEN pgc.reldiststyle = 8
THEN decode( det.n_sortkeys,0, NULL,DECODE( a.rows_all_dist,0,0, (a.unsorted_rows_all_dist::DECIMAL(32)/a.rows_all_dist)100))::DECIMAL(20,2)
ELSE decode( det.n_sortkeys,0, NULL,DECODE( a.rows,0,0, (a.unsorted_rows::DECIMAL(32)/a.rows)100))::DECIMAL(20,2) END
AS pct_unsorted
FROM ( SELECT
db_id
,id
,name
,MAX(ROWS) AS rows_all_dist
,MAX(ROWS) - MAX(sorted_rows) AS unsorted_rows_all_dist
,SUM(rows) AS rows
,SUM(rows)-SUM(sorted_rows) AS unsorted_rows
FROM stv_tbl_perm
GROUP BY db_id, id, name
) AS a
INNER JOIN
pg_class AS pgc
ON pgc.oid = a.id
INNER JOIN
pg_namespace AS pgn
ON pgn.oid = pgc.relnamespace
INNER JOIN
pg_database AS pgdb
ON pgdb.oid = a.db_id
INNER JOIN (SELECT attrelid,
MIN(CASE attisdistkey WHEN 't' THEN attname ELSE NULL END) AS "distkey",
MIN(CASE attsortkeyord WHEN 1 THEN attname ELSE NULL END) AS head_sort,
MAX(attsortkeyord) AS n_sortkeys,
MAX(attencodingtype) AS max_enc,
SUM(case when attencodingtype <> 0 then 1 else 0 end)::DECIMAL(20,3)/COUNT(attencodingtype)::DECIMAL(20,3) 100.00 as pct_enc
FROM pg_attribute
GROUP BY 1) AS det ON det.attrelid = a.id
LEFT OUTER JOIN
( SELECT
tbl
,COUNT() AS mbytes
FROM stv_blocklist
GROUP BY tbl
) AS b
ON a.id=b.tbl
WHERE pgc.relowner > 1)
select info.*
,CASE WHEN info.rowcount = 0 THEN 'n/a'
WHEN info.pct_unsorted >= 20 THEN 'VACUUM SORT recommended'
ELSE 'n/a'
END AS recommendation
from info_table info;性能
找出本週內最費時間的前50個SQL查詢(多個相同的sql查詢時間合併計算)
-- query runtimes
select trim(database) as DB, count(query) as n_qry, max(substring (qrytext,1,80)) as qrytext, min(run_seconds) as "min" , max(run_seconds) as "max", avg(run_seconds) as "avg", sum(run_seconds) as total, max(query) as max_query_id,
max(starttime)::date as last_run, aborted,
listagg(event, ', ') within group (order by query) as events
from (
select userid, label, stl_query.query, trim(database) as database, trim(querytxt) as qrytext, md5(trim(querytxt)) as qry_md5, starttime, endtime, datediff(seconds, starttime,endtime)::numeric(12,2) as run_seconds,
aborted, decode(alrt.event,'Very selective query filter','Filter','Scanned a large number of deleted rows','Deleted','Nested Loop Join in the query plan','Nested Loop','Distributed a large number of rows across the network','Distributed','Broadcasted a large number of rows across the network','Broadcast','Missing query planner statistics','Stats',alrt.event) as event
from stl_query
left outer join ( select query, trim(split_part(event,':',1)) as event from STL_ALERT_EVENT_LOG where event_time >= dateadd(day, -7, current_Date) group by query, trim(split_part(event,':',1)) ) as alrt on alrt.query = stl_query.query
where userid <> 1
-- and (querytxt like 'SELECT%' or querytxt like 'select%' )
-- and database = ''
and starttime >= dateadd(day, -7, current_Date)
)
group by database, label, qry_md5, aborted
order by total desc limit 50;
【關於博思云爲】
做爲一家專業的雲計算服務型企業,博思云爲專爲客戶提供 AWS 上的運營服務:包括架構諮詢服務、遷移服務、雲安全集成服務、混合雲管理服務、大數據服務以及 DevOps 服務。目前,博思云爲在大數據、DevOps、架構、數據庫以及操做系統等都已取得廠商認證,在上海、南京、杭州、武漢等地設有分公司。爲創新服務模式、引領 IT 服務業的發展,博思云爲將持續投入資源開展智能混合雲管理平臺、圖數據庫的研發等。