標籤:

寫一個資料庫最難的地方在哪?最精華的地方在哪?分幾步?


前幾天還跟人討論過這個問題,我認為有三個難點,從前到後分別是,SQL優化器、事務引擎、容災和恢復。

cs基礎紮實、底層開發經驗比較豐富的人,非資料庫專業出身,搞定後兩個是沒問題的,而搞好優化器挑戰還是很大的。

單機資料庫優化器的理論和工程實踐比較成熟,而事務引擎、容災恢復的技術隨硬體發展,變化很快,資料庫專業出身的人也不一定能搞好。


  1. 測試,如何保證寫出來的資料庫是對的
  2. 如何保證架構簡單以及可擴展
  3. 如果是一個分散式資料庫的話,要考慮從上到下各個組件之間如何協調、如何構架一個穩定的系統,總有一些場景是你想不到的


資料庫可以簡單的分為查詢引擎和存儲引擎。

查詢引擎是暴露給用戶的編程介面。對於關係式資料庫就是SQL語句的解析、優化和執行。但需要注意的是SQL是具備定製複雜查詢的能力的。而且因為關係代數的完備性,使得大部分情況下,用戶只需要寫SQL語句就能完成常見的資料庫操作。需要用戶編程實現更加複雜的操作並不多見。

而對於非關係式資料庫則相反,資料庫本身通常提供的介面基本不具備編程能力,或只有簡單的數據結構支持。很多操作都需要用戶自己靠編程來解決。比如一個常見的聯表查詢在SQL里是系統平常的,數據約束等也是如此。而對於非關係式資料庫,這些只能靠用戶自己大量的代碼來實現。所以想嘗試自己實現個資料庫的,可以自己選擇這個折衷,把對資料庫的複雜操作是交給用戶還是資料庫的設計者。

查詢優化是個大坑,坑之大不是三言兩語能解釋清楚的,甚至不是一兩本書能解釋的。我可以給出個postgresql里的例子,是6年前我優化過。第一句是優化前,第二句是優化後:

SELECT * FROM post WHERE NOW()-dt_create&<86400;

SELECT * FROM post WHERE dt_create&>1234567890;

這裡的dt_create欄位是帶有索引的,但是在第一句的比較左側因為與NOW()函數做了計算,所以就沒法利用索引了,而且因為NOW()函數在每個記錄上都要重新求值,所以這個語句的執行是很慢的。

優化過程就是第一把NOW()函數去掉,改為從外部傳入的當前時間戳數字,並且在外部做好與86400的減法。這樣dt_create成了不等式一側的唯一欄位,就能利用好索引了。這樣個優化使得速度提高了近20倍,功能卻沒變。

存儲引擎的玩法也有很多,一些重要功能就是要在存儲引擎里實現的,包括數據恢復、並發控制、索引等。

數據恢復的兩大方法是轉儲和redolog。轉儲是把某個時間點整個資料庫鏡像保存到硬碟,缺點是時間較長,所以該操作啟動後到資料庫故障停止的時間裡數據完整性是沒法確保的。redolog則是把對資料庫的每個修改操作都記一條日誌,記完了日誌才去更新內存鏡像,記錄快恢復慢。現代資料庫更常見的是結合兩者,平時任何更新都記錄redolog,每隔一段時間把之前的更新做一個轉儲。這樣可以兼顧數據完整性和故障恢復速度。

並發控制則是為了防止並發衝突的,對不同級別資料庫玩法也有很大區別。粗糙一些的,每次更新操作都把整個資料庫給鎖了,更新完成再釋放。這也是常見開源資料庫的實現。高級一點的玩法能實現表級或行級鎖,對於更新沒有影響到的表就不會被鎖住。鎖的粒度更細使得更新對資料庫的影響更小,同時設計複雜度也會增加很多。

題主如果只是希望學習資料庫,自己設計個資料庫來練手,則盡量降低第一個例子的門檻更有意義。對此我的建議是,實現memcache協議,做key-value資料庫,底層引擎用一個全局鎖的數據文件。稍微有心一點的可以在存儲引擎上深入一些,比如學習一下數據結構課程里內存動態分配的章節,來做動態存儲管理。之後再加上redolog支持,來實現故障恢復。那麼這樣一個業餘項目就變得有趣很多了。

補充一下三種常見資料庫的通信協議文檔:

memcache通信協議

MySQL的通信協議

PostgreSQL通信協議


回答這個問題之前,首先確定這個話題僅限於disk-based OLTP系統的core engine部分好了,因為一旦超出概念,上面回答的就都太片面了。

首先,大家都回答的特別好。

SQL Optimizer,Transaction Manager,Index,Cache(Buffer Manager),容災其實都挺難的。

我統計一下,Cache(Buffer Manager)這部分有人覺得難,但是贊同這個的不多。Database裡面Buffer Manager是個比較特殊的存在,因為很多組件都涉及到它,作用也很大,但是真正的資料庫developement team裡面懂這個的人已經非常之少了。Sybase ASE裡面懂這個的人現在只有一個,SqlServer,Oracle估計也多不到哪裡去,一把手數過來吧。這個就導致了你想把一個Disk-based的OLTP改一改,改成in-memory的系統時,真正懂這部分代碼的developer少的可憐,拿什麼去改?

SQL Optimizer獲得贊同最多,我也比較贊同這個比較困難。因為SQL前端或者後端做點改動,Optimizer都得做相應修改,而Optimizer的改動又是對系統理解,架構理解,和設計權衡都有要求的部分,承上啟下,但是懂的人還是有一定數量的。

Transaction這部分獲的贊同也比較多。說實話,transaction manager真心是一個OLTP的靈魂部分,但是transaction在disk-based系統里,或者in-memory系統里,它的實現是個很不一樣的。但是這部分知識呢又一定程度上可以從其他系統裡面借鑒,MVCC啦什麼的,二階段提交啦,很多大數據系統啦什麼的都可以參考的。

Index這部分呢,我覺得DBA最最應該投票給這個。因為優化啦什麼的首先就應該考慮index的合理應用,但是index在各個系統里實現的很不一樣,而且裡面很多概念都是各個開發商自己創造出來的,它的複雜來源於各個OLTP系統架構啦,設計啦很多的不同,所以應用的好,其實很不容易了。與此同時,寫一手好的SQL其實挺難的,初級sql看看書就會了,一手performance不錯的sql是要有很多的理論和架構知識的哦。

當然,locklatch,這部分也有一定票數。lock manager實現和transaction manager是共同來實現concurrency control的,高效的鎖機制可以很大程度上提高並發率了。

綜上,總體而言,說的都很有道理了。但是大家的回答都其實是基於一個disk-based的系統來考慮的,如果是一個in-memory系統,裡面很多概念早都變的不一樣了,比方說disk-based的系統有lock很多時候是在等磁碟I/O,所以lock的實現高效與否有時候得看I/O是不是瓶頸。又再者,Buffer manager在in-memory系統裡面壓根就沒有,所以就沒有什麼頁表寫入寫出咯,數據就是直接在內存中malloc出來的。

不同資料庫實現真的千差萬別。如果我說,資料庫的多租戶比較難實現呢?就現在來看,只有Oracle和HANA實現了完整意義上的多租戶,其他資料庫developer你怎麼看呢?如果我說index在in-memory系統裡面已經沒那麼重要了呢?你又怎麼看?這些都得結合具體架構去看。如果我噴Oceanbase出來個paper,A會都未必能中,你又怎麼看呢?這些又得結合具體問題的量級再去看。

資料庫的難點,在於它是一個牽一髮而動全身的系統,很多時候你改這裡一點,其他都得跟著變,所以呢,資料庫的架構調整是一個非常巨大非常巨大的項目,不是你說改就能改的咯。最後,如果你是搞資料庫的,也不要隨便就去問別人,或者就追著Optimizer不放,不同的人理解的真的千差萬別,你以為你很對,其實你可能未必對呢。


最難的地方當然是query plan optimization了。最精華的地方我認為是,在內存嚴重不夠的情況下,既要減少寫硬碟的次數和數量,又要保證每一個query倘若成功結束了一定要成功寫進硬碟里。於是中間在各種transaction攪基的時候怎麼做,就是一個很好玩的問題。


王垠大哥,是你嗎?(大霧)


此答案是我做oracle dba時寫的:最難的,是數據恢復。估計不會有再難的了。

----------------------------------------

此答案是我做mysql和postgresql dba寫的:

整個資料庫,其實就是一個鎖機制。

事務處理核心是鎖機制。

高可用核心是鎖機制。

內存優化核心還是latch。

其實現在大部分資料庫的功能大同小異,基本就是你有的東西我也要有,我現在沒有以後也會有。但在鎖機制上,好多設計理念都不一樣。能設計mysql、oracle和postgres的,都是業界大牛,誰也不比誰差,能讓他們有分歧的問題,才是難題。


我認為查詢優化和存儲引擎比較難.

資料庫最精華的部分是事務處理. 這是各個資料庫最大的區別之一.

你需要一本 &<事務處理&>, 大神寫的.


資料庫三大件:查詢優化/索引設計/緩存,其實都不難,難就難在你要做到哪個水平嘍。x水平,大約10%的人具備這個能力,y水平;大約5%,市面上大部分商業資料庫就是這個水平;z水平,三大件必須都是業界頂尖,大約0.5%的人具備這個能力,但是這些人可能沒從事資料庫,自己對號入座吧


資料庫系統太複雜,需要團隊協作才可能寫出來,最難的是項目的工程化,把複雜問題簡化為一個個小問題,完成後再整合起來,保持系統不處於失控狀態。

最精華的地方在於如何定義執行計劃,這是優化器的輸出,也是執行器的輸入。一個反面的例子是MySQL, 它的定義不太好,導致優化器和執行器的改造/提升空間非常有限。執行計劃的定義形式,不但決定了執行器的執行方法,也決定了優化器的提升空間。

不同的產品其實現途徑有所差別, 多分幾步,少分幾步,感覺並不重要。


我覺得就是transaction manager. 基本上ACID property主要就是靠這塊保持的。系統的through put也和transaction 處理的效率有關。


實際可用


要說『資料庫』最難的地方,應該是『數』字吧,筆畫數最多……

資料庫是一種很複雜的應用系統。說資料庫系統的複雜,是因為資料庫系統自身在操作系統之上又實現了一把任務調度、內存管理和存儲管理。也就是說資料庫系統自身帶一個操作系統。這個操作系統用來調度線程執行查詢、檢查事務一致性;負責吃光它能使用的全部物理內存並和磁碟進行熱數據的交換;還得在現有操作系統的文件系統上維護自己的一組資料庫文件。

從大的方面說,寫這麼一個東東基本上就是一個簡單的操作系統的複雜度了。我覺得這部分才是最難的。這個文章算是個佐證吧:難圓滿的SQL Server 2017Linux夢


我覺得資料庫最難的地方還在於在設計之初,就考慮到業務擴展的情況。

比如用戶暴漲,新業務追加,新邏輯追加等等。

如果設計之初就考慮到了這些,那麼在優化性能的時候,就可以有目的的取捨了。


如果是給企業做的話,應該是在將來業務內容尚不明確的時候(甲方的需求會變得一塌糊塗),建立一個隨著產品迭代還可以保持基本架構穩定的資料庫結構。如果這一點做不到,基本產品要黃或者潛力有限。

這個沒法分步驟,只能靠經驗。

之後就是索引優化了。。


最難的是知道要寫一個什麼樣的資料庫,最精華的是怎麼為了寫這樣一個資料庫合理的做取捨。第三個問題太難了,答不了。


都難,每一塊都可以深入挖掘。查詢解釋器,查詢優化器,B+樹,日誌,鎖機制,事務並發,數據壓縮存儲,跨平台,Cache等等


資料庫過去現在和以後最難的地方都是管理和起名字 其他任何挑戰都無法和這個相提並論


我個人覺得,這個問題不是那麼專業,工業界和學術界,應該都不會說資料庫最難的地方在哪,最精華的地方在哪。

資料庫,按照定義,是按照一定數據模型組織的、長期存儲在計算機中、可被多個用戶共享的數據聚集。

資料庫管理系統,按照定義,是一套建立和管理資料庫的軟體,介於應用程序和操作系統之間,具有數據定義、數據操縱、資料庫運行管理、資料庫的建立和維護等功能。

從這兩個定義來看,題主應該問的是資料庫管理系統。

就以抽象數據類型作為最原始的起點來推導吧。學過數據結構的人,想必對抽象數據類型十分熟悉了。抽象數據類型,包括三個組成部分:數據類型、數據間的關係、操作方法。

沒錯,看看資料庫管理系統的前兩個功能:數據定義、數據操縱,是不是感覺到就是一個抽象數據類型了?

如果題主問的是資料庫,那麼就存在一個數據建模的問題,即數據類型是什麼,或者數據定義是什麼?為了解決這個問題,就必須在數學上解決數據建模。這是第一個問題。雖然在傳統的資料庫中,廣泛地採用E-R模型,但是,對於半結構化、非結構化、異構的數據,是沒有辦法解決的。所以,產生了眾多類型的NoSQL資料庫。數據的建模,必須保證數據操縱。對於關係模型,由於關係代數,所以有非常棒的通用的關係運算規則。但是,對於非關係型數據模型,很難找到一種通用模型。學術界借用本體,作為數據模型,不過似乎運算規則沒有進展。在工業界,轉化為某種常規的數據模型,然後在應用層進行處理,但是,不具備通用性。這是第一個難題。

現在假設這個難題解決了,就採用關係模型吧。那麼接下來就是數據的存儲和檢索問題。由於數據量大,無法放在內存中(內存資料庫是另一回事,流式處理後,這個數據就不再用了,或者緩存),所以必須放在外存中。但是,磁碟是塊設備。所以,如何存放數據。數據結構的教材,後面有N種方法。這就是存儲引擎的問題。設計一個存儲引擎,又是一個難題。對於常規的關係資料庫,還好辦一些。比如B樹。但是,對於時態、空間數據,也是問題頗多。

接下來,假設存儲引擎解決了,比如採用B+樹。


查詢優化器,,,


推薦閱讀:

如何評價國產高性能存儲引擎 TerarkDB ?
华为自研的数据库gaussdb怎么样?
維護人員不小心把資料庫刪除了要賠償嗎?
OpenTSDB 是一種基於 HBase 編寫的分散式、可擴展的時間序列資料庫。
它適用什麼場景呢?

日後想在資料庫方面發展,需要有哪些必備的技能?

TAG:資料庫 |