MySQL的邏輯結構
客戶端+服務器+存儲引擎
存儲引擎
查看存儲引擎: show engines.我的電腦里默認的是InnoDB;
InnoDB和MyISAM索引采用的是B+樹, MEMORY采用的是Hash索引.
MySql中最常用的的存儲引擎是InnoDB和MyISAM.
前者在磁盤中會落2個文件,分別是.frm和.ibd..frm代表form files,代表格式文件..ibd中包含真實數據和索引數據.
而myISAM中會落3個文件,分別是.frm,.MYD和.MYI,其中后面兩種格式代表真實數據和索引數據.
內存和磁盤交互:
磁盤預讀:預讀的長度一般是頁的整數倍.頁是存儲器(包括內存和磁盤)的邏輯塊,通常為4KB,內存和磁盤以頁來為單位交換數據.InnoDB默認一次預讀16KB的數據.
索引:
為什么要創建索引:
如果沒有索引,查找數據是全表掃描,而如果有索引的話,會按照B+樹的結構去查找數據.
創建索引是個什么過程?
就是把數據組織成數據結構的過程.
存儲在文件系統中,存儲形式和存儲引擎有關,索引文件的結構包括hash,二叉樹,B樹和B+樹.
hash表:是數組+鏈表的結構.
hash作為索引存在的問題 :
1.哈希函數不容易選擇
2.hash存儲需要將所有的數據文件添加到內存(why?待后知后覺),浪費內存空間.
3.等值查詢用hash比較快,但是實際中范圍查詢更多,hash不太合適.
以上問題使得hash沒有作為大部分存儲引擎(查找數據是與磁盤進行交互)的數據結構.而MEMORY存儲引擎是在內存中進行的,使用它的時候就接受它占內存的問題了,另外在內存中查找速度很快.
二叉樹,紅黑樹存在的問題:
樹中元素存儲的是數據值,樹在物理結構上是數組進行存放的,可能邏輯結構上很近的數據(比如父子)在物理結構上會相差很遠(比如當樹很大時).因此,每次讀取磁盤頁的數據很多是用不上的.可能需要進行很多次的IO交互才能夠找到要找的數據.
都會因為樹的深度太深而造成io次數變多(指的是內存和磁盤交互的次數),影響讀取的效率.
提升IO效率的兩個方法:
1.減少IO的次數
2.減少IO的大小
eg:不推薦使用select(*)的原因,是因為它會把磁盤中全表的數據都拉到內存(mysql的服務)中,然后在內存中去進行篩選,篩選完畢后給到客戶端中.
B樹:
樹中節點存儲的是數據塊.
圖中紫色的代表鍵值,它可能是記錄的主鍵.
樹的階數(degree)等於它可以最多存儲指針的個數(數據的個數比指針個數少1).
比如下面的這個示意圖,它最多能夠存3個指針,兩個data,它的degree是3.
假如當前磁盤塊的大小為16KB,每個data占1KB的內存,忽略鍵值和指針,一個磁盤塊中可以存16個data,即階為17.那么三層樹可以存儲的數據量16+17*16+17*17*16=16*(1+17+17*17)=4912條數據.從這里可以看出來影響存儲數據多少的因素是data的大小,而這個時候B+樹就比較合適了.
B+樹:
同樣的3層樹,如果前兩層只存儲鍵值和指針的話,那么對應存儲的指針數就會大大增加,假如前兩層每個磁盤可以存儲1600個指針,第三層仍然是存儲16個數據,那么三層樹總共可以存儲的數據量=1600*1600*16 = 40960000,差不多數據容量增加了1萬倍.
注意這里為什么特別在意樹的層數呢?因為樹的層數越深,查找樹的次數就越多(最壞情況,單枝退化成了鏈表).
B+樹中有兩種查找方式:一種是對於主鍵的范圍查找和分頁查找,另一種是從根節點開始,進行隨機查找.
InnoDB和MyISAM所以創建的區別:
InnoDB,葉子節點中放置的是數據,對應.ibd,<-> 聚簇/聚集索引.
注意:
1.InnoDB對主鍵創建索引,也就是把主鍵作為B+樹中的Key,如果沒有主鍵,會選擇唯一鍵,如果沒有唯一鍵,會生成一個6字節的row_id(不可見)來作為主鍵(都是為了保證key的唯一性).
2.如果創建索引的鍵是其他字段,那么在葉子節點中存儲的是該記錄的主鍵,然后再通過主鍵索引找到對應的記錄,這個過程叫做回表.
比如下圖中又對表中的name建立了索引(稱為二級索引/輔助索引),如果要執行select * from table where name = "ma",根據"ma"找到了主鍵1,這個時候還需要根據主鍵回到表中查找所有的列.而如果select id from table where name = "ma"的話,則不會觸發回表.
MyISAM中葉子節點沖存儲的是地址,然后根據地址去查找數據.所以存儲文件是.MYI,.MYD. <->非聚簇索引.
MySQL的B+樹三層還是四層,取決於數據量的多少.
主鍵自增:
分布式不推薦(分布式中有自己的主鍵生成策略),
非分布式推薦.
主鍵自增,能夠保證后面插入的數據在建立索引時從添加到樹的結尾.如果主鍵是亂序的話,在創建索引時,會插入到中間位置.如果中間位置滿了,會導致頁分裂,會造成維護上很麻煩.(添加到結尾,如果數據滿了也會造成頁分裂,但沒有中間插入的那種情況嚴重).
索引優化相關:
1.盡量用int來存儲索引,它只占4個字節,而varchar會占用比較多的字節.
2.