如何設計一個關系型數據庫
索引模塊
為什么要使用索引
B+Tree

- 非葉子節點的字數指針與關鍵字的個數相同
- 非葉子節點的字數指針P[i],指向關鍵字值[K[i],K[i+1]]的子樹
- 非葉子節點僅用來索引,數據保存在葉子節點中
- 所有葉子節點均有一個鏈指針指向下一個葉子節點(方便做索引)
結論
B+Tree更加適合用來做存儲索引
- B+樹的磁盤讀寫代價更低
- B+樹的查詢效率更加穩定
- B+樹更有利於對數據庫的掃描
Hash索引

buckets是桶
缺點
- 僅僅滿足“=”,“IN”,不能用於范圍查詢
- 無法被用來避免數據的排序操作(hashcode是經過hash函數后得出的)
- 不能利用部分索引鍵查詢
- 不能避免表掃描
- 遇到大量Hash相等的情況下不能比B-Tree的索引高
entries在Java中實現有紅黑樹和普通數組兩種形式
BitMap索引
密集索引和稀疏索引的區別
- 密集索引文件中的每個搜索碼都對應一個索引值
- 稀疏索引文件只為索引碼的某些值創建索引項

InnoDB
- 若一個主鍵被定義,則該主鍵被作為密集索引
- 若沒有主鍵被定義,該表的第一個唯一非空索引則作為密集索引
- 若不滿足以上條件,innodb內部會自動生成一個隱藏主鍵(密集索引)
- 非主鍵索引存儲相關鍵位和其對應的主鍵值,包含兩次查找
![1549778755317].\mg\1549778755317.png)
如何定位並優化慢查詢sql
如何優化mysql查詢的查詢效率
show variables like '%quer%';
show status like '%slow_queries%';
-- 設置
set global slow_query_log=on;
-- 修改最長查詢時間
set global long_query_time = 1;
-- 查詢
select name from person_info_large order by name desc;
Explain關鍵字段
type
index:為帶有索引的掃描方式
all:為全表掃描的方式
排序的耗時從低到高的順序:index>all
extra

聯合索引的最左匹配原則的成因

Mysql創建聯合索引(Union Index)時會以Order By A,Order By B的順序,對於A來說所有data rows 都是有序的,但是對於B來說卻不一定。所以必須准許最左匹配原則
對於聯合索引(a,b,c,d)來說,在Mysql解析到(<,>,between and ,like)等范圍查詢語句后,如果后方還有列需要查詢會放棄索引查詢,例如a=1,b=2,c>3,d=5就不會采用索引的方式查詢如果改為a=1,b=2,d=5,c>3就會采用索引,對於第一種情況Mysql的查詢解析器會自動優化,也就是說abc是可以亂序的
緩存模塊
MyISAM和InnoDB
- InnoDB默認為行級鎖,支持表級
- MyISAM默認是表級,不支持行級鎖
MyISAM適合的場景
- 頻繁執行全表
count語句 - 對數據進行增刪改的頻率不高,查詢很頻繁的(這是因為讀寫鎖的原因造成的,讀鎖是共享的
S鎖,寫鎖是互斥的X鎖) - 沒有事務
InnoDB適合的場景
- 數據增刪改查都非常頻繁
- 可靠性高可以支持事務
數據庫的鎖分類
- 按鎖的粒度划分,可分為表級鎖、行級鎖、葉級鎖
- 按鎖級別划分,可分為共享鎖S、排它鎖X
- 按加鎖方式划分,可分為自動鎖、顯示鎖
- 按操作划分,可划分為DML鎖、DDL鎖
- 按使用方式划分,可分為樂觀鎖(使用時間戳或者序列化號)、悲觀鎖
數據庫事務的四大特性 ACID
- 原子性(Atomic):事務包含的操作要么全部完成要么不做
- 一致性(Consistency):事務必須使數據庫從一個一致性狀態變化到另一個一致性狀態
- 隔離性(Isolation):一個事務的執行不能被其他事務干擾,多個事務的並發執行是不會相互干擾。
- 持久性(Durability):已提交事務對數據庫的修改是永久存在的
數據庫定義的錯誤類型
1、臟讀
臟讀是指在事務處理過程中讀取了另一個未提交事務的數據。
當一個事務正在多次修改某個數據,而這個事務的多次修改均為提交,這時一個並發的事務訪問該數據,就會造成兩個事務獲取的數據不一致。
2、不可重復讀
不可重復讀是指對於數據庫的某個數據,一個事務范圍內多次查詢卻返回了不同的值。
例如事務T1在讀取某一數據,而事務T2立馬修改了這個數據並且事務提交給數據庫,事務T1再次讀取這個數據發現數據與之前的數據不相同,發生臟讀。
3、幻讀(虛讀)
幻讀是事務非獨立執行時發生的一種現象。例如事務T1對一個表中的所有行的某個數據項做了從“1”修改到“2”的操作,這是事務T2對表中插入一個數據項“1”,T1查看剛剛修改的數據,會發現還有一行沒有修改,其實是T2添加進來的,就好像發生了幻覺一樣,這就是發生了幻讀。
幻讀和不可重復讀都是讀取了另一條已經提交了的事務,所不同的是臟讀針對的是對一個數據項(的觀察),而幻讀是對一批數據整體(比如數據個數)。
MySql數據庫隔離級別
- Serializable(串行化):可避免臟讀、不可重復讀、幻讀
- Repeatable Read (可重復讀 MySQL默認級別):可避免臟讀、不可重復讀
- Read Committed (讀已提交):可避免臟讀
- Read Uncommitted (讀未提交):最低級別,任何情況都不能保證
語法部分
Group By
- 滿足“select字句中的列名必須為分組列或列函數“
- 列函數每組返回一個值
JVM
ClassLoader類型
- BootstrapClassLoader 系統類加載器:C++編寫,加載
java.*,負責加載放在<JAVA_HOME>\lib目錄中的,被-Xbootclasspath參數所指定的路徑中,並且是虛擬機表示的類庫,用戶無法直接使用; - ExtClassLoader 拓展類加載器:Java編寫,加載
javax.*,該類加載器由sun.misc.Launcher$AppClassLoader實現。負責加載<JAVA_HOME>\lib\ext目錄中的,或者被java.ext.dirs系統變量中指定的目錄的所有類庫,用戶可以直接使用; - AppClassLoader 用戶類加載器:加載程序所在目錄;
- 用戶自定義類加載器:加載用戶指定的目錄;
Class.forName()和ClassLoader.loadClass();
主要區別在於是否進行鏈接(Java裝入類中的一步)
Class.loadClass(className,false);
public static Class<?> forName(String name, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException
Class.forName(className)方法,內部實際調用的方法是 Class.forName(className,true,classloader);
第2個boolean參數表示類是否需要初始化, Class.forName(className)默認是需要初始化。
一旦初始化,就會觸發目標對象的 static塊代碼執行,static參數也也會被再次初始化。
ClassLoader.loadClass(className)方法,內部實際調用的方法是 ClassLoader.loadClass(className,false);
第2個 boolean參數,表示目標對象是否進行鏈接,false表示不進行鏈接,由上面介紹可以,
不進行鏈接意味着不進行包括初始化等一些列步驟,那么靜態塊和靜態對象就不會得到執行
