背景:
目前在做數字化審計時候某業務需要在Oracle中跑的長SQl,需要弄到hive中跑。原本Oracle中又不注意表設計。業務又複雜,所以SQL就很長。而且Hive 中很多Oracle函數中還跑不起來。
業務簡述:
我先把業務描述下。就是計算某個步驟(APP_NO)的5個核心子步驟(process_id)的耗時。
比如:
表結構大概:
1個APP_NO 對應多個 process_id
難點:
難點1:子步驟不固定
不知道哪些process_id 爲一組。有的甚至是有20多個 process_id 爲一組。
有可能是 23333到23336 是一組算步驟1, 也有可能23333到23334算步驟1。 也有可能本身 23333就算步驟1.
甚至有的沒有步驟1
且數據也存在後期填補可能, 也就是你可能遇到步驟1 只有開始時間, 沒有結束時間。因爲數據可能沒有采集呢。
難點2:節假日不固定
目前接手時候SQl大概爲。
select app_no,
步驟1開始時間,
步驟1結束時間,
(select count(1) from 日期表 where bewteen 步驟1開始時間 and 步驟1結束 ),
步驟2開始時間,
步驟2結束時間,
(select count(1) from 日期表 where bewteen 步驟2開始時間 and 步驟2結束 )............
有人說可以根據開始時間,結束時間。算兩個時間相隔多少天。但是此處不可行。 因爲是算工作日天數的。 每年的節假日都不同。
難點3:標量子查詢改造
我們把輸出列中嵌套select語句的叫標量子查詢。
也有說使用left join 改造SQL。
單純用left join 改造的話, 難點又有了,因爲用left join 後數據量會翻幾十甚至幾百倍。
比如兩個時間相隔20天。而且又是5個標量啊。 5個left join ???
比如: A left join B on bewteen and….. A表2個時間, B表一個時間。而且是不等式關聯。 大家可以百度下 不等式標量子查詢看看就知道了。
雖然可以說用group by但是在關聯時候就已經翻翻了。只不過最後group by 重新聚合了而已。 而且不要忘記有5個標量子查詢。
解決方案:
我大概想了2種解決方案。這裏說最終採用的
第一步: 子步驟識別
首先解決 哪幾個process_id 爲子步驟。 我採用的是製造一列。
第二步 子步驟合併:
當然了涉及到數據填補,填補結束時間啊, 因爲有的數據就沒有結束時間。
也就是說結果需要有開始時間,必須有結束時間。
第三步 獲取多少工作日
把所有步驟合併後,只要left join 日期表一次就可以取出工作日。 當然這個涉及到效率問題。可以理解爲 1:N:N轉化爲1:N。
SQL我記得大概
Select t.*, count(t2) from t left join t_日期表t2 on
t1.開始時間>= t2時間 and t1.結束時間<= t2時間 and isworkday=true
group by t.*;
第四步 行列轉換獲取需要的數據
基於以上結果表
Select APP_NO,
max( case when type = ‘步驟1’ then 開始時間 else null end ) 步驟1開始時間,
max( case when type = ‘步驟1’ then 開始時間 else null end ) 步驟1結束時間
max( case when type = ‘步驟1’ then 工作日天數 else null end ) 步驟1工作日天數
…………
結果類似:
至此,功能完成。測試過了結果 2萬多條數據,在1分鐘左右出結果。效率還會更快,後期在說把……
總結:
接到這個業務的時候,基表數據非常不整齊,缺數據,少數據更是常見的。 大數據的基表數據可能來自文件數據,結構化的數據。 因此數據非常的不整潔。往往大數據項目組必然有數據清洗。 正是數據不整齊,大數據項目對業務模型,數據模型的要求是更高的。
如果我前期沒有做數據整理, 基本上這個業務不好做, 而且本身大數據項目數據量大, 如果我不改造取日期計算, 將會是1:N:N:N:N:N. 因爲是5個核心步驟。關聯後數據量無法想象。估計不論多少節點估計暴內存。 可以透露下 process_id 基表數據量應該在 1個億左右。