SQL:多維度切片分析之清腦技巧

最近在跨團(tuán)隊(duì)支持一個(gè)數(shù)據(jù)底層開發(fā)項(xiàng)目,獲益良多樱调,將其中的多維度聚合數(shù)據(jù)處理和SQL優(yōu)化方法梳理總結(jié)到此篇约素,以備來日回查。

(1)問題描述:什么是多維度切片

在對(duì)業(yè)務(wù)進(jìn)行復(fù)盤分析和搭建監(jiān)控體系時(shí)笆凌,BI需要對(duì)不同的維度組合進(jìn)行多維度聚合統(tǒng)計(jì)圣猎,比如分別看在某月中:
1)整體的業(yè)務(wù)指標(biāo)——維度:整體
2)渠道的業(yè)務(wù)指標(biāo)——維度:渠道
3)業(yè)務(wù)線的業(yè)務(wù)指標(biāo)——維度:業(yè)務(wù)線
4)城市的業(yè)務(wù)指標(biāo)——維度:城市
5)每個(gè)渠道在各城市的業(yè)務(wù)指標(biāo)——維度:渠道X城市
6)每個(gè)業(yè)務(wù)線在各城市的業(yè)務(wù)指標(biāo)——維度:業(yè)務(wù)線X城市
7)每個(gè)業(yè)務(wù)線在各渠道的業(yè)務(wù)指標(biāo)——維度:業(yè)務(wù)線X渠道
8)每個(gè)業(yè)務(wù)線在各城市的不同渠道的業(yè)務(wù)指標(biāo)——維度:業(yè)務(wù)線X城市X渠道

維度每多包一層,數(shù)據(jù)體量成指數(shù)增長(zhǎng)乞而,多維度聚合分析在維度多的情況下跑數(shù)非常耗資源送悔,造成數(shù)據(jù)延遲產(chǎn)出、任務(wù)被殺爪模,且指標(biāo)匯總時(shí)容易出錯(cuò)欠啤,因此需要特別注意維度適宜選取和代碼優(yōu)化。

(2)案例分析:多維度統(tǒng)計(jì)時(shí)高效聚合難點(diǎn)

當(dāng)用戶與維度之間存在多對(duì)多的關(guān)系時(shí)屋灌,同一個(gè)用戶在某個(gè)維度下會(huì)出現(xiàn)多次(不同維度取值)洁段,用戶ID可以去重求和,但是用戶ID所對(duì)應(yīng)的數(shù)值指標(biāo)無法直接求和共郭。

假設(shè)字段如下:
表T1為流量表祠丝,含有字段:

user_id(用戶ID),
gender(性別)落塑,
channel(渠道)纽疟,
city(城市)憾赁,
page_id(頁(yè)面ID),
log_time(訪問頁(yè)面時(shí)刻)

表T2為訂單表蟆肆,含有字段:

user_id(用戶ID),
order_id(訂單ID)炎功,
payment(訂單支付金額)
分區(qū)ds均為日。

如何求不同性別赁温、城市股囊、渠道的DAU(即user_id去重)更啄、PV(訪問頁(yè)面次數(shù)求和)、訂單數(shù)(即order_id去重)内狗、總凈G(即訂單支付金額求和)义锥?

預(yù)處理:
1)將表T1按照user_id缨该,gender,channel,city維度統(tǒng)計(jì)PV熄云,新表記作 newT1;
2)將表T2按照user_id統(tǒng)計(jì)當(dāng)日總訂單數(shù)和支付金額荚守,新表記作 newT2矗漾;
3)兩個(gè)新表合并得到表T:

user_id薄料,
gender,
channel誊役,
city,
pv(訪問頁(yè)面次數(shù))击孩,
order_cnt(用戶當(dāng)日總訂單筆數(shù))鹏漆,
pay_sum(用戶當(dāng)日總訂單支付金額)

乍一看艺玲,貌似直接按照性別、城市又跛、渠道group by一下求和就好了若治,實(shí)際并不是那么簡(jiǎn)單,先把數(shù)據(jù)拿出來看下:

表T

如果按照性別分組:
select gender, sum(pv),sum(order_cnt),sum(pay_sum)
from T group by gender


將得到男性訂單數(shù)為4(而實(shí)際只有2單,總計(jì)支付金額只有60婆跑,上海和蘇州重復(fù)算了)滑进,女性訂單也是類似情況。

易錯(cuò)點(diǎn):
這里的問題在于阴汇,訂單沒有歸因到城市和渠道节槐,而是跟著user_id走,但user_id又可以對(duì)應(yīng)多個(gè)不同的城市哥倔、不同的渠道揍庄,因此在進(jìn)行城市/渠道維度切片時(shí)同一個(gè)user_id的order_cnt和pay_sum會(huì)被重復(fù)計(jì)算。

那可以怎么做呢府阀?

(3)升級(jí)解法:在用戶粒度即進(jìn)行多維度聚合

解決辦法:先對(duì)user_id粒度進(jìn)行多維度聚合芽突,再把訂單關(guān)聯(lián)到user_id!

多維度切片分析一般語法:

select 
        V1,V2,V3,V4,
        grouping__id, ----------聚合分組的編號(hào)田巴,區(qū)分是哪種維度組合方式
        count(…),
        sum(…)
from T1
group by V1壹哺,V2艘刚,V3,V4
grouping sets( ------------不同維度組合方式
(),
(V1),
(V2),
(V3),
(V1,V2),
(V1,V3),
(V1,V2,V3),
)

對(duì)于上面的案例箩朴,可以首先將T1按user_id+其他維度一起進(jìn)行聚合:

select 
        user_id,gender,channel,city,
        grouping__id as group_type, ----------聚合分組的編號(hào)炸庞,區(qū)分是哪種維度組合方式
        count(1) as pv
from T1
group by user_id,gender,channel,city,
grouping sets( ------------不同維度組合方式
(user_id),
(user_id,gender),
(user_id,channel),
(user_id,city),
(user_id,channel,gender),
(user_id,channel,city),
(user_id,city,gender),
)

這里有兩個(gè)技巧:
1)grouping函數(shù)使用:進(jìn)行多維度聚合的時(shí)候荚斯,不在聚合維度的字段會(huì)默認(rèn)空值,容易與真實(shí)的空值混淆滥壕,需要做一層判斷處理:
if(grouping(gender)=0,gender,'ALL') as gender

grouping([字段名])判斷字段是否加入聚合捏浊,=0則是撞叨,=1則否
不進(jìn)行聚合則為“ALL”牵敷,代表對(duì)這個(gè)維度整體統(tǒng)計(jì)法希,不再細(xì)分切片。

2)conv函數(shù)巧妙“翻譯”分組編碼:grouping__id的取值是整數(shù)毛肋,很難知道對(duì)應(yīng)哪個(gè)維度組合方式,因此需要對(duì)grouping__id進(jìn)行自動(dòng)匹配處理:
case grouping__id
when conv('0111',2,10) then 'user_id'
when conv('0011',2,10) then 'user_id X gender'
when conv('0101',2,10) then 'user_id X channel'
when conv('0110',2,10) then 'user_id X city'
when conv('0001',2,10) then 'user_id X channel X gender'
when conv('0100',2,10) then 'user_id X channel X city'
when conv('0010',2,10) then 'user_id X city X gender'
end as groupid

group_id是根據(jù)取group by后面的維度字段是(=0)否(=1)加入聚合得到2進(jìn)制數(shù)后轉(zhuǎn)化成的10進(jìn)制數(shù)字诗眨。
conv('[判斷字段是否參與聚合的01序列]',2,10)函數(shù)可用來將2進(jìn)制轉(zhuǎn)換成10進(jìn)制數(shù)匠楚,這樣就可以建立grouping__id 和維度組合方式的映射了厂财。

更新后代碼如下:

select 
        user_id,
        if(grouping(gender)=0,gender,'ALL') as gender
        if(grouping(channel)=0,gender,'ALL') as channel
        if(grouping(city)=0,gender,'ALL') as city
        case grouping__id 
        when conv('0111',2,10) then 'user_id'
        when conv('0011',2,10) then 'user_id X gender'
        when conv('0101',2,10) then  'user_id X channel'
        when conv('0110',2,10) then 'user_id X city'
        when conv('0001',2,10) then 'user_id X channel X gender'
        when conv('0100',2,10) then 'user_id X channel X city'
        when conv('0010',2,10) then 'user_id X city X gender'
        end as groupid ----------聚合分組的編號(hào)璃饱,區(qū)分是哪種維度組合方式
        count(1) as pv
from T1
group by user_id,gender,channel,city,
grouping sets( ------------不同維度組合方式
(user_id),
(user_id,gender),
(user_id,channel),
(user_id,city),
(user_id,channel,gender),
(user_id,channel,city),
(user_id,city,gender),
)

得到新的表newT1:

newT1

跟newT2以u(píng)ser_id為關(guān)鍵字進(jìn)行左連接得到 newT:

newT

對(duì)newT按照gender,channel,city,groupid直接分組計(jì)數(shù)求和撩穿,

select gender,channel,city,group_id,
count(user_id) as dau,
sum(pv) as pv,
sum(order_cnt) as order_cnt,
sum(pay_sum) as pay_sum
from newT
group by gender,channel,city,groupid

得到:

group_id='user_id' 的表示整體業(yè)務(wù)數(shù)據(jù)冗锁;
group_id='user_id X city' 的表示分城市看業(yè)務(wù)數(shù)據(jù)嗤栓;
group_id='user_id X channel' 的表示分渠道看業(yè)務(wù)數(shù)據(jù);
…… ……
所有需要的維度組合切片都全了叨叙,省力擂错!清楚樱蛤!而且數(shù)據(jù)處理過程中沒有任何一處用distinct,計(jì)算高效爽醋!

如果我們嫌字段太多便脊、或者某些字段本身再業(yè)務(wù)上有包含關(guān)系時(shí),可以進(jìn)行合并:

select 
concat(coalesce(gender,'-'),'^',coalesce(channel,'-'),'^',coalesce(city,'-') ) as attr,
group_id,
count(user_id) as dau,
sum(pv) as pv,
sum(order_cnt) as order_cnt,
sum(pay_sum) as pay_sum
from newT
group by gender,channel,city,groupid

得到如下結(jié)果遂赠,之后進(jìn)行報(bào)表處理時(shí),可以根據(jù)分列符號(hào)“^”再進(jìn)行拆解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市送讲,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌监右,老刑警劉巖异希,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件称簿,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡父虑,警方通過查閱死者的電腦和手機(jī)授药,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門悔叽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人笨蚁,你說我怎么就攤上這事趟庄。” “怎么了勒极?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我匾七,道長(zhǎng)江兢,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任邑贴,我火速辦了婚禮拢驾,結(jié)果婚禮上改基,老公的妹妹穿的比我還像新娘。我一直安慰自己秕狰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布架忌。 她就那樣靜靜地躺著叹放,像睡著了一般。 火紅的嫁衣襯著肌膚如雪许昨。 梳的紋絲不亂的頭發(fā)上褥赊,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天拌喉,我揣著相機(jī)與錄音,去河邊找鬼尿背。 笑死,一個(gè)胖子當(dāng)著我的面吹牛荔烧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鹤竭,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼臀稚,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了吧寺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤幕帆,失蹤者是張志新(化名)和其女友劉穎蜓肆,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體仗扬,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡早芭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年退个,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了调炬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡刀荒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出棘钞,到底是詐尸還是另有隱情,我是刑警寧澤泼返,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布姨拥,位于F島的核電站渠鸽,受9級(jí)特大地震影響拱绑,放射性物質(zhì)發(fā)生泄漏丽蝎。R本人自食惡果不足惜屠阻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一额各、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧麻诀,春花似錦、人聲如沸蝇闭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽逻悠。三九已至韭脊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間沪羔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工撵渡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留死嗦,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓节腐,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親翼雀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345