性能優化系列六:數據庫設計

1、爲優化而設計

1. 數據庫設計

數據庫設計,一個軟件項目成功的基石。數據庫設計也是門學問。
在項目早期由開發者進行數據庫設計(後期調優須要DBA)。一個精通OOP和ORM的開發者,設計的數據庫每每更爲合理,更能適應需求的變化。由於數據庫的規範化,與OO的部分思想雷同(如內聚)。而DBA,設計的數據庫的優點是能將DBMS的能力發揮到極致,可以使用SQL和DBMS實現不少程序實現的邏輯,與開發者相比,DBA優化過的數據庫更爲高效和穩定。node

2. 數據庫設計與程序設計的差別

 有以下的一個系統:mysql

面向對象設計思路:sql

封裝
多態
IOC
AOP…數據庫

數據庫的設計思路:緩存

關注存儲
關注效率
二維表關係
關注完整性服務器

3. 數據庫設計早期優化

不要把它僅僅當成一個存儲的功能
一、關係明確:各個表之間的關係必定要先例清楚
二、節省空間:原則合適的類型,不要浪費存儲空間
三、提升效率:好比如今的操做系統都是64位的,咱們選擇主鍵的類型爲beginint,由於beginint也是64位的,和cpu寄存器匹配,這樣就能一次計算拿到值,效率更高網絡

2、設計原則

1. 數據庫種類

說明:咱們這裏所說的數據庫都是指關係型數據庫併發

2. 數據庫特色

文件系統和數據庫系統之間的區別:
(1)文件系統用文件將數據長期保存在外存上,數據庫系統用數據庫統一存儲數據;
(2)文件系統中的程序和數據有必定的聯繫,數據庫系統中的程序和數據分離;
(3)文件系統用操做系統中的存取方法對數據進行管理,數據庫系統用DBMS統一管理和控制數據;
(4)文件系統實現以文件爲單位的數據共享,數據庫系統實現以記錄和字段爲單位的數據共享。數據庫設計

文件系統和數據庫系統之間的聯繫:
(1)均爲數據組織的管理技術;
(2)均由數據管理軟件管理數據,程序與數據之間用存取方法進行轉換;
(3)數據庫系統是在文件系統的基礎上發展而來的。分佈式

3. 優化設計第一步

 精通數據類型

 

4. 優化設計第二步

 瞭解範式1NF,2NF,3NF。。。

4.1 第一範式

1NF:列不可分。每一列都是不可分割的基本數據項

  反例:某列:姓名=(小李,小張)

4.2 第二範式

2NF:1NF的基礎上面,非主屬性徹底依賴於主關鍵字

         ID,學號,姓名,賬號,年級

    姓名、年齡這些非主屬性依賴於主關鍵字學號、帳號

4.3 第三範式
3NF:屬性不依賴於其它非主屬性 , 消除傳遞依賴

     課程表:學員ID,學號,年級

     這裏的學號就和4.2中的學號存在傳遞依賴,由於4.2中的學號變動了,這裏的學號也要跟着變動
4.4 BCNF:符合3NF,每一個表中只有一個候選鍵
4.5 4NF:沒有多值依賴

說明:在設計表的時候知足第一二三範式

5. 優化設計第三步

設計以前要有一些想法

一、選擇小的數據類型——節省空間
二、單獨設計主鍵,並考慮分佈式擴展
三、外鍵設計
四、索引設計——提升性能
五、關聯關係表設計,多對一,多對多
六、讀寫頻繁的信息,與不頻繁的信息分開
七、配置表,日誌表,定時任務表等
八、彙總表設計——解決大數據性能問題時根據業務場景彙總數據

6. 優化設計第四步

 要有一些套路

一、通用型設計
例:人員,部門,角色

這裏指的通用型設計是指適用性,好比最開始作的是一個小公司的OA系統的數據庫設計,後面切換到一個國際型的大公司之後,這一套設計是否還能用
二、特別設計
附件,日誌,配置,監控等
三、存儲設計
類型劃分便於分區
四、一些附加字段
建立日期,修改日期,排序
五、流水錶
相似於日誌,但由業務處理結果組成,賬戶變更或業務處理的中間值

7. Codd的RDBMS12法則

Edgar Frank Codd(埃德加·弗蘭克·科德)被譽爲「關係數據庫之父」,並由於在數據庫管理系統的理論和實踐方面的傑出貢獻於1981年獲圖靈獎。在1985年,Codd博士發佈了12條規則,這些規則簡明的定義出一個關係型數據庫的理念,它們被做爲全部關係數據庫系統的設計指導性方針。

1.信息法則 關係數據庫中的全部信息都用惟一的一種方式表示——表中的值。

2.保證訪問法則 依靠表名、主鍵值和列名的組合,保證能訪問每一個數據項。

3.空值的系統化處理 支持空值(NULL),以系統化的方式處理空值,空值不依賴於數據類型。

4.基於關係模型的動態聯機目錄 數據庫的描述應該是自描述的,在邏輯級別上和普通數據採用一樣的表示方式,即數據庫必須含有描述該數據庫結構的系統表或者數據庫描述信息應該包含在用戶能夠訪問的表中。

5.統一的數據子語言法則 一個關係數據庫系統能夠支持幾種語言和多種終端使用方式,但必須至少有一種語言,它的語句可以一某種定義良好的語法表示爲字符串,並能全面地支持如下全部規則:數據定義、視圖定義、數據操做、約束、受權以及事務。(這種語言就是SQL)

6.視圖更新法則 全部理論上能夠更新的視圖也能夠由系統更新。

7.高級的插入、更新和刪除操做 把一個基礎關係或派生關係做爲單個操做對象處理的能力不只適應於數據的檢索,還適用於數據的插入、修改個刪除,即在插入、修改和刪除操做中數據行被視做集合。

8.數據的物理獨立性 無論數據庫的數據在存儲表示或訪問方式上怎麼變化,應用程序和終端活動都保持着邏輯上的不變性。

9.數據的邏輯獨立性 當對錶作了理論上不會損害信息的改變時,應用程序和終端活動都會保持邏輯上的不變性。

10.數據完整性的獨立性 專用於某個關係型數據庫的完整性約束必須能夠用關係數據庫子語言定義,並且能夠存儲在數據目錄中,而非程序中。

11.分佈獨立性 無論數據在物理是否分佈式存儲,或者任什麼時候候改變分佈策略,RDBMS的數據操縱子語言必須能使應用程序和終端活動保持邏輯上的不變性。

12.非破壞性法則 若是一個關係數據庫系統支持某種低級(一次處理單個記錄)語言,那麼這個低級語言不能違反或繞過更高級語言(一次處理多個記錄)規定的完整性法則或約束,即用戶不能以任何方式違反數據庫的約束

落實這些原則:

(一)下降對數據庫功能的依賴

(二)定義實體關係的原則
    牽涉到的實體 識別出關系所涉及的全部實體。
    全部權 考慮一個實體「擁有」另外一個實體的狀況。
    基數 考量一個實體的實例和另外一個實體實例關聯的數量。
(三)列意味着惟一的值
    若是表示座標(0,0),應該使用兩列表示,而不是將「0,0」放在1個列中。
(四)列的順序,可讀性問題
(五)定義主鍵和外鍵
    數據表必須定義主鍵和外鍵(若是有外鍵)。
(六)選擇鍵
(七)是否容許NULL
    任何值和NULL拼接後都爲NULL。
    全部與NULL進行的數學操做都返回NULL。
    引入NULL後,邏輯不易處理。

(八)規範化——範式

    1NF
    包含分隔符類字符的字符串數據。
    名字尾端有數字的屬性。
    沒有定義鍵或鍵定義很差的表。
    2NF
    多個屬性有一樣的前綴。
    重複的數據組。
    彙總的數據,所引用的數據在一個徹底不一樣的實體中。
    BCNF- 「每一個鍵必須惟一標識實體,每一個非鍵熟悉必須描述實體。
    4NF
    三元關係(實體:實體:實體)。
    潛伏的多值屬性。(如多個手機號。)
    臨時數據或歷史值。(須要將歷史數據的主體提出,不然將存在大量冗餘。)
(九)選擇數據類型
(十)優化並行
    設計DB時就應該考慮到對並行進行優化,好比,timestamp類型。

8. 命名規則

表名規則
一、要用前綴,但不要用無心義的前綴,通常是根據業務模塊設置前綴
二、下劃線分隔
三、全小寫
列名規則
一、通常不用前綴
二、下劃線分隔
三、全小寫

3、設計案例

1. 鍵設計

物理主鍵,好建索引,消除傳遞依賴
主鍵類型,普通系統是int或bigint,效率問題,目前的操做系統基本都是64位的,建議使用bigint
Uuid,容量問題,防碰撞
取消全部的聯合主鍵(課程表中:年級+課程名)

2. 索引設計

2.1. B-Tree 索引

B-Tree 索引是 MySQL 數據庫中使用最爲頻繁的索引類型,除了 Archive 存儲引擎以外的其餘全部的存儲引擎都支持B-Tree 索引。不只僅在MySQL中是如此,實際上在其餘的不少數據庫管理系統中B-Tree索引也一樣是做爲最主要的索引類型,這主要是由於B-Tree索引的存儲結構在數據庫的數據檢索中有很是優異的表現

2.2. Hash 索引

Hash 索引結構的特殊性,其檢索效率很是高,索引的檢索能夠一次定位,不像B-Tree索引須要從根節點到枝節點,最後才能訪問到頁節點這樣屢次的IO訪問,因此Hash索引的查詢效率要遠高於B-Tree索引。

 示例:

Hash值:1111對應的有 記錄1,記錄2,記錄3 
Hash值:2222對應的記錄有 記錄4,記錄5,記錄6

說明:

根據字段計算hash值,把記錄放在一個格子裏,索引的時候只須要找到hash值就能獲取到裏面的記錄了

2.3. 索引的類型

普通索引:最基本的索引,沒有任何限制

惟一索引:與"普通索引"相似,不一樣的就是:索引列的值必須惟一,但容許有空值。

主鍵索引:它是一種特殊的惟一索引,不容許有空值。

全文索引:僅可用於 MyISAM 表,針對較大的數據,生成全文索引很耗時好空間。

組合索引:爲了更多的提升mysql效率可創建組合索引,遵循」最左前綴「原則。

覆蓋索引(Covering Indexes):查詢的列正好是索引列就叫作覆蓋索引,如select id from table_a

聚簇索引(Clustered Indexes)

聚簇索引保證關鍵字的值相近的元組存儲的物理位置也相同(因此字符串類型不宜創建聚簇索引,特別是隨機字符串,會使得系統進行大量的移動操做),且一個表只能有一個聚簇索引。由於由存儲引擎實現引,因此,並非全部的引擎都支持聚簇索引。目前,只有solidDB和InnoDB支持。

非聚簇索引

二級索引葉子節點保存的不是指行的物理位置的指針,而是行的主鍵值。這意味着經過二級索引查找行。
InnoDB對主鍵創建聚簇索引。若是你不指定主鍵,InnoDB會用一個具備惟一且非空值的索引來代替。若是不存在這樣的索引,InnoDB會定義一個隱藏的主鍵,而後對其創建聚簇索引。通常來講,DBMS都會以聚簇索引的形式來存儲實際的數據,它是其它二級索引的基礎。

2.4 何時能夠建索引

1)列無重複值,能夠建索引:惟一索引和普通索引

2)彙集索引和非彙集索引均可以是惟一的。所以,只要列中的數據是惟一的,就能夠在同一個表上建立一個惟一的彙集索引和多個惟一的非彙集索引。

3)建了索引性能獲得提升

4)區分度高的列能夠建索引,好比表示男和女的列區分度就不高,就不能建索引

說明:

惟一索引必定要當心,它帶有惟一約束。

查詢區分度:SELECT COUNT(DISTINCT 列_xx)/COUNT(*) FROM 表

2.5 何時不能夠建索引

1.頻繁更新的字段不適合創建索引

2.where條件中用不到的字段不適合創建索引

3.表數據能夠肯定比較少的不須要建索引

4.數據重複且發佈比較均勻的的字段不適合建索引(惟一性太差的字段不適合創建索引),例如性別,真假值

5. 參與列計算的列不適合建索引,如select * from where amount+1>10

6. 查詢返回的記錄數不適合創建索引

7. 查詢的排序表記錄小於40%不適合創建索引

8. 查詢非排序表的記錄小於 7%不適合創建索引

9. 表的碎片較多(頻繁增長、刪除)不適合創建索引

說明:

基礎表維護時,系統要同時維護索引,不合理的索引將嚴重影響系統資源,主要表如今CPU和I/O上;
插入、更新、刪除數據產生大量db file sequential read鎖等待;

2.6 建索引的目的

加快查詢速度,固然了,使用索引後查詢有跡可循。
減小I/O操做,經過索引的路徑來檢索數據,不是在磁盤中隨機檢索。
消除磁盤排序,索引是排序的,走完索引就排序完成

2.7 存儲引擎及文件格式比較

只須要記住Innodb和Myisam的鎖和事物的區別就能夠了:

Innodb支持表鎖和行鎖,Myisam只支持表鎖

Innodb支持事物,Myisam不支持事物

 2.8 各存儲引擎的區別

 

說明:

Innod的存儲最大限制64TB

3. 表附加字段設計

經常使用:
建立時間:create_at
修改時間:update_at
排序:sn
有時用:
說明:desc,remark
備選字段:opts_1,opts_2….

4. 字典表設計

字典表與系統配置表的區別
字典表示例
經常使用數據的常量化,消費類型,支付類型,物品類型(含層級)
系統配置表示例
各模塊功能參數的常量化,key-value

字典表:

CREATE TABLE dict_content
(
    dcc_id bigint NOT NULL, 
    dct_id bigint, 
    dcc_no character varying(20), 
    dcc_name character varying(30), 
    extend_no character varying(50), 
    remarks character varying(400), 
    sort bigint, 
    parent_id bigint,
    is_leaf smallint, 
    path character varying(400), 
    CONSTRAINT dict_content_pkey PRIMARY KEY (dcc_id)
)

系統表:

CREATE TABLE sys_config_data
(
    id bigint NOT NULL,
    create_date timestamp without time zone NOT NULL,
    modify_date timestamp without time zone NOT NULL,
    catalog character varying(255),
    content character varying(255),
    description character varying(255),
    sn character varying(255),
    CONSTRAINT sys_config_data_pkey PRIMARY KEY (id)
)

5. 附件表設計

存儲位置
類型
用途
使用次數
下載次數

6. 層級結構表設計

父子層級,parent_id
表內劃分層級
表外劃分層級
最快檢索設計

CREATE TABLE public.ihp_boq_tpl 
( 
    boq_id bigint NOT NULL, -- 清單id 
    boq_no character varying(32), -- 清單編號 
    ext_no character varying(32), -- 擴展編號 
    boq_name character varying(64), -- 清單名稱 
    unit_id bigint, -- 計量單位 
    boq_kind smallint, -- 清單類型 
    boq_mode smallint, -- 清單模式 
    boq_rate numeric(18,2), -- 計量率 
    formula character varying(32), -- 計算公式 
    use_formula smallint, -- 是否啓用公式 
    parent_id bigint, -- 父節點 
    path character varying(128), -- 路徑 
    level smallint, -- 層次 
    end_node smallint, -- 最終節點 
    remarks character varying(256), -- 備註 
    status smallint, -- 狀態 
    feature character varying(128), 
    frequency character varying(32), 
    quota_unit_id bigint, 
    quota_tbl_no character varying(8), 
    project_id bigint, 
    CONSTRAINT pk_ihp_boq_tpl PRIMARY KEY (boq_id) 
)

 

 

7. 流程表設計

流程主表
任務子表
業務表關聯

CREATE TABLE process_run
(
    runid bigint NOT NULL, 
    subject character varying(256) NOT NULL, 
    creator character varying(128), 
    userid bigint NOT NULL, 
    defid bigint NOT NULL, 
    piid character varying(64), 
    createtime timestamp without time zone NOT NULL, 
    runstatus bigint NOT NULL, 
    busdesc character varying(1024), 
    entityname character varying(128), 
    entityid bigint, 
    formdefid bigint, 
    CONSTRAINT pk_process_run PRIMARY KEY (runid)
)
CREATE TABLE process_form
(
    formid bigint NOT NULL, 
    runid bigint NOT NULL, 
    activityname character varying(256) NOT NULL, 
    createtime timestamp without time zone NOT NULL, 
    endtime timestamp without time zone, 
    durtimes bigint, 
    creatorid bigint, 
    creatorname character varying(256), 
    taskid character varying(64), 
    status bigint DEFAULT 0, 
    preformid bigint, 
    comments character varying(2000), 
    entity_id bigint, 
    entity_name character varying(128), 
    CONSTRAINT pk_process_form PRIMARY KEY (formid)
)

4、冗餘設計

反範式

適當冗餘
一、借鑑覆蓋索引的思路,在表內直接放經常使用的字段
二、提取相關數據,製做彙總表
三、第3NF的違反
四、程序級別的冗餘或緩存
五、不要寫觸發器,不要寫存儲過程

分表分庫

•性能:能輕鬆面對海量數據和高併發的請求處理,好的分佈式數據庫能作到90%以上的線性增加能力;
•靈活性、彈性:現代的系統的業務和使用場景變化很快,用戶的增加也有不少不肯定因素。彈性擴容就很是重要。分佈式數據庫自己有Cloud-Ready的特性,能很容以經過添加設備擴容知足需求,而不須要影響開發;
•多中心、多活:這點在大型應用中很常見,分佈式數據庫就更容易實現這個功能,固然這裏涉及到分佈式數據庫的同步和一致性的能力,這也是判斷分佈式數據庫好壞的一個重要指標。
•讀寫分離:主從節點都能發揮做用;例如巨杉SequoiaDB數據庫,能在一組三副本的複製組上實現OLTP,NoSQL應用,OLAP多種應用場景同時使用。
•低成本:x86服務器,SATA存儲(部分能夠用SSD),加上較好的網絡帶寬就能夠了。

 

1.水平分區:基本對1個或多個鍵的水平哈希,加強數據的並行處理能力來提升性能;2.垂直分區:和過去的Partition很像,對數據進行有含義的拆分;3.混合分區:水平分區和垂直分區共同使用。

相關文章
相關標籤/搜索