{eval=Array;=+count(Array);}
不知道開發(fā)的同學(xué)有沒有遇到過類似這樣的需求:
相同類型的數(shù)據(jù)在多個系統(tǒng)中,如果要得到全部的信息,就要連續(xù)調(diào)多個系統(tǒng)的接口;
業(yè)務(wù)復(fù)雜,一個需求需要關(guān)聯(lián)幾張表甚至幾十張表才能得到想要的結(jié)果;
系統(tǒng)做了分庫分表,但是需要統(tǒng)計所有的數(shù)據(jù)。
那么此類需求要如何滿足呢?我們選擇了“通過 ETL 提前進(jìn)行數(shù)據(jù)整合”的方案。
說到ETL,很多開發(fā)伙伴可能會有些陌生,更多的時候 ETL 是用在大數(shù)據(jù)、數(shù)據(jù)分析的相關(guān)崗位;我也是在近幾年的工作過程中才接觸到ETL的,現(xiàn)在的項目比較依賴 ETL,可以說是項目中重要的一部分。
ETL 是三個單詞的縮寫:
Extraction:抽取、提?。痪褪前褦?shù)據(jù)從數(shù)據(jù)庫里面取出來;
Transformation:轉(zhuǎn)換;包括但不限于:數(shù)據(jù)篩選校驗、數(shù)據(jù)關(guān)聯(lián)、數(shù)據(jù)內(nèi)容及結(jié)構(gòu)的修改、運算、統(tǒng)計等等;
Loading:加載;將處理后的數(shù)據(jù)保存到目標(biāo)數(shù)據(jù)庫。
從這三個單詞基本可以了解 ETL 的作用:將各個業(yè)務(wù)系統(tǒng)的數(shù)據(jù),通過抽取、清洗、轉(zhuǎn)換之后,將加工后的數(shù)據(jù)落地到數(shù)據(jù)庫中(數(shù)據(jù)倉庫);在這個過程中,ETL 可以將分散、零亂、標(biāo)準(zhǔn)不統(tǒng)一的數(shù)據(jù)整合到一起。
我接觸過的項目,使用ETL工具的場景有這個幾種:
1. 報表、BI系統(tǒng):
在公司建設(shè)的初期,業(yè)務(wù)比較少,系統(tǒng)也比較少,一臺數(shù)據(jù)庫就搞定了;隨著公司業(yè)務(wù)的增加,業(yè)務(wù)系統(tǒng)被拆成很多系統(tǒng);隨著數(shù)據(jù)量的繼續(xù)增加,單個系統(tǒng)的數(shù)據(jù)增加到一定程度的時候,也做了分庫分表;
這時候領(lǐng)導(dǎo)、業(yè)務(wù)人員在用數(shù)據(jù)做分析的時候,數(shù)據(jù)來源可能是多個系統(tǒng)的多張表,這時候企圖通過一個復(fù)雜的 SQL 跑出來結(jié)果就很困難了;通常公司會建立一個數(shù)據(jù)倉庫,通過ETL工具把數(shù)據(jù)抽取到數(shù)據(jù)倉庫中,再做數(shù)據(jù)的擬合和展示。
2. 跨系統(tǒng)的數(shù)據(jù)加工或查詢:
我們現(xiàn)在所在公司,業(yè)務(wù)系統(tǒng)有幾百個,由于業(yè)務(wù)流程比較復(fù)雜,前端系統(tǒng)在做業(yè)務(wù)操作的時候,在正式提交交易之前,有很多業(yè)務(wù)校驗;
比如要查詢客戶在 X 系統(tǒng)的交易歷史,在 Y 系統(tǒng)的交易歷史,在 Z 系統(tǒng)的交易歷史;那么就需要分別調(diào)用 X、Y、Z 系統(tǒng)的接口,這個對前端系統(tǒng)很不友好,那么通常的解決方案是什么?
A 方案:做一個中間服務(wù),中間服務(wù)去調(diào)用 X、Y、Z 系統(tǒng)的接口,客戶端直接調(diào)用這個中間服務(wù);這種方案只是把前端要做的事情,轉(zhuǎn)移到了中間服務(wù);
B 方案:整合 X、Y、Z 三個系統(tǒng),建服務(wù)中臺;這種方法很好,但是極為難,對于很多公司來說,別說把 X、Y、Z 三個系統(tǒng)整合成一個中臺系統(tǒng),就是其中一個系統(tǒng)本身進(jìn)行重構(gòu),都是非常困難的;
C 方案:把 X、Y、Z 三個系統(tǒng)中需要的數(shù)據(jù),通過 ETL 抽取加工到一個數(shù)據(jù)倉庫中,對外提供服務(wù);這個系統(tǒng)最大的好處是在不改造 X、Y、Z 三個系統(tǒng)的前提下,又可以實現(xiàn)跨系統(tǒng)的查詢。
我們在 C 方案的基礎(chǔ)上又往前做了一步,就是將落地后的數(shù)據(jù)又做了一次加工,將需要跨表關(guān)聯(lián)的數(shù)據(jù),提前關(guān)聯(lián)好存入 MongoDB 中,對外提供查詢服務(wù);這樣可以將多表關(guān)聯(lián)查詢,變成了單表查詢。
接上文中第二個例子中的 C 方案,有些同學(xué)可能會有個疑問:數(shù)據(jù)抽取,需要抽取哪些數(shù)據(jù)呢?為什么不讓這些系統(tǒng)把數(shù)據(jù)吐出來呢?
答案也簡單,“有的時候,數(shù)據(jù)不一定能吐出來”。
MySQL 數(shù)據(jù)庫往外吐數(shù)據(jù)有比較成熟的中間件,比如 Canal,它可以通過監(jiān)聽 Mysql 的 binlog 日志來獲取數(shù)據(jù),binlog 設(shè)置為 row 模式,能夠獲取到每一條新增、刪除、修改的日志,同時還能獲取到修改前后的數(shù)據(jù);
其他商用數(shù)據(jù)庫,比如 Oracle、DB2 等,我也查閱過相關(guān)的資料,也是有觸發(fā)器機制,可以當(dāng)數(shù)據(jù)發(fā)生變化的時候通知出來,比如調(diào)用一段程序,將數(shù)據(jù)發(fā)送到消息隊列中,再由其他程序監(jiān)聽消息隊列做后續(xù)處理。
不管什么類型的數(shù)據(jù)庫,這種“吐數(shù)據(jù)”的方案,對于基礎(chǔ)設(shè)施的要求都比較高,并且對原有系統(tǒng)有一定的侵入性;所以我們采用了對原有系統(tǒng)侵入性更小的方案:主動抽數(shù)據(jù)。
1. 優(yōu)點
侵入性較低,數(shù)據(jù)源系統(tǒng)只需要開通數(shù)據(jù)庫的訪問權(quán)限即可,為保證數(shù)據(jù)抽取對業(yè)務(wù)的影響,通常是訪問源系統(tǒng)的備庫,并且多帶帶設(shè)置一個只讀權(quán)限的數(shù)據(jù)庫用戶;
支持不同類型數(shù)據(jù)源的數(shù)據(jù)抽取,比如源庫有 Mysql、DB2、Oracle,通過 ETL 也可以輕松搞定;
數(shù)據(jù)整合,將不同業(yè)務(wù)系統(tǒng)的相同數(shù)據(jù)整合在一起,比如有些系統(tǒng) M/F 表示男女,有些系統(tǒng) 1/0 表示男女,ETL 在抽取加工后轉(zhuǎn)換成統(tǒng)一的編碼;
2. 缺點
比較致命的一個缺點,就是數(shù)據(jù)抽取和加工有一定的延遲,需要根據(jù)業(yè)務(wù)場景進(jìn)行評估,是否接受這個延遲;
可能會受到源庫表結(jié)構(gòu)變化的影響;
如果源庫中的表沒有時間戳,或者時間戳不準(zhǔn)確,那么增量抽取就變得很困難;
需要招聘 ETL 開發(fā)崗,從我目前的經(jīng)驗看,不是特別好招。
關(guān)聯(lián)表都是有復(fù)雜度的,一般不超過三個,不然后期維護(hù)很難看懂邏輯。
可以試試拆分sql,在代碼里多次查詢再主鍵關(guān)聯(lián),最后合并數(shù)據(jù)。
如果很慢的話可以調(diào)查一下是不是sql有笛卡爾積現(xiàn)象,沒有加主鍵或缺少索引。一般查詢慢都是缺少索引,或者索引沒用上。
業(yè)務(wù)邏輯上要加分頁,不要一次查太大量的數(shù)據(jù)。
我記得ucloud巴巴開發(fā)手冊規(guī)定了一次join不能超過3張表,為什么會有這種規(guī)范,顯然是在某種業(yè)務(wù)場景下要多做數(shù)據(jù)冗余,方便查詢,性能更高,帶來的缺點就是更新可能會更復(fù)雜,而三范式結(jié)構(gòu)更清晰,數(shù)據(jù)量大性能必然會下降,所以要有取舍,設(shè)計表結(jié)構(gòu)時,要三范式和反范式結(jié)合而用,否則那些頭部互聯(lián)網(wǎng)公司哪個業(yè)務(wù)不復(fù)雜,雖然可以用es和hbase,但如果都是join十多張表那都不用玩了,我所在的物流公司,業(yè)務(wù)也是非常復(fù)雜,剛來公司的時候就發(fā)現(xiàn),前期表結(jié)構(gòu)規(guī)劃不合理,也沒有采用es等中間件做數(shù)據(jù)聚合,一個簡單的例子,掃條碼碼入庫,全鏈路壓測吞吐連10都不到,走讀下代碼,一個獲取訂單信息的查詢10張表,整個流程中還有多個系統(tǒng)的同步調(diào)用,基本上隨便都是七八張表以上,本身也是個新項目,跑了一年左右了,量沒有特別大,但是業(yè)務(wù)復(fù)雜的牽一發(fā)動全身,這種系統(tǒng)就別想重構(gòu)了,大公司你懂的,所以首先就是各種sql優(yōu)化,能提高多少是多少,待了半年左右就走了,再待下去量上來,系統(tǒng)扛不住,天天就得加班挨叼了。所以說一個好的設(shè)計,至少可以讓你系統(tǒng)能抗的住未來一兩年的業(yè)務(wù)的增長。
建議一:
你應(yīng)該找需求人員,了解清楚需求,看看能否減少關(guān)聯(lián)表
建議二:
關(guān)聯(lián)十幾張表,很大概率,你這個是報表展示的需求,可以用etl工具抽取必要的字段,然后預(yù)處理一些簡單匯總,這樣能少掃描記錄,提升查詢速度
建議三:
建議使用適合做數(shù)據(jù)分析的平臺,如Hadoop,hbase,tispark
這種查詢大概率不是要求查實時數(shù)據(jù),就是統(tǒng)計報表用的,那你為什么非得要從原數(shù)據(jù)結(jié)構(gòu)上做這種復(fù)雜查詢?為什么不能去做etl之后再優(yōu)化數(shù)據(jù)結(jié)構(gòu)?一條路走到黑等著的就肯定是死胡同。如果是要求查詢實時數(shù)據(jù),那就用業(yè)務(wù)代碼去簡化查詢邏輯,用業(yè)務(wù)代碼做數(shù)據(jù)計算和拼接,把變動頻率低的數(shù)據(jù)做緩存,把讀庫做分庫分表,辦法多的是,你除了寫sql就不會別的了?
一次查詢需要關(guān)聯(lián)十幾張表,是不是報表查詢的維度太多了?
關(guān)聯(lián)子查詢的執(zhí)行邏輯和通常的SELECT語句的執(zhí)行邏輯完成不一樣。這就是SQL關(guān)聯(lián)子查詢難以理解的原因。
在關(guān)聯(lián)查詢時要注意:where子句中一定要包含表之間的連接條件,如 line.lid=track.lid,否則查詢結(jié)果會完全超乎我們的想象,造成不必要的麻煩。
我看了一下回答,感覺很少有人能說到點子上。
先說說需求吧,一次十幾張表,這是什么需求?是不是理解錯誤,還是說這需求必須要做?建議和業(yè)務(wù)溝通溝通。
如果說,需求真的不能改,那就用視圖吧。
使用視圖時,會運行視圖里的sql查詢語句創(chuàng)建出一張臨時表。
可以將頻繁使用的select語句保存成視圖,這樣就不用每次都重新書寫了。
使用視圖需要注意什么?
(1)避免在視圖的基礎(chǔ)上再次創(chuàng)建視圖,因為這樣多重視圖會降低sql的性能和效率;
(2)不能往視圖里插入數(shù)據(jù),不然會報錯。
最后,其實做報表真的不復(fù)雜,你要是用好報表工具FineReport,寫sql那真的是很輕松,回復(fù)“報表”就能有了。
互聯(lián)網(wǎng)時代倡導(dǎo)非關(guān)系型數(shù)據(jù)庫,首先保證單表查詢速度到極致,然后程序設(shè)計數(shù)據(jù)關(guān)聯(lián)最終算出結(jié)果,這才是解決之道。強烈依賴關(guān)系型數(shù)據(jù)庫是一種偷懶的方式,當(dāng)今海量數(shù)據(jù)時代,關(guān)系型數(shù)據(jù)庫用武之地也就剩下對速度要求不高的后臺統(tǒng)計和用戶量低的場景。
良好的設(shè)計數(shù)據(jù)庫,這種情況往往是糟糕的數(shù)據(jù)庫設(shè)計的問題。找個對數(shù)據(jù)庫有深入了解大牛,幫忙規(guī)劃一下,要不了幾天,但很解決問題。
本人寫sql也有好多年了,但一次查詢關(guān)聯(lián)10幾張表的情況還沒碰到過。但是這種情況還是有優(yōu)化的方法的。
首先查詢關(guān)聯(lián)10幾張表,不管是內(nèi)聯(lián)還是外聯(lián),不管怎么優(yōu)化你的sql語句,比如建索引,指定返回列,where加限制條件,我相信你的結(jié)果還是會很慢的。 因為這已經(jīng)不是技術(shù)層面可以去優(yōu)化的,建議還是從業(yè)務(wù)層面去優(yōu)化。
不管多復(fù)雜的業(yè)務(wù)我們都可以去分解它,將它分解成一段段的子結(jié)果集,可以將它們作為臨時表或者結(jié)果表存儲起來,在最終的查詢時可以從分解的子集去查詢,這樣就避免了多表關(guān)聯(lián),而且這樣代碼可讀性,可維護(hù)性更好。也符合我們設(shè)計代碼的基本原則。
0
回答0
回答0
回答0
回答0
回答0
回答0
回答0
回答0
回答0
回答