數(shù)據(jù)庫(kù)設(shè)計(jì)原則
引言
本文小結(jié)了數(shù)據(jù)設(shè)計(jì)原則;
數(shù)據(jù)庫(kù)設(shè)計(jì)對(duì)于數(shù)據(jù)庫(kù)的可維護(hù)性、可擴(kuò)展性至關(guān)重要,某些原則必須嚴(yán)格遵守;
數(shù)據(jù)庫(kù)設(shè)計(jì)范式
第一范式:屬性具有原子性,不可再分解,即不能表中有表;
第二范式:唯一性約束,每條記錄有唯一標(biāo)示,所有的非主鍵字段均需依賴于主鍵字段;
第三范式:冗余性約束,非主鍵字段間不能相互依賴;
數(shù)據(jù)庫(kù)設(shè)計(jì)原則
完整性:
not null聲明禁止插入空值;check子句限制屬性域;
去冗余:
避免冗余屬性,冗余屬性會(huì)帶來數(shù)據(jù)不一致性;
學(xué)生選課系統(tǒng)中,老師可以開課、學(xué)生可以選課,數(shù)據(jù)庫(kù)設(shè)計(jì)中,課程可以由課程編號(hào)和課程名稱等確定;
如果現(xiàn)在維護(hù)兩個(gè)表,一個(gè)表A存儲(chǔ)課程信息(課程編號(hào)、名稱、簡(jiǎn)介、學(xué)分、院系等),另一個(gè)表B存儲(chǔ)開課信息(有哪些課程開課),如果B中重復(fù)存儲(chǔ)了A的課程名稱、簡(jiǎn)介、學(xué)分、院系等信息,一旦A中的信息更新,B中和A中信息便出現(xiàn)不一致;
正確的做法是,B中只存儲(chǔ)課程編號(hào),并以此和A相關(guān)聯(lián);
解耦合:
一個(gè)表只存儲(chǔ)它應(yīng)該存儲(chǔ)的信息,和此表無關(guān)的信息放到另一個(gè)表去存儲(chǔ),表之間盡量解耦;
上面的例子中,A中存儲(chǔ)且只存儲(chǔ)面向課程的信息,另外有表C,存儲(chǔ)且只存儲(chǔ)面向?qū)W生的信息(學(xué)號(hào)、姓名、性別、年齡、選課id等),對(duì)于“課程級(jí)別”的信息,應(yīng)當(dāng)堅(jiān)決的存儲(chǔ)在A而不是C中,而且盡量避免將A、C合并成一個(gè)表(可能剛開始是設(shè)計(jì)成一個(gè)表),而且A、C間盡量解耦;
字段不可再分:
一個(gè)字段中不要出現(xiàn)分隔符,或者在一個(gè)字段中存儲(chǔ)多個(gè)信息;
例如,first name和last name不要放在同一個(gè)字段中,穩(wěn)定版本號(hào)和臨時(shí)版本號(hào)不要放在同一個(gè)字段中;
考慮性能:
上述原則可能造成多表連接查詢的情況出現(xiàn),降低性能;
如果性能成為主要矛盾,則上述原則也不絕對(duì);
數(shù)據(jù)庫(kù)命名原則
數(shù)據(jù)庫(kù)的命名會(huì)直接影響到上層應(yīng)用的名稱,所以要和業(yè)務(wù)部門仔細(xì)討論、慎重確定;
每個(gè)屬性名在數(shù)據(jù)庫(kù)中只有唯一的含義,number這個(gè)屬性名可能表示電話號(hào)碼或是房間號(hào),這是一種容易引起歧義的命名;
數(shù)據(jù)庫(kù)的名詞要一致,不能在這個(gè)地方叫一個(gè)名字,到另外一個(gè)表又叫另外一個(gè)名字;
一般來說,Table命名用單數(shù),Column命名用單數(shù);
Table不用Prefix前綴來表示不同的組,而用schema來劃分命名空間(postgresql中);
命名用snake_case,不要有其他特殊字符;
名稱中不要有sql關(guān)鍵字;
如果確實(shí)需要使用sql關(guān)鍵字,可用雙引號(hào)包圍,比如
CREATE TABLE "order"(...);主鍵的名字永遠(yuǎn)都是同一的,就是id,外鍵名稱才需要加table的名字,諸如
xxx_id、yyy_id;命名不要用縮寫,比如date縮寫成dt;
用?
create_date/update_date/sample_date這些含義更明確的名稱代替date這個(gè)命名,這樣不僅表達(dá)更準(zhǔn)確,而且避免了用關(guān)鍵字的麻煩;timestamp類型的字段要有timezone(時(shí)區(qū)),字段名用
xxx_date的形式,僅表示年月日用xxx_day,僅表示時(shí)分秒用xxx_time;表示數(shù)量、次數(shù)等概念的字段名稱最好寫為
xxx_count,不要寫為xxx_number/xxx_num/xxx_no等;boolean類型的命名要用
is_xxx格式;
數(shù)據(jù)庫(kù)設(shè)計(jì)其他注意事項(xiàng)
每個(gè)表都要有主鍵,名稱是id,類型為
bigint;主鍵的類型是設(shè)為integer還是long,取決于這個(gè)系統(tǒng)用多長(zhǎng)時(shí)間,如果要用100年,主鍵還是設(shè)置為long類型較好,這樣用的很久以后id也不會(huì)超出范圍;
一個(gè)字段不要有多個(gè)用途,空間不是問題,清晰才是重點(diǎn);
不要過早優(yōu)化,先把東西做出來再說,遇到性能問題再去優(yōu)化;
對(duì)于
varchar類型的字段,當(dāng)字符串并不是非常明確到底限制是多少的時(shí)候,通常選擇255這個(gè)長(zhǎng)度,varchar(50)并不比varchar(255)節(jié)省空間,varchar(50)僅僅是表示最多分配50個(gè)字符而已;varchar(100)類型在PostgreSQL中代表100個(gè)字符,而在Oracle中代表100字節(jié),具體的占用空間數(shù)目和語言、編碼方式有關(guān);對(duì)外鍵要加Index;
數(shù)據(jù)庫(kù)里面的密碼一定要加密,不能保存明文;
用
is_deleted=true來表示本條記錄的業(yè)務(wù)上的刪除,不要在數(shù)據(jù)庫(kù)中真正刪除記錄,或者僅僅是版本化修改,這樣能防止數(shù)據(jù)丟失;
數(shù)據(jù)庫(kù)性能提升方案
使用索引會(huì)大大提升查詢效率,同時(shí)降低在被索引的表上INSERT和DELETE效率;
分離頻繁和不頻繁使用的數(shù)據(jù)到多個(gè)表中;
例如,原先,一個(gè)表中保存用戶名、密碼、年齡、個(gè)人簡(jiǎn)介、學(xué)校等信息,但是發(fā)現(xiàn)訪問用戶名、密碼、年齡的頻率遠(yuǎn)高于其他字段,此時(shí)就應(yīng)當(dāng)將這個(gè)表分為兩個(gè)表,分別存儲(chǔ)頻繁訪問項(xiàng)和非頻繁訪問項(xiàng);
數(shù)據(jù)庫(kù)安全策略
至少保存3個(gè)月的系統(tǒng)訪問日志;
數(shù)據(jù)庫(kù)中的表可以有創(chuàng)建和更新時(shí)間戳,及所創(chuàng)建/修改行的用戶標(biāo)示;
不刪除字段,而是打上一個(gè)被刪除的標(biāo)記;
版本化修改;
大型數(shù)據(jù)庫(kù)設(shè)計(jì)
負(fù)載均衡;
讀寫分離;
分布式存儲(chǔ);
參考這篇文章(https://www.cnblogs.com/ejiyuan/archive/2010/10/29/1796292.html);
source: //changsiyuan.github.io/2016/05/06/2016-5-6-database-design/
分享&在看
