數據庫基礎知識
以MySQL為基礎
-
數據庫事務 :數據庫中一組原子性的SQL操作,彼此狀態一致。具有ACID特性。
-
事務 ACID 特性:
- 原子性:數據庫事務是一個整體,其中的SQL操作要么全部提交成功commit要么全部失敗回滾rollback,不可分割;
- 一致性:與原子性有聯系。事務總是從一個一致狀態轉換到另一個一致狀態;
- 隔離性:事務之間彼此互不影響,一個事務在提交之前,對其他事務是不可見的。
- 持久性:一個事務一旦提交成功,他所做的修改就會永久性的存儲在數據庫中。
-
MySQL 4 種隔離級別
- 未提交讀READ UNCOMMITTED:一個事務在提交之前,對其他事務是可見的,即事務可以讀取未提交的數據。存在“臟讀”(讀到了臟數據)問題;
- 提交讀READ COMMITTED:事務在提交之前,對其它事務是不可見的。存在“不可重復讀”(兩次查詢的得到的結果可能不同,即可能在查詢的間隙,有事務提交了修改)問題。解決了“臟讀”問題。
- 可重復讀REPEATABLE READ:在同一事務中多次讀取的數據是一致的。解決了臟讀和不可重復讀問題,存在“幻讀”(在事務兩次查詢間隙,有其他事務又插入或刪除了新的記錄)。--- MySQL默認隔離級別。
- 可串行化SERIALIZABLE:強制事務串行化執行。即一個事物一個事物挨個來執行,可以解決上述所有問題。
-
鎖及粒度:
- 共享鎖/讀鎖:互不阻塞,優先級低
- 排他鎖/寫鎖:阻塞其他鎖,優先級高,即確保在一個事務寫入時不受其他事務的影響。
- 鎖粒度:鎖定的數據量越少(粒度越小),並發程度越高,但相應的加鎖、檢測鎖、釋放鎖用的系統開銷也隨之增大。
- 鎖策略:鎖開銷與數據安全性之間的平衡
- 表鎖:鎖住整張表,讀鎖互不阻塞,寫鎖阻塞其他所有讀寫鎖(同一張表)。開銷最小。
- 行級鎖:對每一行數據(記錄)加鎖,開銷大,並發程度高。
-
InnoDB對死鎖的處理:此處死鎖與OS死鎖類似,多個事務互相持有對方所有要申請資源的鎖不釋放,造成環路死鎖。MySQL InnoDB引擎檢測到死鎖循環依賴后,回滾持有最少行級鎖的事務。
-
索引及其作用和實現方法:
- 概念:對數據庫表列進行增加恰當索引,可以快速的找到匹配的記錄行數,相比於默認的全表掃描,可以大大加快查找的速度。
- 作用:加快查找速度;
- 實現方法:一般分為B+樹索引和哈希索引。
- B+樹索引:在B-tree上改進得到,其非葉子節點均為key值,葉子節點是key-data鍵值對。葉子節點前后相連且有序。
- 哈希索引:通過對key進行hash(crc/MD5/sha1/sha256...)而將記錄存儲在不同的bucket種,可以做到常數時間的查找,但要注意哈希沖突的避免(鏈表法、線性探測、二次探測、公共溢出區的方法)。其中MD5 128位,和sha1/256碼都較長不太適合作為hash函數。默認無序。
- 為什么有了B+樹索引還要hash索引?
- B+樹默認有序,hash默認無序,所以哈希索引無法用於排序;
- 哈希索引O(1)在速度上毋庸置疑要快於B+樹近似O(logn);
- 哈希索引只能進行等值查詢(因為他要計算hash(key)再去匹配)而B+樹索引可以進行等值、部分前綴、范圍查詢;
- 底層實現結構不同:B+樹是非線性結構,hash桶是線性結構。
- 對於某些場景如熱點頁/活躍查詢頁,需要借助哈希索引來實現快速查詢。
- 索引越多越快?
此言差矣,索引並非是虛無縹緲的,是實實在在的一種數據結構(B+樹/hash桶)要占內存、維護它要系統開銷,一般的插入刪除都要進行結構的調整,這要消耗時間,所以索引太多反而拖慢查找時間。有時候,見數據量不多時,建立索引還不如全表查詢。索引加快了檢索的速度,但是插入刪除修改都需要DBMS動態更新內部索引結構,要耗費開銷。
-
InnoDB MVCC
多版本並發控制,是為了避免加鎖而實現的。一般的實現方法是存儲快照來實現的。InnoDB實現方式是在記錄后添加兩個隱藏列(表項),分別是事務創建時間、過期時間,存儲的實際上是系統版本號(系統版本號隨着事務的創建而遞增)。
這樣一來,INSERT 時加上開始版本號,UPDATE/DELETE時加上過期版本號,這樣一來在SELETE時,就只訪問開始系統版本號小於當前的事務的版本號、過期時間要么未定義要么在當前版本號之后的記錄,這樣就可以保證:訪問的記錄是在本事務開始前就存在而且在本事務期間沒有過期(被刪除或被修改過的)。可以避免臟讀、不可重復讀、幻讀的問題。(個人覺得) -
MySQL存儲引擎簡介
- InnoDB,最為通用/推薦的一種引擎,支持事務、行級鎖、甚至間隙鎖(避免幻讀)、支持熱備份,MVCC,在並發上占優勢,系統資源占用多。
- MyISAM,默認的存儲引擎,不支持事務和行級鎖,只支持表鎖,某些場景性能很好:占用存儲上優,查詢速度上完勝(大概是InnoDB的3倍)系統資源占用少。
- InnoDB支持事務, MyISAM不支持;
- InnoDB支持行級鎖、表鎖;MyISAM只支持表鎖;
- InnoDB支持MVCC,MyISAM不支持;
- InnoDB不支持全文索引,MyISAM支持;
- InnoDB支持外鍵,MyISAM不支持外鍵;
- InnoDB和MyISAM都支持B+樹索引,InnoDB還支持自適應哈希索引
- MyISAM實現了前綴壓縮技術,占用存儲空間更小(但會影響查找),InnoDB是原始數據存儲,占用存儲更大。
PS:大部分情況下,InnoDB都是正確的選擇。---《高性能MySQL》
-
SQL優化
- 在經常性的檢索列上,建立必要索引,以加快搜索速率,避免全表掃描(索引覆蓋掃描);
- 多次查詢同樣的數據,可以考慮緩存該組數據;
- 審視select * form tables, 你需要所有列數據嗎?
- 切分查詢(大查詢切分成為小查詢,避免一次性鎖住大量數據)
- 分解關聯查詢(單表查詢,結果在應用程序中進行關聯,可以減少處理過程中的鎖爭用)
- 盡量先做單表查詢;
- ...
-
profile 的作用和用法
用於保存SQL語句執行狀態,需要手動開啟,才可以查看。
set profiling = 1; 開啟
show profiles; 顯示SQL查詢的profiles概況
show profile all for query X; 查看第X條語句的所有執行情況。
show profile cpu, block io, memory for query X; 查看部分profile信息。
- MySQL查詢的步驟
- 客戶端發送查詢到服務器;
- 服務器檢查查詢緩存query cache(大小寫敏感的哈希查找,常數時間)。如果命中,返回緩存中的結果,否則下一步;
- 解析語句,生成執行計划;(SQL解析,預處理,優化器生成執行計划);
- 根據執行計划,根據存儲引擎的不同調用API,執行查詢(一棵指令樹);
- 結果返回客戶端。