資料庫筆記整理
參考文章:
https://juejin.im/post/5a9ca0d6518825555c1d1acd
資料庫的正規化:
參考連結: https://www.zhihu.com/question/24696366
正規化(NF):符合某一種級別的關係模式的集合,表示一個關係內部各屬性之間的聯絡的合理化程度
1NF, 2NF, 3NF, BCNF, 4NF, 5NF 一般考慮到BCNF就可以,符合高一級正規化的設計,必然符合低一級正規化
1NF(所有關係型資料庫的最基本要求, 如果不符合這個要求,建立表操作一定不成功):關係中的每個屬性都不可再分
反例:
進貨下面不能再分為數量和單價
改正:
2NF(解決1NF中存在的資料冗餘過大,插入/刪除/修改異常等問題): 表中的欄位必須完全依賴於全部主鍵而非部分主鍵
其他欄位組成的這行記錄和主鍵表示的是一個東西,而主鍵是唯一的,它們只需要依賴於主鍵,也就成為了唯一的
3NF():非主鍵外的所有欄位必須互不依賴 資料只在一個地方儲存,不重複出現在多張表中,可以認為是消除傳遞依賴
比如,我們大學分了很多系(中文系、英語系、計算機系……),這個系別管理表資訊有以下欄位組成:系編號,系主任,系簡介,系架構。那我們能不能在學生資訊表新增系編號,系主任,系簡介,系架構欄位呢?不行的,因為這樣就冗餘了,非主鍵外的欄位形成了依賴關係(依賴到學生資訊表了)!正確的做法是:學生表就只能增加一個系編號欄位。
什麼是事務?
一個Session鍾所進行的所有操作,要麼同時成功,要麼同時失敗
AtomicityConsistency*Isolation**D*urability 資料庫正確執行的四個基本要素
舉例: A向B轉賬,轉賬這個流程如果出現問題,事務機制可以讓資料恢復為原來的樣子【只可能出現A減B加或A不減B不加兩種結果,不可能出現A減B不加和A不減B加】
JDBC預設情況下是關閉事務的,
【假定一切正常】
//JDBC預設的情況下是關閉事務的,下面我們看看關閉事務去操作轉賬操作有什麼問題 //A賬戶減去500塊 String sql = "UPDATE a SET money=money-500 "; preparedStatement = connection.prepareStatement(sql); preparedStatement.executeUpdate(); //B賬戶多了500塊 String sql2 = "UPDATE b SET money=money+500"; preparedStatement = connection.prepareStatement(sql2); preparedStatement.executeUpdate();
【假定轉賬過程中出現了問題】: 程式碼丟擲異常導致A賬號少了500塊錢,B賬戶的錢沒有增加。
String sql = "UPDATE a SET money=money-500 ";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.executeUpdate();
//這裡模擬出現問題
int a = 3 / 0;
String sql2 = "UPDATE b SET money=money+500";
preparedStatement = connection.prepareStatement(sql2);
preparedStatement.executeUpdate();
//開啟事務,對資料的操作就不會立即生效。
connection.setAutoCommit(false);
//A賬戶減去500塊
String sql = "UPDATE a SET money=money-500 ";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.executeUpdate();
//在轉賬過程中出現問題
int a = 3 / 0;
//B賬戶多500塊
String sql2 = "UPDATE b SET money=money+500";
preparedStatement = connection.prepareStatement(sql2);
preparedStatement.executeUpdate();
//如果程式能執行到這裡,沒有丟擲異常,我們就提交資料
connection.commit();
//關閉事務【自動提交】
connection.setAutoCommit(true);
} catch (SQLException e) {
try {
//如果出現了異常,就會進到這裡來,我們就把事務回滾【將資料變成原來那樣】
connection.rollback();
//關閉事務【自動提交】
connection.setAutoCommit(true);
} catch (SQLException e1) {
e1.printStackTrace();
}
事務隔離級別:
- Serializable【可避免髒讀,不可重複讀,虛讀】
髒讀: 一個事務讀取到另一個事務未提交的資料
舉例:A向B轉賬,A執行了轉賬語句,但A還沒有提交事務,B讀取資料,發現自己賬戶錢變多了!B跟A說,我已經收到錢了。A回滾事務【rollback】,等B再檢視賬戶的錢時,發現錢並沒有多。
不可重複讀: 一個事務讀取到另一個事務已經提交的資料,一個事務看到其它事務所做的修改
舉例: A查詢資料庫得到資料,B去修改資料庫的資料,導致A多次查詢資料庫的結果都不一樣
虛讀:在一個事務內讀取到了別的事務插入的資料,導致前後讀取不一致
舉例: 和不可重複讀類似,但虛讀(幻讀)會讀到其他事務的插入的資料,導致前後讀取不一致
資料庫的樂觀鎖和悲觀鎖是什麼?
資料庫的鎖機制中介紹過,資料庫管理系統(DBMS)中的併發控制的任務是確保在多個事務同時存取資料庫中同一資料時不破壞事務的隔離性和統一性以及資料庫的統一性。
悲觀併發控制(Pessimistic Concurrency Control,縮寫“PCC” 悲觀鎖):假定會發生衝突,遮蔽一切可能違規的操作
在查詢完之後就把事務鎖起來,直到提交事務 實現:使用資料庫中的鎖機制
悲觀鎖的實現,往往依靠資料庫提供的鎖機制 (也只有資料庫層提供的鎖機制才能真正保證資料訪問的排他性,否則,即使在本系統中實現了加鎖機制,也無法保證外部系統不會修改資料)
流程:
- 在對任意記錄進行修改之前,先嚐試為該記錄加上排他鎖(exclusive locking)
- 如果加鎖失敗,說明該記錄正在被修改,那麼當前查詢可能要等待 或丟擲異常
- 如果加鎖成功,就可以對記錄做修改,事務完成後就會解鎖
- 在被加鎖期間,如果有其它的記錄對該記錄做出修改或加排他鎖,都會等待我們解鎖或直接丟擲異常
樂觀鎖: 假定不會發生衝突,只在提交操作時檢查是否違規
在修改資料的時候把事務鎖起來,通過version的方式來進行鎖定
實現:使用version版本或者時間戳
資料庫索引
索引(在MySQL當中也叫做Key)是儲存引擎用於快速找到記錄的一種資料結構。這是索引的基本功能。
索引優化可以被認為是對查詢效能優化最有效的手段了。索引能夠輕易將查詢效能提高几個數量級。
最優 比 好的 索引效能要好兩個數量及,建立一個真正最優的索引經常需要重寫查詢。
索引基礎
查字典
索引中找到對應值,根據匹配的索引記錄找到對應資料行
索引是什麼
SELECT first_name FROM sakila.actor WHERE actor_id = 5;
索引可以包含一個或多個列的值。如果索引包含多個列,那麼列的順序也十分鐘要,因為MySQL只能夠高效地使用索引的最左字首匹配,一直向右匹配直到遇到範圍查詢(>、<、between、like)就停止匹配。
舉例:a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)順序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引則都可以用到,a,b,d的順序可以任意調整。
索引可以包含多個列
索引的型別
MySQL中,索引是在儲存引擎層而不是伺服器層面實現的,所以沒有統一的索引標準:不同儲存引擎的索引的工作方式不同,也不是所有的儲存引擎都支援所有型別的索引
B-Tree索引
B-Tree簡介
B+Tree:每個葉子節點都包含指向下一個葉子節點的指標, 從而方便葉子節點的範圍遍歷
Every node has at most m children
A non-leaf node with k children contains k - 1 keys
The root has at least two children if it is not a leaf node
Every non-leaf node(except root) has at least [m/2] children
All leaves appear in the same level
B-Tree對索引列是順序組織儲存的,所以很適合查詢範圍資料。
舉例:對於一個基於文字域的索引樹上,找出所有以A到C開頭的名字 效率很高
CREATE TABLE People (
last_name varchar(50) not null,
first_name varchar(50) not null,
dob date not null,
gender enum('m', 'f') not null,
key(last_name, first_name, dob)
);
索引對於多個值進行排序的一句是CREATE TABLE語句中定義索引時列的書序,比如例子中最後兩個條目中,如果兩個人的姓和名都一樣,則根據他們的出生日期進行排序
適用查詢型別:全鍵值,鍵值範圍或鍵字首查詢(最左)
不適用的查詢型別:
* 不是按照索引的最左列開始查詢,則無法使用該索引
* 舉例: 上面資料表中,無法查詢名字為Bill的人,無法查詢某個特定生日的人,因為這兩列都不是資料最左列,也無法查詢姓氏以某個字母結尾的人
* 不能跳過索引中的列
* 如果查詢中有某個列的範圍查詢,則右邊所有列都無法使用索引優化查詢
雜湊索引
建索引的原則
- 最左字首匹配原則
MySQL 索引型別,隔離級別以及實現
MongoDB + AWS
談談樂觀鎖
MySQL的事務
如何進行索引調優
MySQL索引的資料結構, 使用B樹的原因
Mybatis的一二級快取
有一個數據表的資料量比較大,讀多寫少的資料庫如何設計
資料庫的資料量比較多時,查詢較慢,如何進行優化?
資料庫的聯合索引是什麼? 如何進行索引優化? 如何知道SQL語句是否使用了索引,以及使用了哪些索引?
你知道資料庫分庫分表有哪些?各自在何種情況下使用?
資料庫分庫分表時如何進行劃分?
對於MySQL的索引有哪些瞭解? 哪些列適合建索引? 索引是越多越好麼?
悲觀鎖和樂觀鎖
MySQL儲存引擎、事務隔離級別、鎖
MySQL索引,面試官寫了一條SQL語句,問使用到了哪些索引,為什麼?
Mybaitis 和 Hibernate 區別