前言 我們知道,軟件工程是為了解決軟件危機的,它是采用工程的概念、原理、 技術和方法來開發與維護軟件,把經過時間考驗而證明正确的管理技術和當前能夠得到的最好的技術方法結合起來。
在軟件開發的過程中,數據庫設計是非常重要的,它需要根據需求分析設抽象出E-R圖,邏輯結構設計,數據庫選型,物理設計,實施及運維。下面就聊聊那些年數據庫設計的那些事。
軟件工程 
在問題定義和可行性分析都做好的前提下,就可以進入需求分析階段了,通常來講,一般都有産品部,需求分析往往都是由産品經理和客戶去溝通落地形成PRD,跟開發溝通之後,就可以根據需求分析做數據庫設計了,下面主要讨論下數據庫設計的步驟以及每個階段要完成的内容。
數據庫設計基本步驟 
需求分析階段 要進行數據庫設計首先要了解用戶需求,參與到用戶需求分析中去,需求分析常用SA(Structured Analysis:結構化分析方法)強調開發方法的結構合理性以及所開發軟件的結構合理性的軟件開發方法,是生命周期法的繼承與發展,是生命周期法與結構化程序設計思想的結合。
其基本思想是用系統工程的思想和工程化得方法,根據用戶至上的原則,自始自終按照結構化、模塊化,自頂向下地對系統進行分析與設計。建立的主要步驟如下:
首先畫系統的輸入輸出,先畫頂層數據流程圖(DFD:Data Flow Diagram),頂層數據流程圖隻包含一個加工,用以表示被開發的系統,然後考慮該系統有哪些輸入、輸出數據流。畫系統内部,即畫下層數據流層圖。 下面是一個交易系統的DFD,需要先畫出頂層數據流圖,主要包括系統子模塊之間的交互,然後再進一步對子模塊進行分解。

概念設計階段 概念設計是整個數據庫設計的關鍵,它是對需求分析階段的成果進行綜合,歸檔以及抽象出一個獨立具體的DBMS模型,與具體的RDBMS産品無關。
在實際的開發中,常用E-R(Entity-Relationship:實體關系)圖來表示,常用的工具PowerDesigner,可以實現CDM(概念數據模型)-LDM(邏輯數據模型)-PDM(物理數據模型)-Database的自動轉換,這個過程稱為正向工程,如果有database建庫腳本,也可以通過PowerDesigner工具生成CDM,即Database-LDM-CDM,稱為反向工程。
概念設計通常采用自底向上,首先定義各系統局部的概念模型,然後再将他們集成合并起來,得到全局的概念模型。
舉個例子說明下,現在負責交易系統的開發,主要涉及訂單,價格模塊,分别交給不同的開發去設計開發。
首先每個人要根據需求分析抽象出自己的實體Entity及之間的關系Relationship,設計初步完成之後就要開會讨論了,把每個開發的ER圖合并起來,就得到全局交易系統的CDM。

名詞動詞形容詞分析法
開發如何根據需求分析設計ER圖,完成模塊的詳細設計,提供接口文檔,最重要的是需求分析抽象CDM階段的ER圖,一種行之有效的方法就是名稱動詞形容詞分析法,下面就詳細解釋下這種分析方法。
還是舉例說明吧,現在讓我負責交易系統的訂單這塊的開發,在需求分析文檔裡看到一句話實現訂單的高效管理,分析的過程如下:
名稱:訂單,訂單就是一個Entity,也可以拆分成多個Entity,抽象出每個Entity的Attribute(前期可能由于需求不明确,可以隻做确認的内容),Entity通過PowerDesigner的正向工程轉換成數據庫裡的數據表,Attribute就是表的字段;數據表通過ORM映射到Java裡的就是Class,字段就是private屬性。
動詞:管理,也就是要對訂單要進行增删改查CRUD操作。
形容詞:高效,首先想到在訂單表上創建合适的索引吧,其次根據業務的發展,訂單表太大會影響寫入性能,是否要進行讀寫分離,分庫分表操作。

數據庫設計三範式
第一範式1NF:确保每個字段保持原子性,不可分割。
對于用戶表users來說,有用戶姓名(一般由first_name和last_name組成),如果使用類似Oracle的複合數據類型,就違反了1NF。

很明顯users的字段user_name是一個自定類型,是可分解的,這就違反了1NF。
第二範式2NF:确保字段完全依賴于主鍵。
一個表中隻能保存一種數據,不可以把多種數據保存在一張表裡,假如一張表既存儲了用戶信息,又存儲商品信息,還存儲了訂單信息,這樣就違反了2NF,而應該将用戶表,商品表,訂單表拆分成三張表,确保字段是該表擁有的。
第三範式3NF:必須滿足2NF,實體中每個屬性與主鍵直接相關而不能間接相關。
這個也不難理解,對于訂單表orders來講,是要存儲用戶表users的user_id,要明确哪個用戶下的單,有些業務場景是要獲取users表的用戶姓名user_name,為了減少orders和users表的關聯查詢,将user_name冗餘到orders表中,這種設計就違反了3NF,減少數據冗餘,可以通過主外鍵進行表之間連接。

到底該不該使用外鍵Foreign Key
外鍵目的是為了保證數據完整性和一緻性,避免産生髒數據,設置外鍵有啥缺點呢。
影響寫入性能:對于insert來說,每次都要判斷從表的外鍵列是否在主表中存在(例如每次插入orders表,都要判斷下user_id是否在users中存在),會降低數據庫的寫入性能,對于MySQL本來就隻有Master輸出寫能力的數據庫,就不太合适了,MySQL開發規範規定不允許使用外鍵也是有一定道理的。并發問題:在使用外鍵的情況下,每次修改數據都需要去另外一個表檢查數據,需要獲取額外的鎖。在高并發大場景,使用外鍵造成死鎖或鎖等幾率更大。 實際開發中,更多的是不靠外鍵來保證數據的完整性和一緻性,而是通過的業務邏輯,比如用戶要下單,必須先登錄系統,下單隻需要将登錄的用戶編号寫入到訂單表,這個用戶必然是存在于用戶表的,對于一個用戶友好的系統來說,盡量讓用戶選擇,不要人工輸入,這樣可以保證數據一緻性,避免髒數據的産生。
邏輯設計階段 邏輯設計階段是将概念數據模型轉換為具體的DBMS所支持的數據模型,并将進行優化。雖然LDM獨立于DBMS的,但可以進行外鍵,索引,視圖等對象的設計工作。
在此階段,各子模塊的E-R圖之間的沖突主要有三類:屬性沖突,命名沖突和結構沖突,同時E-R圖向關系模型的轉換,要解決如何将實體性和實體間的聯系轉換為關系模式,确定這些關系模式的屬性和碼,實際開發中,邏輯設計階段不是必須的,有些是從CDM直接到PDM了。

數據庫選型 數據庫選型是非常重要的環節,一般在需求分析完成之後,通過架構評審會進行确認,數據庫方面主要包括數據存儲,檢索,安全,讀寫分離,分庫分表,數據歸檔,接入數據倉庫都要進行确認,根據業務的場景對相關的數據庫産品進行調研比對,選擇最适合業務場景的數據庫作為存儲。
舉個例子:對于一個DAU 1000W TPS 3W的交易的業務場景,如果使用MySQL來存儲,我們知道原生的MySQL寫入瓶頸,以及訂單相關表數據量增長過快導緻的性能問題,不太适合這種高并發寫的場景,可以考慮使用分布式MySQL,例如常見的DRDS,TiDB,OceanBase。既可以解決原生MySQL寫入瓶頸,同時也可以處理單表數據量大導緻的分庫分表問題。
同樣對于優酷,愛奇藝這種視頻類系統,使用MySQL來存儲就不太合适了,應該采用MongoDB集群來存儲;對于京東,淘寶的這種搜索服務采用ElastSearch數據庫集群處理會更高效。
物理設計階段 邏輯設計階段和數據庫選型完成之後,就可以通過LDM生成PDM了,在物理設計階段,需要設計跟RDBMS相關的對象,例如設計存儲過程,觸發器,用戶自定義函數,表空間等。

數據庫實施階段 
例如選擇的是MySQL數據庫,通過PDM生成數據庫的建庫腳本之後,需要進行規範性檢查,通過之後就可以創建表結構,規範性檢查可以借助開源的SQL審核工具,如Yearning,Archery都可以設置規則,檢查之後會給出整改建議,能夠幫我們自動實現SQL Review。Yearning是用go開發,目前隻支持MySQL數據庫,Archery可以支持多種數據庫。下面是Yearning自動化SQL審核平台的一個DDL工單的檢測示例。

檢測通過後就可以提交工單了,審核通過後就會自動執行DDL腳本建庫。
數據庫維護階段 數據庫維護階段主要包括業務支撐和數據庫運維,簡單總結了下,如下圖所示。

總結 實際開發中,數據庫設計階段是非常重要,通常都是開發自己根據業務模塊的需求去分析,抽取成CDM中的E-R圖,轉換成LDM,經過數據庫選型及生成PDM,最終生成數據庫表,然後才能開始coding,測試、發布上線以及版本叠代,為了保證線上業務的安全穩定高效,就需要對數據庫進行精細化管理和維護。
仔細觀察不難發現,數據庫設計的核心就是對需求分析的理解以及抽取沉底出E-R圖,這就需要對行業及相關業務有深刻立即及抽象能力,大家有木有發現,招聘Java工程師的前面附加了業務屬性,例如用戶域Java工程師,支付域Java工程師,主要體現在需求分析抽象以及數據模型設計能力上,開發過程中多參與業務需求讨論是非常有必要的。今天就聊這麼多,希望對大家有所幫助。
絮叨 敖丙把自己的面試文章整理成了一本電子書,共 1630頁!
幹貨滿滿,字字精髓。目錄如下,還有我複習時總結的面試題以及簡曆模闆,現在免費送給大家。

回複【資料】有我準備的一線大廠面試資料和簡曆模闆
,








