當前位置:
首頁 > 最新 > 為什麼要學資料庫原理?

為什麼要學資料庫原理?

只會寫代碼的是碼農;學好資料庫,基本能混口飯吃;在此基礎上再學好操作系統和計算機網路,就能當一個不錯的程序員。如果能再把離散數學、數字電路、體系結構、數據結構/演算法、編譯原理學通透,再加上豐富的實踐經驗與領域特定知識,就能算是一個優秀的工程師了。計算機其實就是存儲/IO/CPU三大件; 而計算說穿了就是兩個東西:數據與演算法(狀態與轉移函數)。常見的軟體應用,除了各種模擬模擬、模型訓練、視頻遊戲這些屬於計算密集型應用外,絕大多數都屬於數據密集型應用。從最抽象的意義上講,這些應用乾的事兒就是把數據拿進來,存進資料庫,需要的時候再拿出來。抽象是應對複雜度的最強武器。操作系統提供了對存儲的基本抽象:內存定址空間與磁碟邏輯塊號。文件系統在此基礎上提供了文件名到地址空間的KV存儲抽象。而資料庫則在其基礎上提供了對應用通用存儲需求的高級抽象。互聯網應用大多屬於數據密集型應用,對於真實世界的數據密集型應用而言,除非你準備從基礎組件的輪子造起,不然根本沒那麼多機會去擺弄花哨的數據結構和演算法。甚至寫代碼的本事可能也沒那麼重要:可能只會有那麼一兩個Ad Hoc演算法需要在應用層實現,大部分需求都有現成的輪子可以使用,主要的創造性工作往往在數據模型與數據流設計上。實際生產中,數據表就是數據結構,索引與查詢就是演算法。而應用代碼往往扮演的是膠水的角色,處理IO與業務邏輯,其他大部分工作都是在數據系統之間搬運數據。在最寬泛的意義上,有狀態的地方就有資料庫。它無所不在,網站的背後、應用的內部,單機軟體,區塊鏈里,甚至在離資料庫最遠的Web瀏覽器中,也逐漸出現了其雛形:各類狀態管理框架與本地存儲。「資料庫」可以簡單地只是內存中的哈希表/磁碟上的日誌,也可以複雜到由多種數據系統集成而來。關係型資料庫只是數據系統的冰山一角(或者說冰山之巔),實際上存在著各種各樣的數據系統組件:

資料庫:存儲數據,以便自己或其他應用程序之後能再次找到(PostgreSQL,MySQL,Oracle)

緩存:記住開銷昂貴操作的結果,加快讀取速度(Redis,Memcached)

搜索索引:允許用戶按關鍵字搜索數據,或以各種方式對數據進行過濾(ElasticSearch)

流處理:向其他進程發送消息,進行非同步處理(Kafka,Flink,Storm)

批處理:定期處理累積的大批量數據(Hadoop)

架構師最重要的能力之一,就是了解這些組件的性能特點與應用場景,能夠靈活地權衡取捨、集成拼接這些數據系統。絕大多數工程師都不會去從零開始編寫存儲引擎,因為在開發應用時,資料庫已經是足夠完美的工具了。關係型資料庫則是目前所有數據系統中使用最廣泛的組件,可以說是程序員吃飯的主要傢伙,重要性不言而喻。

圖:架構演化:一種分拆方法

對玩具應用而言,使用內存變數與文件來保存狀態也許已經綽綽有餘了。但隨著系統的增長,我們會遇到越來越多的挑戰:軟硬體故障把數據搞成一團漿糊(可靠性);狀態太多而內存太小放不下(可伸縮性);並發訪問控制導致代碼複雜度發生爆炸(可維護性),諸如此類。這些問題相當棘手,卻又相當普遍,資料庫就是用來解決這些問題的。分拆是架構演化的重要方法論,資料庫將狀態管理的職能從應用程序中分拆出來,即所謂的「狀態與計算相分離」。資料庫將程序員從重複造輪子的泥潭中解救出來,極大地解放了生產力。每個系統都服務於一個目的,解決一類問題。問題比方法更重要。但現實很遺憾,以大多數學生,甚至相當一部分公司能接觸到的現實問題而言,拿幾個文件甚至在內存里放著估計都能應付大多數場景了(需求簡單到低級抽象就可以Handle)。沒什麼機會接觸到資料庫真正要解決的問題,也就難有真正使用與學習資料庫的驅動力,更別提資料庫原理了。所以我也理解當前這種填鴨教學現狀的苦衷:工作之後很難有這麼大把的完整時間來學習原理了,所以老師只好先使勁灌輸,多少讓學生對這些知識有個印象。等學生參加工作後真正遇到這些問題,也許會想起大學好像還學了個叫資料庫的東西,這些知識就會開始反芻。資料庫,尤其是關係型資料庫,非常重要。那為什麼要學習其原理呢?對優秀的工程師來說,只會用資料庫是遠遠不夠的。學習原理對於當CRUD BOY搬磚收益並不大,但當通用組件真的無解需要自己擼起袖子上時,沒有金坷垃怎麼種莊稼?設計系統時,理解原理能讓你以最少的複雜度代價寫出更可靠高效的代碼;遇到疑難雜症需要排查時,理解原理能帶來精準的直覺與深刻的洞察。資料庫是一個博大精深的領域,存儲I/O計算無所不包。其主要原理也可以粗略分為幾個部分:數據模型設計原理(應用)、存儲引擎原理(基礎)、索引與查詢優化器的原理(性能)、事務與並發控制的原理(正確性)、故障恢復與複製系統的原理(可靠性)。所有的原理都有其存在意義:為了解決實際問題。例如數據模型設計中的範式理論,就是為了解決數據冗餘這一問題而提出的,它是為了把事情做漂亮(可維護)。它是模型設計中一個很重要的設計權衡:通常而言,冗餘少則複雜度小/可維護性強,冗餘高則性能好。具體來說,冗餘欄位能加快特定類型的讀取(通過消除連接),但在寫入時就需要做更多的工作:維護多對象副本間的一致性,避免多對象事務並發執行時發生踩踏。這就需要仔細權衡利弊,選擇合適的規範化等級。數據模型設計,就是生產中的數據結構設計。不了解這些原理,就難以提取良好的抽象,其他工作也就無從談起。而關係代數與索引的原理,則在查詢優化中扮演重要的角色,它是為了把事情做得快(性能,可擴展)。當數據量越來越大,SQL寫的越來越複雜時,它的意義就會體現出來:怎樣寫出等價但是更高效的查詢?當查詢優化器沒那麼智能時,就需要人來干這件事。這種優化往往有四兩撥千斤的效果,比如一個需要幾秒的KNN查詢,如果知道R樹索引的原理,就可以通過改寫查詢,創建GIST索引優化到1毫秒內,千倍的性能提升。不了解索引與查詢設計原理,就難以充分發揮資料庫的性能。

圖:估算表膨脹率的複雜SQL一例,能在50ms內完成

事務與並發控制的原理,是為了把事情做正確。事務是數據處理領域最偉大的抽象之一,它提供了很多有用的保證(ACID),但這些保證到底意味著什麼?事務的原子性讓你在提交前能隨時中止事務並丟棄所有寫入,相應地,事務的持久性則承諾一旦事務成功提交,即使發生硬體故障或資料庫崩潰,寫入的任何數據也不會丟失。這讓錯誤處理變得無比簡單,所有可能的結果被歸結為兩種情況:要麼成功完事,要麼失敗了事(或重試)。有了後悔葯,程序員不用再擔心半路翻車會留下慘不忍睹的車禍現場了。另一方面,事務的隔離性則保證同時執行的事務無法相互影響(在可序列化隔離等級下)。更進一步,資料庫提供了不同的隔離等級保證,以供程序員在性能與正確性之間進行權衡。編寫並發程序並不容易,在幾萬TPS的負載下,各種極低概率,匪夷所思的問題都會出現:事務之間相互踩踏,丟失更新,幻讀與寫入偏差,慢查詢拖慢快查詢導致連接堆積,單表資料庫並發增大後的性能急劇惡化,比如我遇到的一個最靈異的例子是:快慢查詢總量都減少,但因相對比例變化導致資料庫被壓垮。這些問題,在低負載的情況下會潛伏著,隨著規模量級增長突然跳出來,給你一個大大的驚喜。現實中真正可能出現的各類異常,也絕非SQL標準中簡單的幾種異常能說清的。不理解事務的原理,意味著應用的正確性與數據的完整性可能遭受不必要的損失。

圖:隔離等級與一致性

故障恢復與複製的原理,可能對於普通程序員沒有那麼重要,但架構師與DBA必須清楚。高可用是很多應用的追求目標,但什麼是高可用,高可用怎麼保證?讀寫分離?快慢分離?異地多活?x地x中心?說穿了底下的核心技術其實就是複製(Replication)(或再加上自動故障切換(Failover))。這裡有無窮無盡的坑:複製延遲帶來的各種靈異現象,網路分區與腦裂,存疑事務,諸如此類。不理解複製的原理,高可用就無從談起。對於一些程序員而言,可能資料庫就是「增刪改查」,包一包介面,原理似乎屬於「屠龍之技」。如果止步於此,那原理確實沒什麼好學的,但有志者應當打破砂鍋問到底的精神。私認為只了解自己本領域知識是不夠的,只有把當前領域賴以建立的上層領域摸清楚,才能稱為專家。在資料庫面前,後端也是前端;對於程序員的知識棧而言,資料庫是一個合適的棧底。上面講了WHY,下面就說一下HOW資料庫教學的一個矛盾是:如果連資料庫都不會用,那學資料庫原理有個卵用呢?學資料庫的原則是學以致用。只有實踐,才能帶來對問題的深刻理解;只有先知其然,才有條件去知其所以然。教材可以先草草的過一遍,然後直接去看資料庫文檔,上手去把資料庫用起來,做個東西出來。通過實踐掌握資料庫的使用,再去學習原理就會事半功倍(以及充滿動力)。對於學習而言,有條件去實習當然最好,沒有條件那最好的辦法就是自己創造場景,自己挖掘需求。比如,從解決個人需求開始:管理個人密碼,體重跟蹤,記賬,做個小網站、在線聊天App,實用微信小程序。當它演化的越來越複雜,開始有多個用戶,出現各種蛋疼問題之後,你就會開始意識到事務的意義。再比如,結合爬蟲,抓一些房價、股價、地理、社交網路的數據存在資料庫里,做一些挖掘與分析。當你積累的數據越來越多,分析查詢越來越複雜;SQL長得沒法讀,跑起來慢出豬叫,這時候關係代數的理論就能指導你進一步進行優化。當你意識到這些設計都是為了解決現實生產中的問題,並親自遇到過這些問題之後,再去學習原理,才能相互印證,並知其所以然。當你發現查詢時間隨數據增長而指數增長時;當你遇到成千上萬的用戶同時讀寫為並發控制焦頭爛額時;當你碰上軟硬體故障把數據攪得稀巴爛時;當你發現數據冗餘讓代碼複雜度快速爆炸時;你就會發現這些設計存在的意義。教材、書籍、文檔、視頻、郵件組、博客都是很好的學習資源。教材的話華章的黑皮系列教材都還不錯,《資料庫系統概念》這本就挺好的。但我推薦先看看這本書:《設計數據密集型應用》,寫的非常好,我覺得不錯就義務翻譯了一下。紙上得來終覺淺,絕知此事要躬行。寫了這麼多,不帶點「私貨」也不合適哈?實踐方能出真知,新手上路選哪家?我個人推薦PostgreSQL,如果能再選一樣就加個Redis。對開發而言,這是相當實用的組合。PostgreSQL號稱世界上最先進的開源關係型資料庫,源代碼寫的非常漂亮,有很多值得學習的地方。很多國外的資料庫課程與教科書都使用PostgreSQL作為教學樣例。PostgreSQL在現實世界中也表現不俗,在我們的實踐中,在250WTPS與200TB數據的量級下,單一PostgreSQL選型依然能穩如狗地支撐業務。而且其功能豐富到不可思議,能在很可觀的規模內做到一專多長,除了本職的OLTP,Pg還在相當長的時間裡兼任了緩存,OLAP,批處理,甚至消息隊列的角色。當然如「架構演進」一圖所示,神龜雖壽,猶有竟時。最終這些兼職功能還是要逐漸分拆出去由專用組件負責,但那已經是近千萬日活時的事了。所以,關係型資料庫雖然強大,卻絕非數據處理的終章。資料庫的世界非常精彩,儘可能地去嘗試各種各樣的組件吧~。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 非法加馮 的精彩文章:

TAG:非法加馮 |