第32期:JOIN簡化 - 意義總結
我們重新審視和定義了等值JOIN運算,并簡化了語法。一個直接的效果顯然是讓語句書寫和理解更容易。外鍵屬性化、同維表等同化和主子表一體化方案直接消除了顯式的關聯運算,也更符合自然思維;維度對齊則可讓程序員不再關心表間關系,降低語句的復雜度。
一
簡化JOIN的好處不僅在于此,還能夠降低出錯率。
我們知道,SQL允許用WHERE來寫JOIN運算的過濾條件(回到原始的笛卡爾積式的定義),很多程序員也習慣于這么寫。當JOIN表只有兩三個的時候,那問題還不大,但如果JOIN表有七八個甚至十幾個的時候,漏寫一個JOIN條件是很有可能的。而漏寫了JOIN條件意味著將發生多對多的完全叉乘,而這個SQL卻可以正常執行,一方面計算結果會出錯(回憶一下以前說過的,發生多對多JOIN時,大概率是語句寫錯了),另一方面,如果漏寫條件的表很大,笛卡爾積的規模將是平方級的,這極有可能把數據庫直接“跑死”!
采用簡化后的JOIN語法,就不可能發生漏寫JOIN條件的情況了。因為對JOIN的理解不再是以笛卡爾積為基礎,而且設計這些語法時已經假定了多對多關聯沒有業務意義,這個規則下寫不出完全叉乘的運算。
對于多個子表分組后與主表對齊的運算,在SQL中要寫成多個子查詢的形式。但如果只有一個子表時,可以先JOIN再GROUP,這時不需要子查詢。有些程序員沒有仔細分析,會把這種寫法推廣到多個子表的情況,也先JOIN再GROUP,可以避免使用子查詢,但計算結果是錯誤的。
使用維度對齊的寫法就不容易發生這種錯誤了,無論多少個子表,都不需要子查詢,一個子表和多個子表的寫法完全相同。
二
重新看待JOIN運算,最關鍵的作用在于實現關聯查詢。
當前敏捷BI產品非常火熱,各家產品都宣稱能夠讓業務人員拖拖拽拽就完成想要的查詢報表。但實際應用效果會遠不如人意,業務人員仍然要經常求助于IT部門。造成這個現象的主要原因在于大多數業務查詢都是有過程的計算,不大可能由直接不會編程的業務人員獨立完成。但是,仍有約三成左右的業務查詢并不涉及多步過程,而業務人員仍然無法完成。
這是由于大多數敏捷BI產品(以及多年前流行的OLAP產品)都不支持關聯查詢。這些產品的工作模式是先由技術人員構建模型,再由業務人員基于模型在界面上進行查詢。而所謂建模,其實就是生成一個邏輯上或物理上的單表,業務人員只能在這個單表的范圍內查詢分析,無論界面做得多么流暢炫酷,在數據獲取層面都不可能超越這個事先構建好的單表范圍。用戶的查詢需求一旦超出了這個單表,需要關聯到其它表中數據時,就要由技術人員再次建模。建模實際上要針對不同的關聯需求分別實現,我們稱之為按需建模。但實際上,有意義的查詢絕大多數都有關聯需求,技術人員也不可能事先預測所有的關聯,就算預測了也不可能把所有的關聯可能性都事先做好。結果是,要么建模動作頻頻發生,要么業務用戶沒法使用,無論如何,這些敏捷BI產品都會失去敏捷性。
為什么這些BI產品不能支持關聯查詢呢?因為并不容易,其根源就在于SQL對JOIN的定義過于簡單,導致表間關聯過于繁瑣,超出業務人員的理解能力,直接把數據結構暴露出來由業務用戶自己完成JOIN運算是不可能的。有些BI產品的界面協助下有一些改善,在事先定義好維度后,可以讓業務人員正確處理沒有形成環的關聯關系以及同表內沒有相同維度的關聯情況,全自關聯(形成環)和同表多同維字段仍需要再建模去解決,這些細節我們也留到講述維度概念時來再詳細討論。
但是,如果改變了對JOIN運算的看法,關聯查詢可以從根本上得到解決。回憶前面講過的三種JOIN及其簡化手段,我們事實上把這幾種情況的多表關聯都看成了單表查詢,而業務用戶對于單表查詢并沒有理解障礙。無非就是表的屬性(字段)稍復雜了一些:可能有子屬性(外鍵字段指向的外鍵表),子屬性可能還有子屬性(多層的外鍵表),有些字段取值是集合而非單值(子表看作為主表的字段)。發生自關聯也不會影響理解(前面的例子就是個自關聯),同表有相同維度也不礙事(各自有各自的子屬性)。在這種關聯機制下,技術人員只要一次性把數據結構(元數據)定義好,在合適的界面下,由業務人員可以自己實現JOIN運算,不再需要技術人員的參與。數據建模只發生于數據結構改變的時刻,而不需要為新的關聯需求建模,這也就是非按需建模。