聚簇索引:將數據存儲與索引放到了一塊,找到索引也就找到了數據。具備惟一性,聚簇索引默認是主鍵,若是表中沒有定義主鍵,InnoDB 會選擇一個惟一的非空索引代替。若是沒有這樣的索引,InnoDB 會隱式定義一個主鍵來做爲聚簇索引。java
非聚簇索引:將數據存儲於索引分開結構,索引結構的葉子節點指向了數據的對應行,myisam經過key_buffer把索引先緩存到內存中,經過索引訪問數據,在內存中直接搜索索引,而後經過索引找到磁盤相應數據,這也就是爲何索引不在key buffer命中時,速度慢的緣由。 redis
innodb中,在聚簇索引之上建立的索引稱之爲輔助索引,輔助索引訪問數據老是須要二次查找,非聚簇索引都是輔助索引,像複合索引、前綴索引、惟一索引,輔助索引葉子節點存儲的再也不是行的物理位置,而是主鍵值算法
爲何主鍵一般建議使用自增id?數據庫
聚簇索引的數據的物理存放順序與索引順序是一致的,即只要索引是相鄰的,那麼對應的數據必定也是相鄰地存放在磁盤上。若是不是自增id,那麼會不斷地調整數據的物理地址、分頁,而自增id只須要一頁一頁地寫,索引結構相對緊湊,磁盤碎片少,效率高。segmentfault
MyISAM的主索引爲非聚簇索引,所以其物理地址必然凌亂,拿到這些物理地址,按照合適的算法進行I/O讀取,而聚簇索引只須要一次I/O緩存
可是涉及大數據量的排序、全表掃描、count之類的操做的話,仍是MyISAM佔優點些,由於索引所佔空間小,這些操做是須要在內存中完成的。安全
適用場景服務器
聚簇索引適用在排序的場合數據結構
取出必定範圍數據的適合,使用聚簇索引多線程
維護索引很是昂貴,特別是插入新行或者主鍵被更新致使到分頁時
當使用UUID(隨機ID)做爲主鍵,使數據存儲稀疏,這就會出現聚簇索引有可能比全表掃描更慢
InnoDB是默認的表存儲引擎,其特色是行鎖設計、支持MVCC、支持外鍵、提供一致性非鎖定讀、同時被設計用來最有效的利用以及使用內存和CPU。
體系結構:
後臺線程主要負責刷新內存池中的數據、將已修改的數據刷新到磁盤等。
使用緩衝池技術來提升數據庫的總體性能,緩衝池就是一塊內存區域,在數據庫中進行取頁的操做。緩衝池中緩存的數據頁類型有:索引頁、數據頁、undo頁、插入緩衝、自適應哈希索引、innoDB的鎖信息、數據字典信息等。
關鍵特性:插入緩衝(insert buffer,爲了提升寫性能)、兩次寫(提升可靠性)、自適應哈希索引(經過緩衝池的B+樹頁構造而來,創建速度很是快,不須要對整張表構建哈希索引。innoDB存儲引擎會自動根據訪問的頻率和模式來自動地爲某些熱點頁創建哈希索引)、異步IO(AIO,提升磁盤操做性能,用戶能夠在發出一個IO請求後當即再發出另一個IO請求,當所有IO請求發送完畢後,等待全部IO操做完成。相對的是Sync IO,即每進行一次IO操做,都須要等待這次操做結束才能繼續接下來的操做)、刷新鄰接頁(InnoDB存儲引擎在刷新一個髒頁時,會檢測該頁所在區(extent)的全部頁,若是是髒頁,那麼一塊兒刷新。經過AIO能夠將多個IO寫操做合併爲一個IO操做)
咱們爲了設計索引的存儲結構,以前是創建平衡二叉樹,從而避免遍歷整張表,最壞狀況的時間複雜度是O(logN)->爲了當數據量很大時,下降時間複雜度,咱們須要創建其餘高度更低的樹->那麼經過在一個樹節點中包含多條數據,和包含多個指針域來實現。->進一步優化,B+樹是B樹的一種變體,查詢性能更好。B+樹是一種樹數據結構,n叉樹,每一個節點有多個孩子,一般用於數據庫和操做系統的文件系統中。
特色是可以保持數據穩定有序,其插入和修改擁有較穩定的對數時間複雜度。B+樹元素自底向上插入。
一個m階的B樹具備如下特徵:(即每一個節點最多包含m個孩子,m值取決於磁盤頁的大小)
如5階B樹中,結點最多有4個key,最少有2個key。
插入刪除時須要始終知足結點key的個數的限制條件。
m階的B+樹的特徵?
B+樹和B樹(balance tree)的區別?
1.有k個子結點的結點必然有k個關鍵碼
2.B+樹非葉結點僅具備索引做用,跟記錄有關的信息均存放在葉結點中,所以磁盤頁能容納更多節點元素,更「矮胖」
3.B+樹的全部葉結點構成一個有序鏈表,能夠按照關鍵碼排序的次序遍歷所有記錄
4.B+樹的查詢必須查找到葉子節點,而B樹只要匹配到便可不關注元素位置,所以B+樹查找更穩定
5.B+樹全部葉子節點自己根據關鍵字的大小進行鏈接,從而快速實現範圍查詢。
https://segmentfault.com/a/1190000019927682?utm_source=tag-newest
https://blog.csdn.net/Fmuma/article/details/80287924
事務是邏輯上的一組邏輯,要麼都執行,要麼都不執行。(經典例子:銀行轉帳)
四大特性(ACID):
* 原子性:事務是最小的執行單位,不容許分割
* 一致性:執行事務先後,數據保持一致,多個事務對同一數據讀取的結果是相同的。
* 隔離性:併發訪問數據庫時,一個用戶的事務不被其餘事務干擾,各併發事務之間的數據庫是獨立的。
* 持久性:*一個事務被提交後*,它對數據庫中數據的改變是持久的。即便數據庫發生故障也不該該對其有任何影響。
多個事務併發運行,常常會操做相同的數據來完成各自的任務(多個用戶對同一數據進行操做)
髒讀:當一個事務正在訪問數據而且對數據進行了修改,而這種修改尚未提交到數據庫中,這時另一個事務也訪問了這個數據,而後使用了這個數據。此時用到的數據是尚未提交的數據。
丟失修改:在一個事務讀取一個數據時,另一個事務也訪問了該數據,那麼在第一個事務中修改了這個數據後,第二個事務也修改了這個數據。這樣第一個事務內的修改結果就被丟失。
不可重複讀:指在一個事務內屢次讀同一數據。在這個事務尚未結束時,另外一個事務也訪問該數據。那麼,在第一個事務中的兩次讀數據之間,因爲第二個事務的修改致使第一個事務兩次讀取的數據可能不太同樣。這就發生了在一個事務內兩次讀到的數據是不同的狀況,所以稱爲不可重複讀。
幻讀:它發生在一個事務讀取了幾行數據,接着另外一個併發事務插入/刪除了一些數據時。在隨後的查詢中,第一個事務就會發現多了/少了一些本來不存在的記錄,就好像發生了幻覺同樣。
READ-UNCOMMITTED(讀取未提交): 最低的隔離級別,容許讀取還沒有提交的數據變動,可能會致使髒讀、幻讀或不可重複讀。
READ-COMMITTED(讀取已提交): 容許讀取併發事務已經提交的數據,能夠阻止髒讀,可是幻讀或不可重複讀仍有可能發生。
REPEATABLE-READ(可重複讀): 對同一字段的屢次讀取結果都是一致的,除非數據是被自己事務本身所修改,能夠阻止髒讀和不可重複讀,但幻讀仍有可能發生。
SERIALIZABLE(可串行化): 最高的隔離級別,徹底服從ACID的隔離級別。全部的事務依次逐個執行,這樣事務之間就徹底不可能產生干擾,也就是說,該級別能夠防止髒讀、不可重複讀以及幻讀。
爲了解決併發、數據安全的問題,採用鎖機制。
按照鎖粒度將數據庫鎖分爲表級鎖和行級鎖
表級鎖:對當前操做的整張表加鎖,實現簡單 ,資源消耗也比較少,加鎖快,不會出現死鎖 。其鎖定粒度最大,觸發鎖衝突的機率最高,併發度最低,MyISAM和 InnoDB引擎都支持表級鎖。當事務更新大表中大部分數據時直接使用表級鎖效率更高&事務複雜時,使用行級鎖可能會引發死鎖致使回滾。
行級鎖:只針對當前操做的行進行加鎖。 行級鎖能大大減小數據庫操做的衝突。其加鎖粒度最小,併發度高,但加鎖的開銷也最大,加鎖慢,會出現死鎖。InnoDB支持行級鎖
頁級鎖:粒度介於二者之間,一次鎖定相鄰的一組記錄。BDB支持頁級鎖。開銷和加鎖時間界於表鎖和行鎖之間,會出現死鎖。鎖定粒度界於表鎖和行鎖之間,併發度通常。
按照是否可寫分爲共享鎖和排他鎖:
共享鎖S:讀鎖,其餘用戶能夠併發讀取數據,但任何事務都不能獲取數據上的排他鎖,直到已釋放全部共享鎖。若是事務T對數據A加上共享鎖後,則其餘事務只能對A再加共享鎖,不能加排他鎖。
排它鎖X:寫鎖,防止任何其它事務獲取資源上的鎖,直到在事務的末尾將資源上的原始鎖釋放爲止。若是事務T對數據A加上排他鎖後,則其餘事務不能再對A加任任何類型的封鎖。
InnoDB另外的兩個表級鎖:(意向鎖是InnoDB自動加的,不須要用戶干預)
意向共享鎖IS:事務準備給數據行記入共享鎖,事務在一個數據行加共享鎖前必須先取得該表的IS鎖。
意向排它鎖IX:事務準備給數據行加入排他鎖,事務在一個數據行加排他鎖前必須先取得該表的IX鎖。
死鎖和避免死鎖
InnoDB的行級鎖是基於索引實現的,若是查詢語句爲命中任何索引,那麼InnoDB會使用表級鎖.
MyISAM老是一次性得到所需的所有鎖(採用表級鎖),InnoDB的鎖是逐步得到的(默認行級鎖)。當兩個事務都須要得到對方持有的鎖,致使雙方都在等待,從而產生死鎖。
InnoDB的行級鎖是基於索引實現的,若是查詢語句爲命中任何索引,那麼InnoDB會使用表級鎖。
避免死鎖的方式:使用表級鎖;多個程序儘可能約定以相同的順序訪問表;同一個事務儘量作到一次鎖定所須要的全部資源。
限定數據的範圍:禁止不帶任何限制數據範圍條件的查詢語句。
讀/寫分離:數據庫拆分,主庫負責寫,從庫負責讀。
垂直分區:根據數據庫裏面數據表的相關性進行拆分,把一張列比較多的表拆分爲多張表。可使列數據變小,減小I/O次數,簡化表的結構,易於維護;可是主鍵會出現冗餘,須要管理冗餘列,使事務變得更加複雜。
水平分區:保持數據表結構不變,經過某種策略存儲數據分片。使每一片數據分散到不一樣的表/庫中,實現分佈式。水平拆分最好分庫(數據庫分片的方案有客戶端代理:分片邏輯在應用端,封裝在jar包裏,經過修改或封裝JDBC層實現;中間件代理:在應用和數據中間加一個代理層,分片邏輯統一維護在中間件服務中)。支持很是大的數據量存儲,應用端改造也少,可是分片事務難以解決,帶來邏輯、部署、運維的各類複雜度。
初始預設資源,解決的問題就是抵消每次獲取資源的消耗,如建立線程的開銷,獲取遠程鏈接的開銷等。還包括池子的初始值、池子的活躍值、池子的最大值等。
最大的做用是支持複用,避免重複的建立銷燬帶來的開銷。
表明實現有java線程池、jdbc鏈接池、redis鏈接池等。
「單線程的方式:你們排隊一個一個取水,爲了避免浪費水,每一個人接完水後,關掉水龍頭,下一我的接的時候再打開水龍頭,開水龍和關水龍頭能夠當作建立和銷燬一個線程用於一我的的取水任務。這種方式適合人少的場景。
多線程的方式:多提供幾個水龍頭,這種方式適合人較多的場景,例如學生宿舍的公共水房。
線程池的方式:提供一個水池,先將水放到水池,而後由多我的同時在水池取水,水龍頭能夠不用頻繁開關,能夠支持多人併發取水,可是水池須要專人監管,如監控水池溢出,水池沒水,水池取水人員達到上限等。這種方式適合高併發的狀況。」
數據庫鏈接本質就是一個socket的鏈接。在鏈接池中,建立鏈接後,將其放置在池中,並再次使用它,所以沒必要創建新的鏈接。若是使用了全部鏈接,則會創建一個新鏈接並將其添加到池中。鏈接池還減小了用戶必須等待創建與數據庫的鏈接的時間。
JDK內置的四種線程池拒絕策略:調用者運行策略;停止策略;丟棄策略;dubbo/Netty/ActiveMq/pinpoint中的線程拒絕策略(第三方實現);
分紅多個表以後,每一個表都是從1開始累加,可是咱們應該是須要一個全局惟一的id來支持。生成全局id的方式有:
UUID:不適合做爲主鍵,無序不可讀,查詢效率低。
數據庫自增id:兩臺數據庫分別設置不一樣步長,生成不重複ID的策略來實現高可用。這種方式生成的id有序,可是須要獨立部署數據庫實例,成本高,且有性能瓶頸。
利用redis生成id:性能好,且靈活方便。可是引入新的組件形成系統更加複雜,可用性下降,編碼更加複雜,系統成本增長。
MySQL分爲Server層(全部跨存儲引擎的功能在此實現)和存儲引擎層(主要負責數據的存儲和讀取,採用能夠替換的插件式架構,支持InnoDB、MyISAM、Memory等)。
0.客戶端和server之間經過鏈接器鏈接,登陸MySQL時進行身份認證和權限相關。
1.應用程序把查詢SQL語句發送給服務器端執行
2.查詢緩存:接收到查詢請求後,並不會直接去數據庫查詢,而是在數據庫的查詢緩存中找是否有相應的查詢數據。若是語句不在查詢緩存中,就會繼續後面的執行階段,執行完成後,執行結果會被存入查詢緩存中。
3.查詢優化處理,生成執行計劃(若是沒有命中緩存)/將一個SQL轉換爲一個執行計劃
* 解析SQL:MySQL解析SQL語句,生成一棵對應的解析樹。
* 預處理:根據一些MySQL規則進一步檢查解析樹是否合法,如數據表和列是否存在,解析列名和別名,是否有歧義。
* 優化SQL執行計劃:優化器是在表裏面有多個索引的時候,決定使用哪一個索引;或者在一個語句有多表關聯的時候,決定各個表的鏈接順序,將SQL語句轉化成執行計劃,一條查詢能夠有不少種執行方式,最後都返回相同的結果,最後找到其中最好的執行計劃。
4.MySQL根據相應的執行計劃完成整個查詢:執行計劃是一個數據結構,其中有大量的操做須要經過調用存儲引擎實現的接口完成。
5.將查詢結果返回客戶端
大多數狀況下很正常,偶爾很慢
1.數據庫在刷新髒頁:redolog寫滿了;內存不夠用了;MySQL認爲系統「空閒」的時候;MySQL正常關閉的時候
2.執行時遇到鎖,如表鎖、行鎖。經過show processlist查看當前狀態
一直執行得很慢
1.沒用到索引,只能走全表掃描:字段沒有索引;字段有索引但沒有用上索引(若是字段左邊作了運算,那麼查詢時就不會用上索引。須要把運算放在字段右邊);函數操做致使沒有用上索引。
2.數據庫選錯索引:主鍵索引存放的值是整行字段的數據,非主鍵索引上存放的值不是整行字段的數據,而是存放主鍵字段的值。系統經過預測而選擇走全表掃描或者走索引,可是因爲統計的失誤,致使系統沒有走索引,而是走了全表掃描。