NoSQL和MemeryCache的出現意味著傳統數據庫使用方式的變革嗎?
故事的起源
作為軟件工程專業出身的程序員,之前所接受的關于數據庫的教育都是基于關系型數據庫。對key-value based數據庫和document-based數據庫的都只是僅僅了解而已。
最近公司要做一個類似電商的系統,我來負責數據庫的設計和接口的提供。當然,我們使用的數據庫也是傳統的關系型數據庫SQL SERVER 2005,所以我也并沒有什么太大壓力。
但是當頭兒看到我設計的分類系統的數據庫表結果時意見很大,一翻溝通下來,我基本上就崩潰了。他的一翻話基本上推翻了我對數據庫的基本認識。
我的設計
要實現的分類是書籍分類體系,會至少有4層,總共大約有幾百個分類。我很自然地想到了鄰接表(Adjacency List)模式。然后設計了的表結構大體如下:
| 列名 | CategoryId | ParentId | Name |
| 描述 | 主鍵 | 父鍵 | 分類名 |
當然還有別的字段,與問題無關就不列了。
使用CTE遞歸的方式來獲取一個分類下的子分類樹。我考慮數據量并不大,所以性能上應該不成什么問題。
和頭兒的爭論
頭兒看到我的設計,直接說,不用這么麻煩了,不是有4層嗎?那就用4列,一列表示一級。
我說國圖法分類可能有7層以上。他說那就7列好了。
我說這樣數據量會有大量冗余,更新起來會很麻煩。
頭兒說,我之前做過很多樹型結構,一開始也和你一樣。但是做著做著就發現查詢繼承關系好麻煩啊,還不如直接用列存儲下來。
我說查詢繼承的代碼我已經寫好了,用CTE遞歸我并不覺得麻煩啊。
頭兒說,不要用遞歸,我們要為讀優化,而不是為寫優化。
這個我完全贊同,但是這個數據量并不大,但是我還是覺得這個做法很山寨。不符合數據庫的基本范式啊。
他說你知道范式,也要了解反范式。而且這個數據庫本身不要包含業務邏輯。你看現在出來的Redis和MemeryCached,存的都是名值對兒,沒有邏輯。邏輯是給業務處理的。什么是程序?程序就是算法加數據,數據和邏輯是要分開的。
我說從屬關系也是邏輯嗎?數據一致性也是邏輯嗎?
應該算啊,數據庫就是負責存儲數據的就夠了,你自己好好想想吧。
之后我還是堅持了自己的做法,頭兒勉強接受,但是要多加一個Path列,存儲這個分類的所有父節點。
這個我倒是同意加上,這屬于為特定查詢做的優化。
背景和現狀
我進這個項目的時候,這個項目的數據庫基本上已經建立完了。現在只是由于業務擴展需要新建數據庫表。剛進公司的時候,我就覺得這里的數據庫用法很詭異。
- 只有主鍵,沒有外鍵,也就是數據庫基本無從保證數據的一致性。
- 沒有使用ORM,需要在C#代碼中拼SQL來實現業務對象的讀取和寫入。
- 不允許使用存儲過程。這會引入過多的業務邏輯。
- 我也沒見過任何View,任何Trigger,任何自定義函數。
現在發現這些現狀與頭兒的想法其實是比較一致的。但是給人的感覺就是把SQL SERVER當作一個Key-Value的Database來實用。自然也就不需要那些SQL SERVER的功能。
但是我很奇怪,這樣的用法,為什么不直接用No SQL方案呢?不用也就算了,更讓我困惑的地方就在于,把No SQL的理念用在關系型數據庫上合適嗎?
我在這里也沒有看到過任何數據庫性能Profiling的代碼,對于數據庫性能的考量,基本上依賴數據庫服務器的CPU占用。(也許有測試人員做過我不知道而已吧。希望是這樣。)我們僅有的一名DBA也于年前離職了。
我的想法
我一直覺得數據庫設計是一項很重要很復雜的工作,需要了解業務需求,需要了解用戶的使用方式,需要能夠遇見到基本的可變性,需要對數據庫底層機制有深入的了解,等等等等。也聽過很多數據庫高手改寫一段SQL,就讓數據庫查詢變得飛快的故事。而且一切優化都應該有實際的數據來說話。也許我們頭兒在數據庫設計上有相當的功力,很有感覺。但是真的是這樣的嗎?我有我自己的想法,不知道是不是正確,但希望能和大家討論一下。
關于反范式和優化
反范式作為一種數據庫優化方案,我并覺得和其它的優化有什么根本上的不同。但是從優化的次序上來講,我個人覺得應該先在查詢的SQL上做足功夫,不行了再祭出反范式這個以空間換時間的殺手锏。不應該是從數據庫設計一開始就惦記著的事情,尤其是這還是在關系型數據庫上。當然,資深人員一眼就能感覺出哪里需要這么干當然更好。不過對于上面的情況,我個人覺得不需要。
關于數據庫不能有邏輯
這句話首先需要澄清什么屬于邏輯。由于這是我們頭的觀點,我也沒有跟他詳細討論過這個問題。我來講下我的理解吧。數據庫在設計之初就是為某個業務設計的,脫離了這個業務,這個設計本身也沒有了意義。所以我不認為邏輯從數據庫分離能讓數據庫可以被重用。但是數據庫包含了過多的邏輯會增加數據庫服務器的負擔,所以邏輯還是少放在數據庫為好。所以我基本同意這句話。
但是,我認為。數據關系(如外鍵)不屬于邏輯,數據完全性不屬于邏輯。而且這些就應該主是由數據庫來保證的。Web 服務器可以去檢查外鍵,檢查唯一約束,但是即使Web服務器不做這些,數據庫也應該做到這些。
最常見的就是數據插入和更新,如果涉及到多張表,那這些SQL寫入一個存儲過程以方便外界調用是很好的。同時,存儲過程或是View也可以把數據庫表設計與程序之間的依賴解除,在一些簡單的情況下實現不修改程序而對數據庫表結構進行變更。使用存儲過程也許會給數據遷移帶來麻煩,但是有誰沒事兒換數據庫呢?
我們目前這種在程序中拼SQL去操作數據庫的做法,我沒有看到什么優勢。純粹就是為了“數據庫不能有‘邏輯’”而拆分出來的東西。
關于數據庫系統的選用
我并沒有反對NoSQL或MemeryCached的理念,畢竟是用于處理不同的情況問題的。
像微博、社交、互動相關的系統。因為數據量大,訪問量大,數據結構相對簡單,用戶訪問具有時效性、地域性,使用這種NoSQL+MemeryCache方案是合理甚至是唯一的選擇。但是任何產品或是理念都有它適用的范圍,沒有銀彈。把 MemoryCache用在員工作業平臺或是項目管理系統上我覺得就相當的不靠譜。
但是電商系統似乎是處于兩者之間的一種模式,而且我們的業務量在可預見的未來也不會增長到淘寶的那個級別。我和頭的爭論也就源于這些理念上的差別,他像是在建立大統一理論,把各種先進思想整合在一起,而我又不確定這是創新呢?還是不倫不類的方式?于是有了題目上的疑問。而按頭的說法,也許這就是思考問題層次上的差別。
浙公網安備 33010602011771號