資料庫三種正規化
第一正規化(1NF)
屬性的不可再分特性:稱為關係的第一正規化。
舉剛才的例子:
一個家庭中有丈夫,妻子,子女,這些屬性對於這個表來說都是不可再分的了。
概念:也就是說要求屬性具有原子性~ 不可再分解!
資料庫表中的每一列都是不可分割的基本資料項,同一個列中不能有多個值。
如果重複
如果出現重複的屬性,就可能需要定義一個新的實體,新的實體由重複的屬性構成,新實體與原實體之間為一對多的關係。在1NF中表的每一行只包含一個例項的資訊。無重複列~
對於任何一個數據庫,1NF是對關係模式的基本要求,不滿足1NF的資料庫就不是關係資料庫。當前的任何DBMS中,不可能做出不符合1NF的資料庫,因為這些DBMS不允許你把資料庫的表的一列再分成多個列。
第二正規化(2NF)
第二正規化是在第一正規化的基礎上建立起來的,即滿足第二正規化必須先滿足第一正規化1NF。 第二正規化2NF要求資料庫表中的每個例項或行必須可以被唯一區分。
一般來說,之前是依靠每個行可能有一個或某幾個資料不同來區分。
這裡一般就是加上id,或者所謂的uuid來區分,這也就是主鍵/主碼~
2NF要求實體的屬性完全依賴主關鍵字。 所謂完全依賴是指不能存在僅依賴主關鍵字一部分的屬性,要求記錄有唯一標識。
所謂完全依賴是指不能存在僅依賴主關鍵字一部分的屬性,如果存在,那麼這個屬性和主關鍵字的這一部分應該分離出來形成一個新的實體,新實體與原實體之間是一對多的關係。為實現區分通常需要為表加上一個列,以儲存各個例項的唯一標識。簡而言之,第二正規化就是屬性完全依賴於主鍵。
舉例:
CREATE TABLE `articles` (
`id` int(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`article_uuid` char(32) NOT NULL DEFAULT '0' COMMENT '文章uuid',
`title` varchar(200) NOT NULL DEFAULT '0' COMMENT '文章名',
`user_uuid` char(32) NOT NULL DEFAULT '0' COMMENT '樓主uuid',
`create_time` char(19) NOT NULL DEFAULT '2000-01-01 00:00:00' COMMENT '帖子建立時間',
`last_update_time` char(19) DEFAULT NULL COMMENT '最後跟新時間',
`img` varchar(200) DEFAULT '0' COMMENT '圖片',
`texts` text COMMENT '正文',
PRIMARY KEY (`id`)
)
建立了一個表,但是有若干個uuid 和一個id,其實這些都是可以稱為候選鍵/候選碼,其實也可以看成是一個聯合主鍵,也就是說主鍵其實有幾個屬性。但是我們可以發現,其實title只取決於article_uuid,而texts和img等只取決於id,那其實就可以拆分成兩張表了:
CREATE TABLE1 `articles` (
`article_uuid` char(32) NOT NULL DEFAULT '0' COMMENT '文章uuid',
`title` varchar(200) NOT NULL DEFAULT '0' COMMENT '文章名',
`create_time` char(19) NOT NULL DEFAULT '2000-01-01 00:00:00' COMMENT '帖子建立時間',
`last_update_time` char(19) DEFAULT NULL COMMENT '最後跟新時間',
)
CREATE TABLE `articlesX` (
`id` int(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`user_uuid` char(32) NOT NULL DEFAULT '0' COMMENT '樓主uuid',
`create_time` char(19) NOT NULL DEFAULT '2000-01-01 00:00:00' COMMENT '帖子建立時間',
`last_update_time` char(19) DEFAULT NULL COMMENT '最後跟新時間',
`img` varchar(200) DEFAULT '0' COMMENT '圖片',
`texts` text COMMENT '正文',
PRIMARY KEY (`id`)
)
這就是符合第二正規化了。屬性不是依賴主鍵的一部分,實體的屬性完全依賴主鍵,不能依賴它的一部分!
第三正規化(3NF)
滿足第三正規化3NF的也是必須先滿足第二正規化2NF,第三正規化要求一個數據庫表中不包含已在其他表中已包含的非主關鍵字資訊。
也就是欄位冗餘性的約束,任何欄位不能由其他欄位派生,
舉例:
CREATE TABLE `bl_photo` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`photoName` varchar(200) DEFAULT NULL,
`photoPath` varchar(200) DEFAULT NULL,
`shrinkPhotoPath` varchar(200) DEFAULT NULL,
`photoSize` bigint(30) DEFAULT NULL,
`uploadTime` datetime DEFAULT NULL,
`downloadCounts` int(20) DEFAULT '0',
`photoId` varchar(255) DEFAULT NULL,
`uploadUserId` int(10) NOT NULL DEFAULT '0',
`adaptType` int(11) NOT NULL DEFAULT '4',
`checkStatus` int(10) NOT NULL DEFAULT '0',
`photoData` varchar(255) DEFAULT NULL,
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8;
這裡這個主鍵是id,這個屬性可以唯一確定其他所有屬性,知道了id就能知道圖片的名字,路徑,上傳時間等。
但是這裡還有個photo_id,它不是主鍵,但是我們又發現photoData 和 uploadUserId取決於這個候選碼,也就是說photoData依賴photo_id,photo_id依賴id。
這就存在了傳遞依賴。 資料冗餘~
解決:
拆分成兩個表:
CREATE TABLE `bl_photo` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`photoName` varchar(200) DEFAULT NULL,
`photoPath` varchar(200) DEFAULT NULL,
`shrinkPhotoPath` varchar(200) DEFAULT NULL,
`photoSize` bigint(30) DEFAULT NULL,
`uploadTime` datetime DEFAULT NULL,
`downloadCounts` int(20) DEFAULT '0',
`photoId` varchar(255) DEFAULT NULL,
`adaptType` int(11) NOT NULL DEFAULT '4',
`checkStatus` int(10) NOT NULL DEFAULT '0',
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8;
CREATE TABLE `XPhoto` (
`photoId` varchar(255) DEFAULT NULL,
`uploadUserId` int(10) NOT NULL DEFAULT '0',
`photoData` varchar(255) DEFAULT NULL,
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8;
我們在原來的表中刪除了依賴photo_id的屬性,然後新建一個表,這樣如果要搜尋依賴它的屬性,就利用資料庫連線來實現:
select p.id,p.photo_data,d.photo_data from bl_photo p,XPhoto d where p.photo_id=d.photo_id
缺點:
- 資料庫連線會帶來一部分的效能損失
- 並不是資料庫正規化越高越高
- 有時會在資料冗餘與正規化之間做出權衡,在實際的資料庫開發過程中,往往會允許一部分的資料冗餘來減少資料庫連線。
區分2NF和3NF
2NF:非主鍵列是否完全依賴於主鍵,還是依賴於主鍵的一部分,一般情況下如果主鍵是一個欄位那麼是滿足的,主鍵是聯合主鍵就要考慮了;(是否依賴主鍵的一部分)
3NF:非主鍵列是直接依賴於主鍵,還是直接依賴於非主鍵列。(是否直接依賴~!或者說多個依賴並存)