[TOC]
# 主 鍵
數據庫表中對儲存數據對象予以唯一和完整標識的數據列或屬性的組合。一個數據列只能有一個主鍵,
且主鍵的取值不能缺失,即不能為空值(Null)。
# 外 鍵
在一個表中存在的另一個表的主鍵稱此表的外鍵。
# 事務
數據庫中一個獨立的執行單元,通常由用戶編寫的程序執行而引起。當在數據庫中更改數據成功時,在
事務中更改的的數據便會提交,不再改變。否則,事務會取消或回滾,更改無效。
## 四個屬性
ACID,原子性,一致性,隔離性,持久性。
1. 原子性:事務是一個不可分割的整體,當數據修改時,要么全執行,要么全不執行,即不允許事務部分的完成。即不成功失敗,不能只運行其中一個。
2. 一致性:事務處理要將數據庫從一種狀態轉變為另一種狀態。一旦提交了修改數據,那么其它人讀取這個數據,也是被修改后的數據。例如:銀行轉賬,轉賬前后兩個賬戶總金額保持不變。
3. 隔離性:當兩個或者多個事務并發執行之后,為了保證數據的安全性,**需要將多個事務執行分隔開來**。多個用戶,不能同時讀寫同一個數據,應該有先后順序,在數據庫中是一個一 個事件地運行,如果事務的條件不滿足,后續事件就回滾。
6. 持久性:事件一旦提交成功,數據就發生了變化。
## 舉例
網上定票系統,扣錢和定票是一個事務,它需要有原子性即不能只運行扣錢不運行定票。符合原子性。
這張票被多人同時在網上定,就會有先來的才定上這個票,后來定票的動作,如果發現票已賣出,(票的狀態改變了,其它人通過網站訪問這個數據,就會發現票已賣出符合一致性),就會回滾到不扣錢,票訂不上的狀態。符合隔離性。
票被定了,在數據庫里設置標志位,它就一直顯示為賣出狀態。符合持久性。
# 事務鎖
數據庫鎖就是事務T在對某個數據對象(例如表、記錄等)操作之前,先向系統發出請求,對其加鎖。
加鎖后事務T就對該數據對象有了一定的控制,在事務T釋放它的鎖之前,其它的事務不能更新此數據對象。
數據庫鎖是實現并發控制的重要技術,但是“鎖”會帶來系統額外的開銷。所以需要注意選擇封鎖粒度時必須同時考慮開銷和并發度兩個因素,進行權衡,以求得最優的效果。
## 共享鎖
多個事務可封鎖一個共享頁;任何事務都不能修改該頁; 通常是該頁被讀取完畢,S鎖立即被釋放。
在執行select語句的時候需要給操作對象(表或者一些記錄)加上共享鎖,但加鎖之前需要檢查是否有排他鎖,如果沒有,則可以加共享鎖(一個對象上可以加n個共享鎖),否則不行。共享鎖通常在執行完select語句之后被釋放。
## 排他鎖
僅允許一個事務封鎖此頁;其他任何事務必須等到X鎖被釋放才能對該頁進行訪問;X鎖一直到事務結束才能被釋放。執行insert、update、delete語句的時候需要給操作的對象加排他鎖(我感覺在執行insert的時候應該是在表級加排他鎖),在加排他鎖之前必須確認該對象上沒有其他任何鎖,一旦加上排他鎖之后,就不能再給這個對象加其他任何鎖。
## 更新鎖
用來預定要對此頁施加X鎖,它允許其他事務讀,但不允許再施加U鎖或X鎖;當被讀取的頁將要被更
新時,則升級為X鎖;U鎖一直到事務結束時才能被釋放。
### 用處
若兩個事務同時對一個對象加共享鎖,當他們都想修改這個對象時,數據庫是支持在一個事務中進行自動鎖升級的,所以這兩個事務都想升級他們的鎖,但由于這個對象上存在對方事務加的共享鎖。所以無法升級。這樣兩個事務就在等待對方釋放共享鎖,進入死鎖狀態。
更新鎖就是為了解決這個問題,即在執行查詢操作的時候加的不是共享鎖而是更新鎖(一個對象上只能有一個更新鎖和n個共享鎖),當要更新的時候,再將更新鎖升級為排他鎖。
# 數據庫**沒有隔離級別時**的問題:
更新丟失:兩個線程要更改數據,同時獲取了原始值,A更新了后寫回,B更新后也寫回,這時A更新的內容就丟失了。
臟讀:當一個事務正在訪問數據,并且對數據進行了修改,而這種修改還沒有提交到數據庫中,這時,另外一個事務也訪問這個數據,然后使用了這個數據。
不可重復讀:一個事務對同一行數據重復讀取兩次,但是卻得到了不同的結果。即為幻讀,事務T1讀取某一數據后,事務T2對其做了修改,當事務T1再次讀該數據時得到與前一次不同的值。
# 數據庫的事務隔離級別:
1. 讀未提交:允許臟讀取,但不允許更新丟失。如果一個事務已經開始寫數據,則另外一個事務則不允許同時進行寫操作,但允許其他事務讀此行數據
2. 讀提交:允許不可重復讀取,但不允許臟讀取。讀取數據的事務允許其他事務繼續訪問該行數據,但是未提交的寫事務將會禁止其他事務訪問該行。
3. 可重復讀:禁止不可重復讀取和臟讀取。讀取數據的事務將會禁止寫事務(但允許讀事務),寫事務則禁止任何其他事務。
4. 串行化:提供嚴格的事務隔離。它要求事務序列化執行,事務只能一個接著一個地執行,但不能并發執行。
# 連接:分為內連接和外連接
內連接:返回的結果集選取了兩個表中所有匹配的數據,舍棄了不匹配的數據。
例子:
```sql
select tlb_a.sid , tlb_b.name
from tlb_a inner join tlb_b
on tlb_a.id = tlb_b.id
```
左外連接:結果集包含左表的所有行,如果左表的某行在右表中沒有匹配行,則在結果集中右表對應行為空。
例子:
```sql
select tlb_a.sid , tlb_b.name
from tlb_a left join tlb_b
on tlb_a.id = tlb_b.id
```
右連接同上
# 數據庫范式
冗余:在設計數據庫時,某一字段屬于一個表,但它又同時出現在另一個或多個表,且完全等同于它在其本
來所屬表的意義表示,那么這個字段就是一個[冗余字段](http://www.blueidea.com/tech/program/2011/8311.asp)
情景一:只在name表中有nickname,這樣修改nickname時,只需要改這個表
情景二:想要根據id查找nickname,則需要使用join,當數據很多時,這樣很費時
所有關系型數據庫均滿足第一范式
第一范式:屬性不可分。指數據庫表的每一列都是不可分割的基本數據項,同一列中不能有多個值,即實體中的某個屬性不能有多個值或者不能有重復的屬性。如表中聯系方式字段,不能既有座機號碼,又有手機號碼
第二范式:符合1NF,并且,非主屬性完全依賴于碼。
主屬性:一個屬性只要在任何一個候選碼中出現過,這個屬性就是主屬性。
非主屬性:與上面相反,沒有在任何候選碼中出現過,這個屬性就是非主屬性。
不能存在一個非主屬性部分依賴于碼,比如一個表中,主碼是課程和學生,但是課程可以確定教材。
三種異常:
有什么不好嗎?你可以想想:
1、校長要新增加一門課程叫“微積分”,教材是《大學數學》,怎么辦?學生還沒選課,而學生又是主
屬性,主屬性不能空,課程怎么記錄呢,教材記到哪呢? ……郁悶了吧?(插入異常)
2、下學期沒學生學一年級語文(上)了,學一年級語文(下)去了,那么表中將不存在一年級語文
(上),也就沒了《小學語文1》。這時候,校長問:一年級語文(上)用的什么教材啊?……郁悶了
吧?(刪除異常)
3、校長說:一年級語文(上)換教材,換成《大學語文》。有10000個學生選了這么課,改動好大
啊!改累死了……郁悶了吧?(修改異常)
第三范式:數據表中如果不存在非關鍵字段對任一候選關鍵字段的傳遞函數依賴則符合第三范式
出現傳遞依賴A->B->C,即主鍵A可以確定出某一非關鍵字段B,而B又可以確定出C,這意味著C依賴于一個非關鍵字段B。因此第三范式又可描述為:表中不存在可以確定其他非關鍵字的非鍵字段。
問題就出在“老師”和“老師職稱”這里。一個老師一定能確定一個老師職稱。
有什么問題嗎?想想:
1、老師升級了,變教授了,要改數據庫,表中有N條,改了N次……(修改異常)
2、沒人選這個老師的課了,老師的職稱也沒了記錄……(刪除異常)
3、新來一個老師,還沒分配教什么課,他的職稱記到哪?……(插入異常)
## BC范式:符合3NF,并且,主屬性不依賴于主屬性
視圖:從數據庫中選取出來的數據組成的邏輯窗口,是一個虛表。在數據庫中,存放的只是視圖的定義,而不包括的數據項
好處:
1. 當查詢時使用復雜的sql語句
2. 可以把各個表之間復雜的操作和連接對用戶隱藏
例子:
~~~
create view del as
select 職工號,姓名,部門名稱,負責人 from work1,部門
where work1.部門編號=部門.部門編號
~~~
觸發器
觸發器是一種與表操作有關的數據庫對象,當觸發器所在表上出現指定事件時,將調用該對象,即表的操作事件觸發表上的觸發器的執行語法:
~~~
CREATE TRIGGER trigger_name
trigger_time
trigger_event ON tbl_name
FOR EACH ROW
trigger_stmt
~~~
> trigger_name:標識觸發器名稱,用戶自行指定;
trigger_time:標識觸發時機,取值為 BEFORE 或 AFTER;
trigger_event:標識觸發事件,取值為 INSERT、UPDATE 或 DELETE;
tbl_name:標識建立觸發器的表名,即在哪張表上建立觸發器;
trigger_stmt:觸發器程序體,可以是一句SQL語句,或者用 BEGIN 和 END 包含的多條語句。
其中,statement_list 代表一個或多個語句的列表,列表內的每條語句都必須用分號(;)來結尾。
而在MySQL中,分號是語句結束的標識符,遇到分號表示該段語句已經結束,MySQL可以開始執行了。因此,解釋器遇到statement_list 中的分號后就開始執行,然后會報出錯誤,因為沒有找到和 BEGIN 匹配的END。
這時就會用到 DELIMITER 命令(DELIMITER 是定界符,分隔符的意思),它是一條命令,不需要語句結束標識,語法為:
~~~
DELIMITER new_delemiter
~~~
`new_delemiter` 可以設為1個或多個長度的符號,默認的是分號(`;`),我們可以把它修改為其他符號,如`$`:
~~~
DELIMITER $
~~~
> [MySQL的學習--觸發器](http://www.cnblogs.com/CraryPrimitiveMan/p/4206942.html)
# 存儲過程和函數
sql語句在執行之前要先編譯再執行。為了提高效率,將為了完成特定功能的語句集編譯優化后放在數據庫服務器中。
使用存儲過程可以,傳遞參數并可以使用流程控制語句
## 與函數的區別
1. 函數可以作為查詢的一部分,存儲過程是獨立的一部分
2. 存儲過程在創建時就編譯了,速度比函數快
# 索引
B-樹是一種平衡的多路查找樹,它在文件系統中很有用。
定義:一棵m 階的B-樹,或者為空樹,或為滿足下列特性的`m 叉樹`:
1. 樹中每個結點至多有m 棵子樹;
2. 若根結點不是葉子結點,則至少有兩棵子樹;
3. 除根結點之外的所有非終端結點至少有[m/2] 棵子樹;
4. 所有的非終端結點中包含以下信息數據:
~~~
(n,A0,K1,A1,K2,…,Kn,An)
~~~
其中:`Ki(i=1,2,…,n)`為關鍵碼,且`Ki<Ki+1`,
`Ai` 為指向子樹根結點的指針`(i=0,1,…,n)`,且指針`Ai-1` 所指子樹中所有結點的關鍵碼均小于`Ki (i=1,2,…,n)`,
`An` 所指子樹中所有結點的關鍵碼均大于`Kn`.
`n` 為關鍵碼的個數。
5. 所有的葉子結點都出現在同一層次上,并且不帶信息(可以看作是外部結點或查找失敗的結點,實際上這些結點不存在,指向這些結點的指針為空)
B+樹是應文件系統所需而產生的一種B-樹的變形樹。
一棵m 階的B+樹和m 階的B-樹的差異在于:
1. 有n 棵子樹的結點中含有n 個關鍵碼;
2. 所有的葉子結點中包含了全部關鍵碼的信息,及指向含有這些關鍵碼記錄的指針,且葉子結點本身依關鍵碼的大小自小而大的順序鏈接。
3. 所有的非終端結點可以看成是索引部分,結點中僅含有其子樹根結點中最大(或最小)關鍵碼。
通常在B+樹上有兩個頭指針,一個指向根節點,另一個指向關鍵字最小的葉子節點。因此可以對B+樹進行兩種
查找運算:一種是從最小關鍵字起順序查找,另一種是從根節點開始,進行隨機查找。
## 為什么使用B-Tree(B+Tree)
二叉查找樹進化品種的紅黑樹等數據結構也可以用來實現索引,但是文件系統及數據庫系統普遍采用B-/+Tree作為索引結構。
一般來說,索引本身也很大,不可能全部存儲在內存中,因此索引往往以索引文件的形式存儲的磁盤上。這樣的話,索引查找過程中就要產生磁盤I/O消耗,相對于內存存取,I/O存取的消耗要高幾個數量級,所以評價一個數據結構作為索引的優劣最重要的指標就是在查找過程中磁盤I/O操作次數的漸進復雜度。換句話說,索引的結構組織要盡量減少查找過程中磁盤I/O的存取次數。為什么使用B-/+Tree,還跟磁盤存取原理有關。
## 局部性原理與磁盤預讀
磁盤往往不是嚴格按需讀取,而是每次都會預讀,即使只需要一個字節,磁盤也會從這個位置開始,順序向后讀取一定長度的數據放入內存。這樣做的理論依據是計算機科學中著名的局部性原理:當一個數據被用到時,其附近的數據也通常會馬上被使用。
預讀的長度一般為頁(page),磁盤會找到數據的起始位置并向后連續讀取一頁或幾頁載入內存中。
數據庫系統巧妙利用了磁盤預讀原理,將一個節點的大小設為等于一個頁,這樣每個節點只需要一次I/O就可以完全載入。
B-Tree中一次檢索最多需要`h-1`次I/O(根節點常駐內存),而紅黑樹這種結構,`h`明顯要深的多。
在 MySQL 中,主要有四種類型的索引:
B-Tree 索引, Hash 索引, Fulltext 索引和 R-Tree 索引。
> [MySQL索引背后的數據結構及算法原理](http://blog.codinglabs.org/articles/theory-of-mysql-index.html)
## Mysql B樹索引有哪些?
### 普通索引
這是最基本的索引類型,而且它沒有唯一性之類的限制。普通索引可以通過以下幾種方式創建:
(1)創建索引: CREATE INDEX 索引名 ON 表名(列名1,列名2,...);
(2)修改表: ALTER TABLE 表名ADD INDEX 索引名 (列名1,列名2,...);
(3)創建表時指定索引:CREATE TABLE 表名 ( [...], INDEX 索引名 (列名1,列名 2,...) );
### UNIQUE索引
表示唯一的,不允許重復的索引,如果該字段信息保證不會重復例如身份證號用作索引時,可設置為`unique`:
(1)創建索引:`CREATE UNIQUE INDEX 索引名 ON 表名(列的列表)`;
(2)修改表:`ALTER TABLE 表名ADD UNIQUE 索引名 (列的列表)`;
(3)創建表時指定索引:`CREATE TABLE 表名( [...], UNIQUE 索引名 (列的列表) )`;
### 主鍵:PRIMARY KEY索引
主鍵是一種唯一性索引,但它必須指定為`PRIMARY KEY`。
(1)主鍵一般在創建表的時候指定:`CREATE TABLE 表名( [...], PRIMARY KEY (列的列表) );`。
(2)但是,我們也可以通過修改表的方式加入主鍵:`ALTER TABLE 表名ADD PRIMARY KEY (列的列表); `。
每個表只能有一個主鍵。 (主鍵相當于聚合索引,是查找最快的索引)
# MySql存儲引擎
1. MyISAM:有較高的插入、查詢速度,但不支持事務,數據文件和索引文件可以在不同的目錄,5.5.5版本
2. 前是默認引擎
3. InnoDB:支持事務的ACID屬性,給MySql提供了提交、回滾和崩潰的恢復事務能力,新版本的默認引擎
4. Memory