【面試】數據庫原理

什麼是數據庫

數據庫簡單來講就是存放數據的地方,面試過程中,數據庫一般都會被問到,這裏主要是自己查閱的資料和一些總結,主要爲了鞏固下自己的對數據庫的理解和認識。這裏主要結合MySQL數據庫進行整理。

存儲過程(Store Procedure)

MySQL數據庫是一種常用的關係型數據庫,操作語言是SQL語句,SQL語句一般在執行的時候需要先編譯,然後執行。而存儲過程一般是有預先定義的SQL語句集,經編譯後存儲在數據庫中,用戶指定存儲過程的名字並給定參數(如果存儲過程有參數的話),然後直接可以執行。
一個存儲過程像是一個可編程的函數,它在數據庫中創建並保存,由SQL語句和一些控制結構組成。
當希望在不同的應用程序或平臺上執行相同的函數,或者封裝特定功能時,存儲過程是非常有用的。數據庫中的存儲過程可以看做是對面向對象方法的模擬,它允許控制數據的訪問方式。

存儲過程的優點

(1)存儲過程增強了SQL語言的功能和靈活性:存儲過程可以用流控制語句編寫,有很強的靈活性,可以完成複雜的判斷和較複雜的運算。
(2)存儲過程允許標準組件式編程:存儲過程被創建後,可以在程序中被多次調用,而不必重新編寫該存儲過程的SQL語句。而且可以隨時對存儲過程進行修改,對應用程序源代碼毫無影響。
(3)存儲過程能實現較快的執行速度:如果某一操作包含大量的Transaction-SQL代碼或分別被多次執行,那麼存儲過程要比批處理的執行速度快很多。因爲存儲過程是預編譯的。在首次運行一個存儲過程時,優化器對其進行分析優化,並且給出最終被存儲在系統表中的執行計劃。而批處理的Transaction-SQL語句在每次運行時都要進行編譯和優化,速度相對要慢一些。
(4)存儲過程能減少網絡流量:針對同一個數據庫對象的操作(如查詢、修改),如果這一操作所涉及的Transaction-SQL語句被組織成存儲過程,那麼當在客戶計算機上調用該存儲過程時,網絡中傳送的只是該調用語句,從而大大增加了網絡流量並降低了網絡負載。
(5)存儲過程可被作爲一種安全機制來充分利用:系統管理員通過執行某一存儲過程的權限進行限制,能夠實現對相應的數據的訪問權限的限制,避免了非授權用戶對數據的訪問,保證了數據的安全。

索引

有過編程經驗的同學,一提起索引並不陌生,其實就是幫助我們高效進行數據訪問的方式。在數據庫中,索引指的是幫助MySQL高效獲取數據的數據結構;簡要來說,在數據之外,數據庫系統還維護着滿足特定查找算法的數據結構,這些數據結構以某種方式引用(指向)數據,可以在這些數據結構上實現高級查找算法,提高查詢速度,這種數據結構,就是索引。

索引存儲分類

索引是在MySQL的存儲引擎層中實現的,而不是在服務層實現的。所以各種存儲引擎支持的索引並不相同,MySQL目前提供了以下4種索引。
1 B-Tree 索引:最常見的索引類型,大部分引擎都支持B樹索引。
2 HASH 索引:只有Memory引擎支持,使用場景簡單。
3 R-Tree索引(空間索引):空間索引是MyISAM的一種特殊索引類型,主要用於地理空間數據類型。
4 Full-text (全文索引):全文索引也是MyISAM的一種特殊索引類型,主要用於全文索引,InnoDB從MySQL5.6版本提供對全文索引的支持。

B-TREE索引

這個是通用的索引存儲方式,主要包括以下三種常用的形式:
1 普通索引
這是最基本的索引類型,而且它沒有唯一性之類的限制,可以通過以下幾種方式創建:
(1)創建索引: CREATE INDEX 索引名 ON 表名(列名1,列名2,…);
(2)修改表: ALTER TABLE 表名 ADD INDEX 索引名 (列名1,列名2,…);
(3)創建表時指定索引:CREATE TABLE 表名 ( […], INDEX 索引名 (列名1,列名 2,…) );
2 UNIQUE索引
表示唯一的,不允許重複的索引,若某一字段的信息不能重複(例如身份證號),可以將該字段的索引設置爲unique:
(1)創建索引:CREATE UNIQUE INDEX 索引名 ON 表名(列名1,列名2,…);
(2)修改表:ALTER TABLE 表名ADD UNIQUE 索引名 (列名1,列名2,…);
(3)創建表時指定索引:CREATE TABLE 表名( […], UNIQUE 索引名 (列名1,列名2,…));
3 主鍵:PRIMARY KEY索引
主鍵是一種唯一性索引,但它必須指定爲“PRIMARY KEY”。可以將其理解爲 索引名固定爲 PRIMARY KEY 的 UNIQUE索引。
(1)主鍵一般在創建表的時候指定:“CREATE TABLE 表名( […], PRIMARY KEY (列的列表) ); ”。
(2)但是,我們也可以通過修改表的方式加入主鍵:“ALTER TABLE 表名 ADD PRIMARY KEY (列的列表); ”。
每個表只能有一個主鍵。 (主鍵相當於聚合索引,是查找最快的索引)
注:不能用CREATE INDEX語句創建PRIMARY KEY索引

常用語法
設置索引

在執行CREATE TABLE語句時可以創建索引,也可以單獨用CREATE INDEX或ALTER TABLE來爲數據表增加索引。
1.ALTER TABLE - ALTER TABLE可以用來創建普通索引、UNIQUE索引或PRIMARY KEY索引。
ALTER TABLE table_name ADD INDEX index_name (column_list)
ALTER TABLE table_name ADD UNIQUE index_name (column_list)
ALTER TABLE table_name ADD PRIMARY KEY (column_list)
2.CREATE INDEX - CREATE INDEX可對錶增加普通索引或UNIQUE索引。
CREATE INDEX index_name ON table_name (column_list)
CREATE UNIQUE INDEX index_name ON table_name (column_list)

刪除索引

可利用ALTER TABLE或DROP INDEX語句來刪除索引。類似於CREATE INDEX語句,DROP INDEX可以在ALTER
TABLE內部作爲一條語句處理,語法如下。
DROP INDEX index_name ON talbe_name
ALTER TABLE table_name DROP INDEX index_name
ALTER TABLE table_name DROP PRIMARY KEY

其中,前兩條語句是等價的,刪除掉table_name中名爲index_name的索引。 第3條語句只在刪除PRIMARY
KEY索引時使用,因爲一個表只可能有一個PRIMARY KEY索引,因此不需要指定索引名。如果沒有創建PRIMARY
KEY索引,但表具有一個或多個UNIQUE索引,則MySQL將刪除第一個UNIQUE索引。
如果從表中刪除了某列,則索引會受到影響。對於多列組合的索引,如果刪除其中的某列,則該列也會從索引中刪除。如果刪除組成索引的所有列,則整個索引將被刪除。

查看索引

show index from tblname;
在這裏插入圖片描述

設置索引的原則

1 較頻繁的作爲查詢條件的字段應該創建索引
2 唯一性太差的字段不適合單獨創建索引,即使頻繁作爲查詢條件
3 更新非常頻繁的字段不適合創建索引
4 不會出現在 WHERE 子句中的字段不該創建索引
5 索引的選擇性較低不宜建索引
注:所謂索引的選擇性(Selectivity),是指不重複的索引值(也叫基數,Cardinality)與表記錄數的比值,顯然選擇性的取值範圍爲(0, 1]:
命令:SELECT count(DISTINCT(column_name))/count(*) AS Selectivity FROM table_name;
在這裏插入圖片描述

索引的弊端

索引是一種空間換時間的操作,是有代價的:索引文件本身要消耗存儲空間,同時索引會加重插入、刪除和修改記錄時的負擔,另外,MySQL在運行時也要消耗資源維護索引,因此索引並不是越多越好。

平衡多路查找樹——B-Tree

B-Tree是爲磁盤等外存儲設備設計的一種平衡查找樹
系統從磁盤讀取數據到內存時是以磁盤塊(block)爲基本單位的,位於同一個磁盤塊中的數據會被一次性讀取出來,而不是需要什麼取什麼。
InnoDB存儲引擎中有頁(Page)的概念,頁是其磁盤管理的最小單位。InnoDB存儲引擎中默認每個頁的大小爲16KB,可通過參數innodb_page_size將頁的大小設置爲4K、8K、16K,在MySQL中可通過如下命令查看頁的大小:
show variables like ‘innodb_page_size’;
在這裏插入圖片描述
而系統一個磁盤塊的存儲空間往往沒有這麼大,因此InnoDB每次申請磁盤空間時都會是若干地址連續磁盤塊來達到頁的大小16KB。InnoDB在把磁盤數據讀入到磁盤時會以頁爲基本單位,在查詢數據時如果一個頁中的每條數據都能有助於定位數據記錄的位置,這將會減少磁盤I/O次數,提高查詢效率。
B-Tree結構的數據可以讓系統高效的找到數據所在的磁盤塊。

爲了描述B-Tree,首先定義一條記錄爲一個二元組[key, data] ,key爲記錄的鍵值,對應表中的主鍵值,data爲一行記錄中除主鍵外的數據。對於不同的記錄,key值互不相同。
一棵m階的B-Tree有如下特性:

  1. 每個節點最多有m個孩子。
  2. 除了根節點和葉子節點外,其它每個節點至少有Ceil(m/2)個孩子。
  3. 若根節點不是葉子節點,則至少有2個孩子
  4. 所有葉子節點都在同一層,且不包含其它關鍵字信息
  5. 每個非終端節點包含n個關鍵字信息(P0,P1,…Pn, k1,…kn)
  6. 關鍵字的個數n滿足:ceil(m/2)-1 <= n <= m-1
  7. ki(i=1,…n)爲關鍵字,且關鍵字升序排序。
  8. Pi(i=1,…n)爲指向子樹根節點的指針。P(i-1)指向的子樹的所有節點關鍵字均小於ki,但都大於k(i-1)

B-Tree中的每個節點根據實際情況可以包含大量的關鍵字信息和分支,如下圖所示爲一個3階的B-Tree:

在這裏插入圖片描述
每個節點佔用一個盤塊的磁盤空間,一個節點上有兩個升序排序的關鍵字和三個指向子樹根節點的指針,指針存儲的是子節點所在磁盤塊的地址。兩個關鍵詞劃分成的三個範圍域對應三個指針指向的子樹的數據的範圍域。以根節點爲例,關鍵字爲17和35,P1指針指向的子樹的數據範圍爲小於17,P2指針指向的子樹的數據範圍爲17~35,P3指針指向的子樹的數據範圍爲大於35。

如何使用b-tree查找數據

模擬查找關鍵字29的過程:

根據根節點找到磁盤塊1,讀入內存。【磁盤I/O操作第1次】
比較關鍵字29在區間(17,35),找到磁盤塊1的指針P2。
根據P2指針找到磁盤塊3,讀入內存。【磁盤I/O操作第2次】
比較關鍵字29在區間(26,30),找到磁盤塊3的指針P2。
根據P2指針找到磁盤塊8,讀入內存。【磁盤I/O操作第3次】
在磁盤塊8中的關鍵字列表中找到關鍵字29。
分析上面過程,發現需要3次磁盤I/O操作,和3次內存查找操作。由於內存中的關鍵字是一個有序表結構,可以利用二分法查找提高效率。而3次磁盤I/O操作是影響整個B-Tree查找效率的決定因素。B-Tree相對於AVLTree縮減了節點個數,使每次磁盤I/O取到內存的數據都發揮了作用,從而提高了查詢效率。

B+樹

B+Tree是在B-Tree基礎上的一種優化,使其更適合實現外存儲索引結構,InnoDB存儲引擎就是用B+Tree實現其索引結構。

相較於B-Tree

從上一節中的B-Tree結構圖中可以看到每個節點中不僅包含數據的key值,還有data值。而每一個頁的存儲空間是有限的,如果data數據較大時將會導致每個節點(即一個頁)能存儲的key的數量很小,當存儲的數據量很大時同樣會導致B-Tree的深度較大,增大查詢時的磁盤I/O次數,進而影響查詢效率。在B+Tree中,所有數據記錄節點都是按照鍵值大小順序存放在同一層的葉子節點上,而非葉子節點上只存儲key值信息,這樣可以大大加大每個節點存儲的key值數量,降低B+Tree的高度。

B+Tree相對於B-Tree有幾點不同:

1 非葉子節點只存儲鍵值信息。
2 所有葉子節點之間都有一個鏈指針。
3 數據記錄都存放在葉子節點中

舉例

在這裏插入圖片描述

1.通常在B+Tree上有兩個頭指針,一個指向根節點,另一個指向關鍵字最小的葉子節點。
2. 而且所有葉子節點(即數據節點)之間是一種鏈式環結構。
3.因此可以對B+Tree進行兩種查找運算:
3.1一種是對於主鍵的範圍查找和分頁查找
3.2 另一種是從根節點開始,進行隨機查找。
InnoDB存儲引擎中頁的大小爲16KB,一般表的主鍵類型爲INT(佔用4個字節)或BIGINT(佔用8個字節),指針類型也一般爲4或8個字節,也就是說一個頁(B+Tree中的一個節點)中大概存儲16KB/(8B+8B)=1K個鍵值(因爲是估值,爲方便計算,這裏的K取值爲〖10〗^3)。
也就是說一個深度爲3的B+Tree索引可以維護10^3 * 10^3 * 10^3 = 10億 條記錄。
實際情況中每個節點可能不能填充滿,因此在數據庫中,B+Tree的高度一般都在2-4層。mysql的InnoDB存儲引擎在設計時是將根節點常駐內存的,也就是說查找某一鍵值的行記錄時最多隻需要1~3次磁盤I/O操作。

事務

事務(Transaction)是併發控制的基本單位。所謂的事務,它是一個操作序列,由一條或者多條sql語句組成,這些操作要麼都執行,要麼都不執行,它是一個不可分割的工作單位。

事務的特性-ACID

事務應該具有4個屬性:原子性、一致性、隔離性、持久性。
1 原子性(Atomicity):指整個數據庫事務是不可分割的工作單位。只有事務中所有的數據庫操作都執行成功,整個事務的執行纔算成功。事務中任何一個sql語句執行失敗,那麼已經執行成功的sql語句也必須撤銷,數據庫狀態應該退回到執行事務前的狀態。
2 一致性(Consistency):事務應確保數據庫的狀態從一個一致狀態轉變爲另一個一致狀態。一致狀態的含義是數據庫中的數據應滿足完整性約束,也就是說在事務開始之前和事務結束以後,數據庫的完整性約束沒有被破壞
3 隔離性(Isolation):隔離性也叫做併發控制、可串行化或者鎖。事務的隔離性要求每個讀寫事務的對象與其它事務的操作對象能相互分離,即該事務提交前對其它事務都不可見,這通常使用鎖來實現多個事務併發執行時,一個事務的執行不應影響其他事務的執行。
4 持久性(Durability):表示事務一旦提交了,其結果就是永久性的,也就是數據就已經寫入到數據庫了,如果發生了宕機等事故,數據庫也能將數據恢復。

事務的分類

1 扁平事務;
扁平事務是最簡單的一種,也是實際開發中使用的最多的一種事務。在這種事務中,所有操作都處於同一層次,最常見的方式如下:

 BEGIN WORK
     Operation 1
     Operation 2
     Operation 3
     ...
     Operation N
 COMMIT WORK

或者

BEGIN WORK
     Operation 1
     Operation 2
     Operation 3
     ...
     Operation N
     (Error Occured)
 ROLLBACK WORK

扁平事務很簡單,但有一個主要缺點是不能提交或回滾事務的某一部分,或者分幾個獨立的步驟去提交。
比如有這樣的一個例子,我從呼和浩特去深圳,爲了便宜,我可能這麼幹:

BEGIN WORK
	Operation1:呼和浩特---火車--->北京
     Operation2:北京---飛機--->深圳
 ROLLBACK WORK

但是,如果在Operation1中,從呼和浩特到北京的火車晚點了,錯過了航班,怎麼辦?因爲扁平事務的特性,那我就需要回滾,我需要再回到呼和浩特,這樣做的成本太高,

2 帶有保存點的扁平事務;
這種事務除了支持扁平事務支持的操作外,允許在事務執行過程中回滾到同一事務中較早的一個狀態,這是因爲可能某些事務在執行過程中出現的錯誤並不會對所有的操作都無效,放棄整個事務不合乎要求,開銷也太大。保存點用來通知系統應該記住事務當前的狀態,以便以後發生錯誤時,事務能回到該狀態。

3 鏈事務;
鏈事務,就是指回滾時,只能恢復到最近一個保存點;而帶有保存點的扁平事務則可以回滾到任意正確的保存點。

4 嵌套事務;

BEGIN WORK
     SubTransaction1:
             BEGIN WORK
                 SubOperationX
             COMMIT WORK
     SubTransaction2:
             BEGIN WORK
                 SubOperationY
             COMMIT WORK
     ...
     SubTransactionN:
             BEGIN WORK
                 SubOperationN
             COMMIT WORK
 COMMIT WORK

這就是嵌套事務,在事務中再嵌套事務,位於根節點的事務稱爲頂層事務。事務的前驅稱爲父事務,事務的下一層稱爲子事務。

子事務既可以提交也可以回滾,但是它的提交操作並不馬上生效,除非由其父事務提交。因此就可以確定,任何子事務都在頂層事務提交後才真正的被提交了。同理,任意一個事務的回滾都會引起它的所有子事務一同回滾。

5 分佈式事務
分佈式事務通常是指在一個分佈式環境下運行的扁平事務,因此需要根據數據所在位置訪問網絡中的不同節點,比如:通過建設銀行向招商銀行轉賬,建設銀行和招商銀行肯定用的不是同一個數據庫,同時二者的數據庫也不在一個網絡節點上,那麼當用戶跨行轉賬,就是通過分佈式事務來保證數據的ACID的。

MySQL中使用事務

在MySQL命令行的默認設置下,事務都是自動提交的,即執行SQL語句後就會馬上執行COMMIT操作。因此要顯示地開啓一個事務須使用命令BEGIN或START TRANSACTION,或者執行命令SET AUTOCOMMIT=0,用來禁止使用當前會話的自動提交。
來看看我們可以使用哪些事務控制語句。
BEGIN或START TRANSACTION;顯示地開啓一個事務;
COMMIT;也可以使用COMMIT WORK,不過二者是等價的。COMMIT會提交事務,並使已對數據庫進行的所有修改稱爲永久性的;
ROLLBACK;有可以使用ROLLBACK WORK,不過二者是等價的。回滾會結束用戶的事務,並撤銷正在進行的所有未提交的修改;
SAVEPOINT identifier;SAVEPOINT允許在事務中創建一個保存點,一個事務中可以有多個SAVEPOINT;
RELEASE SAVEPOINT identifier;刪除一個事務的保存點,當沒有指定的保存點時,執行該語句會拋出一個異常;
ROLLBACK TO identifier;把事務回滾到標記點;
SET TRANSACTION;用來設置事務的隔離級別。

事務的隔離級別

在數據庫操作中,爲了有效保證併發讀取數據的正確性,提出的事務隔離級別。InnoDB存儲引擎提供事務的隔離級別有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ和SERIALIZABLE。這些隔離級別之間的區別如下:
在這裏插入圖片描述
隔離級別越低,事務請求的鎖越少或保持鎖的時間就越短。InnoDB存儲引擎默認的支持隔離級別是REPEATABLE READ;在這種默認的事務隔離級別下已經能完全保證事務的隔離性要求,即達到SQL標準的SERIALIZABLE級別隔離。
我們可以可以用SET TRANSACTION語句改變單個會話或者所有新進連接的隔離級別。具體操作可以訪問點擊

幾種一致性異常

1 丟失修改:T1和T2兩個事務對數據修改,T1先修改,T2後修改,T2的修改覆蓋了T1的修改
2 髒讀:一個事務讀取到了另外一個事務沒有提交的數據;
比如:事務T1更新了一行記錄的內容,但是並沒有提交所做的修改。事務T2讀取到了T1更新後的行,然後T1執行回滾操作,取消了剛纔所做的修改。現在T2所讀取的行就無效了;
不可重複讀:在同一事務中,兩次讀取同一數據,得到內容不同;
比如:事務T1讀取一行記錄,緊接着事務T2修改了T1剛纔讀取的那一行記錄。然後T1又再次讀取這行記錄,發現與剛纔讀取的結果不同。這就稱爲“不可重複”讀,因爲T1原來讀取的那行記錄已經發生了變化;
幻讀:同一事務中,用同樣的操作讀取兩次,得到的記錄數不相同;
比如:事務T1讀取一條指定的WHERE子句所返回的結果集。然後事務T2新插入 一行記錄,這行記錄恰好可以滿足T1所使用的查詢條件中的WHERE子句的條件。然後T1又使用相同的查詢再次對錶進行檢索,但是此時卻看到了事務T2剛纔插入的新行。這個新行就稱爲“幻像”,因爲對T1來說這一行就像突然出現的一樣。

視圖

視圖是一種虛擬的表,具有和物理表相同的功能,可以對視圖進行增,改,查操作,視圖通常是有一個表或者多個表的行或列的子集,對視圖的修改不影響基本表,它使得我們獲取數據更容易,相比多表查詢。
嘗試運行以下命令:
1 創建視圖
create or replace view dbtest_view as select * from dbtest;
2 查詢
select * from dbtest_view;
3 刪除
drop dbtest_view;
在這裏插入圖片描述

超鍵 候選鍵 主鍵 外鍵

1 超鍵:在關係中能唯一標識元組(數據庫中的一條記錄)的屬性集稱爲關係模式的超鍵。一個屬性可以爲作爲一個超鍵,多個屬性組合在一起也可以作爲一個超鍵。超鍵包含候選鍵和主鍵。
2 候選鍵:是最小超鍵,即沒有冗餘元素的超鍵。
3 主鍵:數據庫表中對儲存數據對象予以唯一和完整標識的數據列或屬性的組合,用戶選作元組標識的一個侯選鍵稱爲主鍵。一個數據列只能有一個主鍵,且主鍵的取值不能缺失,即不能爲空值(Null)。
4 外鍵:在一個表中存在的另一個表的主鍵稱此表的外鍵,外鍵主要是用來描述兩個表的關係。
例子:
身份證 姓名 性別 年齡
身份證唯一,所以是一個超鍵
姓名唯一,所以是一個超鍵
(姓名,性別)唯一,所以是一個超鍵
(姓名,性別,年齡)唯一,所以是一個超鍵
–這裏可以看出,超鍵的組合是唯一的,但可能不是最小唯一的
身份證唯一,而且沒有多餘屬性,所以是一個候選鍵
姓名唯一,而且沒有多餘屬性,所以是一個候選鍵
–這裏可以看出,候選鍵是沒有多餘屬性的超鍵
考慮輸入查詢方便性,可以選擇 身份證 爲主鍵
也可以 考慮習慣 選擇 姓名 爲主鍵
–主鍵是選中的一個候選鍵

數據庫三範式

第一範式(1NF):數據庫表中的字段都是單一屬性的,不可再分。這個單一屬性由基本類型構成,包括整型、實數、字符型、邏輯型、日期型等。
第二範式(2NF):數據庫表中不存在非關鍵字段對任一候選關鍵字段的部分函數依賴(部分函數依賴指的是存在組合關鍵字中的某些字段決定非關鍵字段的情況),也即所有非關鍵字段都完全依賴於任意一組候選關鍵字。
第三範式(3NF):在第二範式的基礎上,數據表中如果不存在非關鍵字段對任一候選關鍵字段的傳遞函數依賴則符合第三範式。所謂傳遞函數依賴,指的是如 果存在”A → B → C”的決定關係,則C傳遞函數依賴於A。因此,滿足第三範式的數據庫表應該不存在如下依賴關係: 關鍵字段 → 非關鍵字段 x → 非關鍵字段y。
說明:
1NF:字段不可分;
2NF:有主鍵,非主鍵字段依賴主鍵;
3NF:非主鍵字段不能相互依賴;
解釋:
1NF:原子性 字段不可再分,否則就不是關係數據庫;
2NF:唯一性 一個表只說明一個事物;
3NF:每列都與主鍵有直接關係,不存在傳遞依賴;
三範式旨在避免一些數據的冗餘。

反三範式

沒有冗餘的數據庫未必是最好的數據庫,有時爲了提高運行效率,提高讀性能,就必須降低範式標準,適當保留冗餘數據。具體做法是: 在概念數據模型設計時遵守第三範式,降低範式標準的工作放到物理數據模型設計時考慮。降低範式就是增加字段,減少了查詢時的關聯,提高查詢效率,因爲在數據庫的操作中查詢的比例要遠遠大於DML的比例。但是反範式化一定要適度,並且在原本已滿足三範式的基礎上再做調整的。

E-R圖

E-R圖也稱實體-聯繫圖(Entity Relationship Diagram),提供了表示實體類型、屬性和聯繫的方法,用來描述現實世界的概念模型。
E-R方法是“實體-聯繫方法”(Entity-Relationship Approach)的簡稱。它是描述現實世界概念結構模型的有效方法,是表示概念模型的一種方式,
1 用矩形表示實體型,矩形框內寫明實體名;
2 用橢圓表示實體的屬性,並用無向邊將其與相應的實體型連接起來,對於主屬性名(主鍵),則在其名稱下劃一下劃線。;
3 用菱形表示實體型之間的聯繫,在菱形框內寫明聯繫名,並用無向邊分別與有關實體型連接起來,
4 同時在無向邊旁標上聯繫的類型(1:1,1:n或m:n)。
聯繫可分爲以下 3 種類型:
(1) 一對一聯繫(1 ∶1)
例如,一個班級有一個班長,而每個班長只在一個班級任職,則班級與班長的聯繫是一對一的。
(2) 一對多聯繫(1 ∶N)
例如,某校教師與課程之間存在一對多的聯繫“教”,即每位教師可以教多門課程,但是每門課程只能由一位教師來教。
(3) 多對多聯繫(M ∶N)
例如,學生與課程間的聯繫(“學 ”)是多對多的,即一個學生可以學多門課程,而每門課程可以有多個學生來學。聯繫也可能有屬性。例如,學生“ 學” 某門課程所取得的成績,既不是學生的屬性也不是課程的屬性。由於“ 成績” 既依賴於某名特定的學生又依賴於某門特定的課程,所以它是學生與課程之間的聯繫“ 學”的屬性。

作圖步驟

⑴確定所有的實體集合
⑵選擇實體集應包含的屬性
⑶確定實體集之間的聯繫
⑷確定實體集的關鍵字,用下劃線在屬性上表明關鍵字的屬性組合
⑸確定聯繫的類型,在用線將表示聯繫的菱形框聯繫到實體集時,在線旁註明聯繫的類型。
在這裏插入圖片描述

處理重複數據

(1)查找表中多餘的重複記錄,重複記錄是根據單個字段(column_name)來判斷。

select * from table_name where column_name in (select column_name from table_name group by column_name having count(column_name) > 1)

在這裏插入圖片描述
(2)刪除表中多餘的重複記錄,重複記錄是根據單個字段(column_name)來判斷。

delete from table_name where column_name in (select b.column_name from (select column_name from table_name group by column_name having count(column_name)>1)b);

(3)查找表中多餘的重複記錄(多個字段)。

select * from table_name a where (a.column_name1,a.column_name2) in (select column_name1,column_name2 from vitae group by column_name1,column_name2 having count(*) > 1)

(4)刪除表中多餘的重複記錄(多個字段),只留有rowid最小的記錄 。

delete from table_name a where (a.column_name1,a.column_name2) in (select column_name1,column_name2 from table_name group by column_name1,column_name2 having count(*) > 1) and rowid not in (select min(rowid) from table_name group by column_name1,column_name2 having count(rowid)>1)

批處理SQL

#創建表和單處理
create table test(id int,name varchar(20));
insert into test values(1,'watson');

有些時候需要批處理操作,如果手動逐條運行較複雜,可以採用以下方式:
(1) 定義一個test.txt文本(以下命令不適合插入含主鍵的表,由於是反覆的查然後添加重複的元素),假設此文本是在 /home/test.txt

insert into test select * from test;
insert into test select * from test;
insert into test select * from test;
insert into test select * from test;
insert into test select * from test;
insert into test select * from test;
insert into test select * from test;
insert into test select * from test;
insert into test select * from test;
insert into test select * from test;
insert into test select * from test;
insert into test select * from test;
insert into test select * from test;
insert into test select * from test;
insert into test select * from test;

批處理

mysql -uroot -p -D MyZone < /home/test.txt

將查詢結果寫在文件中

select * from test limit 200;

命令行運行
mysql -uroot -p -D MyZone < /home/test.txt >/home/mysql0716.out

MyISAM與InnoDB的區別是什麼?

1、存儲結構

MyISAM:每個MyISAM表在磁盤上存儲成三個文件,文件的名字以表的名字開始,擴展名指出文件類型:.frm文件存儲表定義;數據文件的擴展名爲.MYD (MYData);索引文件的擴展名是.MYI (MYIndex)。
InnoDB:所有的表都保存在同一個數據文件中(也可能是多個文件,或者是獨立的表空間文件),InnoDB表的大小隻受限於操作系統文件的大小,一般爲2GB。

2、存儲空間

MyISAM:可被壓縮,存儲空間較小。支持三種不同的存儲格式:靜態表(默認,但是注意數據末尾不能有空格,會被去掉)、動態表、壓縮表。
InnoDB:需要更多的內存和存儲,它會在主內存中建立其專用的緩衝池用於高速緩衝數據和索引。

3、可移植性、備份及恢復

MyISAM:數據是以文件的形式存儲,所以在跨平臺的數據轉移中會很方便。在備份和恢復時可單獨針對某個表進行操作。
InnoDB:免費的方案可以是拷貝數據文件、備份 binlog,或者用 mysqldump,在數據量達到幾十G的時候就相對痛苦了。

4、事務支持

MyISAM:強調的是性能,每次查詢具有原子性,其執行數度比InnoDB類型更快,但是不提供事務支持。
InnoDB:支持事務,外部鍵等高級數據庫功能。 具有事務(commit)、回滾(rollback)和崩潰修復能力(crash recovery capabilities)的事務安全(transaction-safe (ACID compliant))型表。

這一點是非常重要。事務是一種高級的處理方式,如在一些列增刪改中只要哪個出錯還可以回滾還原,而MyISAM就不可以了。

5、AUTO_INCREMENT

MyISAM:可以和其他字段一起建立聯合索引。引擎的自動增長列必須是索引,如果是組合索引,自動增長可以不是第一列,他可以根據前面幾列進行排序後遞增。
InnoDB: InnoDB中必須包含只有該字段的索引。引擎的自動增長列必須是索引,如果是組合索引也必須是組合索引的第一列。

6、表鎖差異

MyISAM:只支持表級鎖,用戶在操作myisam表時,select,update,delete,insert語句都會給表自動加鎖,如果加鎖以後的表滿足insert併發的情況下,可以在表的尾部插入新的數據。
InnoDB:支持事務和行級鎖,是innodb的最大特色。行鎖大幅度提高了多用戶併發操作的性能。但是InnoDB的行鎖,只是在WHERE的主鍵是有效的,非主鍵的WHERE都會鎖全表的。

7、 全文索引

MyISAM:支持 FULLTEXT類型的全文索引。
InnoDB:不支持FULLTEXT類型的全文索引,但是innodb可以使用sphinx插件支持全文索引,並且效果更好。

8、表主鍵

MyISAM:允許沒有任何索引和主鍵的表存在,索引都是保存行的地址。
InnoDB:如果沒有設定主鍵或者非空唯一索引,就會自動生成一個6字節的主鍵(用戶不可見),數據是主索引的一部分,附加索引保存的是主索引的值。

9、 表的具體行數

MyISAM:保存有表的總行數,如果select count() from table;會直接取出出該值。
InnoDB:沒有保存表的總行數,如果使用select count() from table;就會遍歷整個表,消耗相當大,但是在加了wehre條件後,myisam和innodb處理的方式都一樣。

10、CURD操作

MyISAM:如果執行大量的SELECT,MyISAM是更好的選擇。
InnoDB:如果你的數據執行大量的INSERT或UPDATE,出於性能方面的考慮,應該使用InnoDB表。DELETE 從性能上InnoDB更優,但DELETE FROM table時,InnoDB不會重新建立表,而是一行一行的刪除,在innodb上如果要清空保存有大量數據的表,最好使用truncate table這個命令。

11、 外鍵

MyISAM:不支持
InnoDB:支持
通過上述的分析,基本上可以考慮使用InnoDB來替代MyISAM引擎了,原因是InnoDB自身很多良好的特點,比如事務支持、存儲 過程、視圖、行級鎖定等等,在併發很多的情況下,相信InnoDB的表現肯定要比MyISAM強很多。另外,任何一種表都不是萬能的,只用恰當的針對業務類型來選擇合適的表類型,才能最大的發揮MySQL的性能優勢。如果不是很複雜的Web應用,非關鍵應用,還是可以繼續考慮MyISAM的,這個具體視情況而定。

樂觀鎖 與 悲觀鎖

數據庫管理系統(DBMS)中的併發控制的任務是確保在多個事務同時存取數據庫中同一數據時不破壞事務的隔離性和一致性以及數據庫的統一性。

樂觀併發控制(樂觀鎖)和悲觀併發控制(悲觀鎖)是併發控制採用的主要技術手段。

無論是悲觀鎖還是樂觀鎖,都是人們定義出來的概念,可以認爲是一種思想。其實不僅僅是關係型數據庫系統中有樂觀鎖和悲觀鎖的概念,像memcache、hibernate、tair等都有類似的概念。

針對不同的業務場景,應該選用不同的併發控制方式。所以,不要把樂觀併發控制和悲觀併發控制狹義的理解爲僅在DBMS中存在的概念,更不要把他們和數據庫中提供的鎖機制(行鎖、表鎖、排他鎖、共享鎖)混爲一談。其實,在DBMS中,悲觀鎖正是利用數據庫本身提供的鎖機制來實現的。

悲觀鎖

在關係數據庫管理系統裏,悲觀併發控制(又名“悲觀鎖”,Pessimistic Concurrency Control,縮寫“PCC”)是一種併發控制的方法。它可以阻止一個事務以影響其他用戶的方式來修改數據。如果一個事務執行的操作在某行數據上應用了鎖,那只有當這個事務把鎖釋放,其他事務才能夠執行與該鎖衝突的操作。

悲觀併發控制主要用於數據爭用激烈的環境,以及發生併發衝突時使用鎖保護數據的成本要低於回滾事務的成本的環境中。

悲觀鎖:正如其名,它指的是對數據被外界(包括本系統當前的其他事務,以及來自外部系統的事務處理)修改持保守態度(悲觀),因此,在整個數據處理過程中,將數據處於鎖定狀態。 悲觀鎖的實現,往往依靠數據庫提供的鎖機制 (也只有數據庫層提供的鎖機制才能真正保證數據訪問的排他性,否則,即使在本系統中實現了加鎖機制,也無法保證外部系統不會修改數據)。

悲觀鎖的流程:
1.在對某一記錄進行修改前,先嚐試爲該記錄加上排他鎖(exclusive locking)。
2.如果加鎖失敗,說明該記錄正在被修改,那麼當前操作可能要等待或者拋出異常, 具體響應方式由開發者根據實際情況決定。
3.如果成功加鎖,那麼就可以對記錄做修改,事務完成後就會解鎖了。
4.其間如果有其他事務要對該記錄做修改或加排他鎖,都會等待該事務將該記錄解鎖或直接拋出異常。

MySQL InnoDB中使用悲觀鎖

注意:要使用悲觀鎖,必須先關閉mysql數據庫的自動提交功能,因爲MySQL默認使用autocommit模式,也就是說,當你執行一個更新操作後,MySQL會立刻將結果進行提交。

set autocommit=0;//禁止自動提交
//0.開始事務
begin;/begin work;/start transaction; (三者選一就可以)
//1.查詢出商品信息
select status from t_goods where id=1 for update;
//2.根據商品信息生成訂單
insert into t_orders (id,goods_id) values (null,1);
//3.修改商品status爲2
update t_goods set status=2;
//4.提交事務
commit;/commit work;

上面的查詢語句中,我們使用了select…for update的方式,這樣就通過開啓排他鎖的方式實現了悲觀鎖。此時在t_goods表中,id爲1的 那條數據就被我們鎖定了,其它事務必須等本次事務提交之後才能對該記錄進行操作。這樣我們可以保證當前的數據不會被其它事務修改。

注意:上面提到,使用select…for update會把數據給鎖住,不過我們需要注意一下鎖的級別,MySQL InnoDB默認爲行級鎖。行級鎖都是基於索引的,如果一條SQL語句沒有用到索引是不會使用行級鎖的,會使用表級鎖把整張表鎖住,這點需要注意。

優點與不足:

優點:悲觀併發控制實際上是採用“先取鎖再訪問”的保守策略,爲數據處理的安全性提供了保證;
缺點:在效率方面,處理加鎖的機制會讓數據庫產生額外的開銷,同時會增加產生死鎖的機率;另外,在只讀型事務中由於不會產生衝突,也沒必要使用鎖,這樣做只會增加系統負載;還會降低並行性,一個事務如果鎖定了某行數據,其他事務就必須等待該事務處理完纔可以處理那行數據。

樂觀鎖

在關係數據庫管理系統裏,樂觀併發控制(又名“樂觀鎖”,Optimistic Concurrency Control,縮寫“OCC”)是一種併發控制的方法。它假設多用戶併發的事務在處理數據時不會彼此互相影響,各事務能夠在不產生鎖的情況下處理各自影響的那部分數據。在提交數據更新之前,每個事務會先檢查在該事務讀取數據後,有沒有其他事務對該數據做過修改。如果其他事務更新過該數據的話,正在提交的事務會進行回滾。

樂觀鎖( Optimistic Locking )是相對悲觀鎖而言,樂觀鎖假設數據一般情況下不會造成衝突,所以在事務對數據進行提交更新的時候,纔會正式對數據的衝突與否進行檢測,如果發現衝突了,則返回錯誤信息,讓用戶決定如何去做。

相對於悲觀鎖,在對數據庫進行處理的時候,樂觀鎖並不會使用數據庫提供的鎖機制,一般用記錄數據版本的方式實現樂觀鎖。

數據版本:爲數據增加的一個版本標識。當讀取數據時,將版本標識的值一同讀出,數據每更新一次,便對版本標識進行一次更新。當事務提交更新的時候,需要判斷數據庫表對應記錄的當前版本信息與第一次取出來的版本標識是否一致,如果數據庫表當前版本號與第一次取出來的版本標識值相等,則予以更新,否則認爲是過期數據。

實現數據版本有兩種方式,第一種是使用版本號,第二種是使用時間戳。

使用版本號實現樂觀鎖

使用版本號時,可以在數據初始化時指定一個版本號,每次對數據的更新操作都對版本號執行+1操作。並判斷當前版本號是不是該數據的最新的版本號。

1.查詢出商品信息
select (status,status,version) from t_goods where id=#{id}
2.根據商品信息生成訂單
3.修改商品status爲2
update t_goods 
set status=2,version=version+1
where id=#{id} and version=#{version};

樂觀併發控制假設事務之間的數據競爭(data race)概率比較小,因此儘可能直接做下去,直到提交的時候纔去鎖定,所以不會產生任何鎖和死鎖。但如果直接簡單這麼做,還是有可能會遇到不可預期的結果,例如兩個事務都讀取了數據庫的某一行,經過修改以後寫回數據庫,這時就遇到了問題。

左 右 連接 全連接 內連接

SQL連接可以分爲內連接、外連接、交叉連接。
在這裏插入圖片描述

內連接

內連接:內連接查詢操作列出與連接條件匹配的數據行,它使用比較運算符比較被連接列的列值。包含以下三種:
1.1.等值連接:在連接條件中使用等於號(=)運算符比較被連接列的列值,其查詢結果中列出被連接表中的所有列,包括其中的重複列。
1.2.不等值連接:在連接條件使用除等於運算符以外的其它比較運算符比較被連接的列的列值。這些運算符包括>、>=、<=、<、!>、!<和<>。
1.3.自然連接:在連接條件中使用等於(=)運算符比較被連接列的列值,但它使用選擇列表指出查詢結果集合中所包括的列,並刪除連接表中的重複列。

select * from book as a,stu as b where a.sutid = b.stuid
或者
select * from book as a inner join stu as b on a.sutid = b.stuid

內連接可以使用上面兩種方式,其中第二種方式的inner可以省略。
在這裏插入圖片描述
其連接結果如上圖,是按照a.stuid = b.stuid進行連接。紅色框爲重複列。

左連接

1.左聯接:是以左表爲基準,將a.stuid = b.stuid的數據進行連接,然後將左表沒有的對應項顯示,右表的列爲NULL
2.右連接:是以右表爲基準,將a.stuid = b.stuid的數據進行連接,然以將右表沒有的對應項顯示,左表的列爲NULL
3全連接:完整外部聯接返回左表和右表中的所有行。當某行在另一個表中沒有匹配行時,則另一個表的選擇列表列包含空值。如果表之間有匹配行,則整個結果集行包含基表的數據值。

1 左連接

select * from book as a left join stu as b on a.sutid = b.stuid

在這裏插入圖片描述
2 右連接

select * from book as a right join stu as b on a.sutid = b.stuid

在這裏插入圖片描述
3 全連接

select * from book as a full outer join stu as b on a.sutid = b.stuid

在這裏插入圖片描述

交叉連接

交叉連接:交叉聯接返回左表中的所有行,左表中的每一行與右表中的所有行組合。交叉聯接也稱作笛卡爾積。

select * from book as a cross join stu as b order by a.id

在這裏插入圖片描述
【參考借鑑】
【1】參考一點擊
【2】參考二點擊
【3】參考三點擊
【4】參考四點擊

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章