你們都據說過:數據庫設計有幾種範式,其中最主要知足第三範式.
1.第一範式(1NF):屬性不可分
第一範式是最基本的範式。若是數據庫表中的全部字段值都是不可分解的原子值,就說明該數據庫表知足了第一範式。數據庫
2.第二範式(2NF):知足1NF,徹底函數依賴
第二範式須要確保數據庫表中的每一列都和主鍵相關,而不能只與主鍵的某一部分相關(主要針對聯合主鍵而言)。也就是說在一個數據庫表中,一個表中只能保存一種數據,不能夠把多種數據保存在同一張數據庫表中。緩存
3.第三範式(3NF):知足2NF,消除傳遞依賴
第三範式須要確保數據表中的每一列數據都和主鍵直接相關,而不能間接相關。數據庫設計
4.BC範式(BCNF):符合3NF,而且,主屬性不依賴於主屬性。
若一個關係達到了第三範式,而且它只有一個候選碼,或者它的每一個候選碼都是單屬性,則該關係天然達到BC範式。函數
5.第四範式(4NF):符合BCNF,要求把同一表內的多對多關係刪除。性能
6.第五範式(5NF):符合4NF,將一個table儘量的分割成小的塊,以排除在table中全部冗餘的數據。fetch
沒有最好的設計,只有最合適的設計,因此不要過度注重理論。
在數據庫的設計中,數據應當按兩種類別進行組織:頻繁訪問的數據和頻繁修改的數據。
對於頻繁訪問可是不頻繁修改的數據,數據表設計應該反規範化。
對於頻繁修改但並不頻繁訪問的數據,數據表設計應當規範化。
有時還需將規範化的表做爲邏輯數據庫設計的基礎,而後再根據整個應用系統的須要,進行反規範化。
規範與反規範都是創建在實際的操做基礎之上的約束,脫離了實際二者都沒有意義。只有把二者合理地結合在一塊兒,才能相互補充,發揮各自的優勢。優化
在設計表時應同時考慮對某些表進行反規範化,方法有如下幾種:設計
一是分割表。
分割表可分爲水平分割表和垂直分割表兩種:
水平分割是按照行將一個表分割爲多個表,這能夠提升每一個表的查詢速度,但查詢、更新時要選擇不一樣的表,統計時要彙總多個表,所以應用程序會更復雜。
垂直分割是對於一個列不少的表,若某些列的訪問頻率遠遠高於其它列,就能夠將主鍵和這些列做爲一個表,將主鍵和其它列做爲另一個表。經過減小列的寬度,增長了每一個數據頁的行數,一次I/O就能夠掃描更多的行,從而提升了訪問每個表的速度。可是因爲形成了多表鏈接,因此應該在同時查詢或更新不一樣分割表中的列的狀況比較少的狀況下使用。索引
二是保留冗餘列。當兩個或多個表在查詢中常常須要鏈接時,能夠在其中一個表上增長若干冗餘的列,以免表之間的鏈接過於頻繁,通常在冗餘列的數據不常常變更的狀況下使用。字符串
三是增長派生列。派生列是由表中的其它多個列的計算所得,增長派生列能夠減小統計運算,在數據彙總時能夠大大縮短運算時間。
優化原則:
1.儘可能使用定長類型,由於固定長度的表會更快。
若是表中的全部字段都是「固定長度」的,整個表會被認爲是 「static」 或 「fixed-length」。 例如,表中沒有以下類型的字段: VARCHAR,TEXT,BLOB。只要你包括了其中一個這些字段,那麼這個表就不是「固定長度靜態表」了,這樣,MySQL 引擎會用另外一種方法來處理。
固定長度的表會提升性能,由於MySQL搜尋得會更快一些,由於這些固定的長度是很容易計算下一個數據的偏移量的,因此讀取的天然也會很快。而若是字段不是定長的,那麼,每一次要找下一條的話,須要程序找到主鍵。
而且,固定長度的表也更容易被緩存和重建。不過,惟一的反作用是,固定長度的字段會浪費一些空間,由於定長的字段不管你用不用,他都是要分配那麼多的空間。
使用「垂直分割」技術,你能夠分割你的表成爲兩個一個是定長的,一個則是不定長的。
2.儘可能使用較小的類型,由於更節省存儲空間,且越小的列會越快。
例如:
a.儘量用MEDIUMINT, SMALLINT 或是更小的 TINYINT代替INT;
b.對於只須要精確到某一天的數據類型,用DATE代替DATETIME好得多
c.使用TIMESTAMP類型代替DATETIME類型,由於其存儲空間只須要DATETIME類型的一半
d.把IP地址存成 UNSIGNED INT
e.使用ENUM而不是VARCHAR。ENUM 類型是很是快和緊湊的。在實際上,其保存的是 TINYINT,但其外表上顯示爲字符串。這樣一來,用這個字段來作一些選項列表變得至關的完美。
1.永遠爲每張表設置一個ID
咱們應該爲數據庫裏的每張表都設置一個ID作爲其主鍵,並且最好是一個INT型的(推薦使用UNSIGNED),並設置上自動增長的AUTO_INCREMENT標誌。
2.合理使用索引
對查詢進行優化,要儘可能避免全表掃描,首先應考慮在 where 及 order by 涉及的列上創建索引。索引並非越多越好,索引當然能夠提升相應的 select 的效率,但同時也下降了 insert 及 update 的效率,由於 insert 或 update 時有可能會重建索引,因此怎樣建索引須要慎重考慮,視具體狀況而定。
3.儘量的使用NOT NULL
NULL 類型比較特殊,SQL 難優化,如難以創建索引。並且NULL值存儲時可能還比EMPTY須要更多的存儲空間。
1.儘可能避免SELECT *命令,只返回須要的字段
2.利用LIMIT 1取得惟一行
當你查詢表的有些時候,你已經知道結果只會有一條結果,但由於你可能須要去fetch遊標,或是你也許會去檢查返回的記錄數。
在這種狀況下,加上 LIMIT 1 能夠增長性能。這樣同樣,MySQL數據庫引擎會在找到一條數據後中止搜索,而不是繼續日後查少下一條符合記錄的數據。
3.應儘可能避免在 where 子句中對字段進行 null 值判斷,不然將致使引擎放棄使用索引而進行全表掃描,如:
select id from t where num is null
4.應儘可能避免在 where 子句中使用 != 或 <> 操做符和not in,不然將致使全表掃描。
5.若是 where 子句的字段中存在某個字段沒有索引,將致使引擎放棄使用索引而進行全表掃描。
6.搜索字串column LIKE '%a'沒法利用索引的檢索優點,column LIKE 'a%'才能利用索引的檢索優點。
7.應儘可能避免在 where 子句中對字段進行表達式操做,這將致使引擎放棄使用索引而進行全表掃描。如:
select id from t where num/2 = 100
應改成:
select id from t where num = 100*2
8.應儘可能避免在where子句中對字段進行函數操做,這將致使引擎放棄使用索引而進行全表掃描。如:
select id from t where substring(name,1,3) = ’abc’ -–name以abc開頭的id
select id from t where datediff(day,createdate,’2005-11-30′) = 0 -–‘2005-11-30’ --生成的id
應改成:
select id from t where name like 'abc%'
select id from t where createdate >= '2005-11-30' and createdate < '2005-12-1'
9.不要在 where 子句中的「=」左邊進行函數、算術運算或其餘表達式運算,不然系統將可能沒法正確使用索引。
10.避免對實數和date/time等類型使用=操做符,由於可能得不到實際的結果。
11.避免使用or如:select id from t where num=10 or Name = 'admin'能夠這樣查詢:select id from t where num = 10union allselect id from t where Name = 'admin'