資料庫的正規化、連線、鎖等知識點梳理
資料庫的三大正規化
在資料庫的表設計中我們需要遵守一些規範,以達到資料庫結構合理,查詢高效,刪改無誤的目標。
一、資料庫的第一正規化:在設計表格的欄位時,要確保欄位的原子性(即不可再分),比如電話號碼這個欄位名的表意就不是很明確,它是指家庭電話還是個人手機電話呢?欄位的原子性保證了我們在查詢資料時的高效和準確。這也是關係型資料庫比如MySQL資料庫的設計要求。
二、資料庫第二正規化:在滿足第一正規化的基礎上,我們還需要滿足第二正規化,即各個欄位都應該依賴主鍵,且不能依賴於主鍵的一部分,我們可以通過主鍵唯一確定我們要查詢的內容。我們舉一個例子,現給出一些資訊:學號、姓名、課名、分數、系名、系主任。
接下來我們先介紹一下超鍵、候選鍵、主鍵的概念:
超鍵:能夠唯一標識元組(一條記錄)的屬性組合,超鍵的要求比較寬泛,因此只要通過它能唯一標識元祖就可以了,在一張資訊表中超鍵有多種組合形式。
候選鍵:候選鍵是特殊的超鍵,它也能唯一標識元祖,但是候選鍵中的屬性都不能去掉,去掉其中的任一屬性,它就不屬於超鍵了。
主鍵:候選鍵顧名思義是“候選者”,它是主鍵的候選者,使用者可以在候選鍵中選擇一個作為主鍵。
主屬性和非主屬性:包含在鍵中的屬性稱為主屬性,其餘屬性為非主屬性。
另外再闡述一下依賴的概念:當屬性A確定後,屬性B也唯一確定,那麼稱屬性B依賴於屬性A。
我們再來看看上面的例子。可以唯一標識元組的屬性組合是學號和課程,我們選擇它作為主鍵。通過學號和課程,我們可以確定分數;另外通過學號我們可以確定姓名、系名、系主任,系名也可以確定系主任。做出如下關係圖:
這些屬性不可再分,所以他們是滿足第一正規化的,但它存在非主屬性對鍵的部分依賴,在上圖中我們可以發現,姓名、系名、系主任是可以通過學號這個主屬性來確定的,第二正規化的要求是所有非主屬性都是依賴主鍵,不允許部分依賴。解決這個問題的方案是把這個表劃分為兩張字表,即單獨把學號拿出來作為姓名、系名、系主任的主鍵。如圖:
這樣便消除了部分依賴的關係了。這可以防止一些資料的冗餘,以及資料的插入刪除可以導致的錯誤。
三、資料庫的第三正規化:我們繼續在上述例子的基礎上挖深,上面用紅色線標識的關係可以表示系主任這個屬性是依賴於學號的,同時系主任也可以通過系名唯一確定,系名由學號唯一確定,這時發生了依賴的傳遞。主鍵是學號,元祖可以通過學號來唯一確定,但是我們可以假設這樣一種情況:如果一個新成立的系,還沒有開始招收學生,資料表中沒有資料,是不是就表示這個系不存在了?不是的,這時我們需要把系和學號分離開來。資料庫第三正規化的要求是表中不能存在傳遞依賴的關係,這使得表格的邏輯不清,資料的儲存也會出現錯誤。解決問題的思路依然是對錶格進行劃分。如圖:
在一個新系成立後,可以在表三新增系名和系主任,招生之後可以新增學號、系名、姓名的對應關係,學生選課後再新增學號課名到分數的對應關係,邏輯清晰,層次分明,滿足第三正規化。
資料庫的左連線、右連線、內連線
左連線: 例如:select * from tbl1 Left Join tbl2 where tbl1.ID = tbl2.ID 。選擇需要連線的兩張表,Left Join來表示採用了左連線,連線後的表結構是按照上式中的表順序的,tbl1在左,tbl2在右,左連線是指把右表合併到左表,關聯兩表的因素自然是兩表的欄位。上面這句話的意思是把兩張表ID相同的部分連線起來。左連線對錶一不做任何修改,在表二中找到和表一ID屬性匹配的記錄,拼接到表一相應記錄的後方。此時原表變長了,表二拼接上去後,其他匹配不到的資料部分都用null表示,此時記錄之間的順序可以簡單調整,匹配到的記錄移到上方。
右連線:
內連線: 例如:select * from tbl1 inner join tbl2 on tbl1.ID = tbl2.ID。最終得到的表是兩者的公共部分(類似於交集)。
作用: 這幾種連線方式可以使得我們在查詢成績的時候有所偏重的去查詢,比如學生資訊和課程成績兩張表的查詢,如果我們以學生資訊表為主,如果學生資訊表中沒有某同學,那麼左連線時即便他有成績也不會顯示在最終表中;反之,如果以成績為準,如果沒有某同學的成績記錄,右連線時是不會顯示這個同學的資訊的。這種查詢方式使得對錶資訊的篩選效率大大的提高了。
MySQL的樂觀鎖和悲觀鎖
樂觀鎖: 顧名思義,MySQL在對錶格處理時是抱著樂觀的態度的,它認為不會有別人在自己操作的時候去修改記錄資料,唯一做的事是在操作前取出表單的版本號,最後要更新資料的時候再取版本號比對,觀察在這期間是不是有別人操作過資料庫導致版本號的更新(+1),如果沒有人動過資料庫,那麼它就可以更新資料了。樂觀鎖是人為實現的,而不是是資料庫自帶的。
悲觀鎖: 持悲觀的態度,認為在自己操作的時候會有別人操作資料,所以在自己操作之前,先給表上鎖,結束之後再釋放鎖,這個鎖是MySQL自帶的,通過相應配置即可實現。我們既可以為表加表鎖,也可以為行加行鎖。
兩種鎖的分析比較: 一般樂觀鎖操作時效率較高,只是簡單檢查版本號便可以實現安全的操作,悲觀鎖在每次處理時需要上鎖,這必然會帶來一些資源的開銷。一般樂觀鎖被廣泛使用,因為其簡單高效;而悲觀鎖在高併發且易出現資源競爭的情況下會比樂觀鎖更有優勢,因為如果經常競爭性地對錶進行操作,在樂觀鎖的情況下容易出現操作失效,降低了效率,而悲觀鎖可以確保指令的執行,可靠性好。
MySQL語句知識點擴充套件
1、SELECT DISTINCT “欄位名” FROM “表格名”
作用:在篩選的同時去掉重複的內容。
2、SELECT “欄位名” FROM “表格名” WHERE “簡單條件” { [AND|OR] “簡單條件” }
作用:多條件篩選。
3、SELECT “欄位名” FROM “表格名” WHERE “欄位名” IN (‘值一’,‘值二’…)
SELECT “欄位名” FROM “表格名” WHERE “欄位名” BETWEEN ‘值一’ AND ‘值二’
作用:查詢指定欄目的內容,同時滿足其他欄目的某些條件。
4、select * from table1 where name like ‘%明%’ //含有“明”字的
select * from table1 where name like ‘%[0-9]%’ //含有數字的
select * from table1 where name like ‘%[a-z]%’ //含有小寫字母的
select * from table1 where name like ‘%[!0-9]%’ //不含數字的
作用:模糊查詢含有指定內容的記錄。
5、SELECT “欄位名” FROM “表格名” WHERE “簡單條件” ORDER BY “欄位名” [ASC,DESC]
作用:篩選後降序(DESC)或者升序(ASC)排列。
6、SELECT COUNT “欄位名” FROM “表格名”
作用:查詢表中記錄的行數。
7、SELECT “欄位名1”,SUM “欄位名2” FROM “表格名” GROUP BY “欄位1”
作用:把欄目2中資料按照欄目1的內容計算合計值,合併欄目1中相同的部分。
8、SELECT “欄位名1”,SUM “欄位名2” FROM “表格名” GROUP BY “欄位1” HAVING(函式條件)
作用:在上題的基礎上,另加函式條件約束。
常見完整性約束:
非空約束:not null
唯一約束:unique
主鍵約束:primary key
外來鍵約束:foreign key
檢查約束:check (確保新增內容在check約束範圍內)
新增非空約束:modify(score number(10,2) not null)
刪除非空約束:drop constraint std1_id_nn ;
加入檢查約束:add(constraint std1_score_ck check(score>=0 and score<=100)) ;
有效化無效化約束:disable 、enable
級聯刪除:ON DELETE CASCADE (當父表中的列被刪除時,字表中相對應的列也被刪除)
級聯置空:ON DELETE SET NULL (當父表中的列被刪除時,字表中相對應的列被置空)