數據庫相關知識點


  • 二級索引

    • 聚簇索引:將數據存儲與索引放到了一塊,找到索引也就找到了數據。具有唯一性,聚簇索引默認是主鍵,如果表中沒有定義主鍵,InnoDB 會選擇一個唯一的非空索引代替。如果沒有這樣的索引,InnoDB 會隱式定義一個主鍵來作為聚簇索引。

    • 非聚簇索引:將數據存儲於索引分開結構,索引結構的葉子節點指向了數據的對應行,myisam通過key_buffer把索引先緩存到內存中,通過索引訪問數據,在內存中直接搜索索引,然后通過索引找到磁盤相應數據,這也就是為什么索引不在key buffer命中時,速度慢的原因。  

    • innodb中,在聚簇索引之上創建的索引稱之為輔助索引,輔助索引訪問數據總是需要二次查找,非聚簇索引都是輔助索引,像復合索引、前綴索引、唯一索引,輔助索引葉子節點存儲的不再是行的物理位置,而是主鍵值

    • 為什么主鍵通常建議使用自增id?

      聚簇索引的數據的物理存放順序與索引順序是一致的,即只要索引是相鄰的,那么對應的數據一定也是相鄰地存放在磁盤上。如果不是自增id,那么會不斷地調整數據的物理地址、分頁,而自增id只需要一頁一頁地寫,索引結構相對緊湊,磁盤碎片少,效率高。

      MyISAM的主索引為非聚簇索引,因此其物理地址必然凌亂,拿到這些物理地址,按照合適的算法進行I/O讀取,而聚簇索引只需要一次I/O

      但是涉及大數據量的排序、全表掃描、count之類的操作的話,還是MyISAM占優勢些,因為索引所占空間小,這些操作是需要在內存中完成的

    • 適用場景

      • 聚簇索引適用在排序的場合

      • 取出一定范圍數據的適合,使用聚簇索引

      • 維護索引非常昂貴,特別是插入新行或者主鍵被更新導致到分頁時

      • 當使用UUID(隨機ID)作為主鍵,使數據存儲稀疏,這就會出現聚簇索引有可能比全表掃描更慢

  • InnoDB索引底層數據結構

    • InnoDB是默認的表存儲引擎,其特點是行鎖設計、支持MVCC、支持外鍵、提供一致性非鎖定讀、同時被設計用來最有效的利用以及使用內存和CPU。

    • 體系結構:

    • 后台線程主要負責刷新內存池中的數據、將已修改的數據刷新到磁盤等。

      使用緩沖池技術來提高數據庫的整體性能,緩沖池就是一塊內存區域,在數據庫中進行取頁的操作。緩沖池中緩存的數據頁類型有:索引頁、數據頁、undo頁、插入緩沖、自適應哈希索引、innoDB的鎖信息、數據字典信息等。

    • 關鍵特性:插入緩沖(insert buffer,為了提高寫性能)、兩次寫(提高可靠性)、自適應哈希索引(通過緩沖池的B+樹頁構造而來,建立速度非常快,不需要對整張表構建哈希索引。innoDB存儲引擎會自動根據訪問的頻率和模式來自動地為某些熱點頁建立哈希索引)、異步IO(AIO,提高磁盤操作性能,用戶可以在發出一個IO請求后立即再發出另外一個IO請求,當全部IO請求發送完畢后,等待所有IO操作完成。相對的是Sync IO,即每進行一次IO操作,都需要等待此次操作結束才能繼續接下來的操作)、刷新鄰接頁(InnoDB存儲引擎在刷新一個臟頁時,會檢測該頁所在區(extent)的所有頁,如果是臟頁,那么一起刷新。通過AIO可以將多個IO寫操作合並為一個IO操作)

  • B+樹

    • 我們為了設計索引的存儲結構,之前是建立平衡二叉樹,從而避免遍歷整張表,最壞情況的時間復雜度是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):

       * 原子性:事務是最小的執行單位,不允許分割
      * 一致性:執行事務前后,數據保持一致,多個事務對同一數據讀取的結果是相同的。
      * 隔離性:並發訪問數據庫時,一個用戶的事務不被其他事務干擾,各並發事務之間的數據庫是獨立的。
      * 持久性:*一個事務被提交后*,它對數據庫中數據的改變是持久的。即使數據庫發生故障也不應該對其有任何影響。
  • 並發事務帶來哪些問題

    多個事務並發運行,經常會操作相同的數據來完成各自的任務(多個用戶對同一數據進行操作)

    • 臟讀:當一個事務正在訪問數據並且對數據進行了修改,而這種修改還沒有提交到數據庫中,這時另外一個事務也訪問了這個數據,然后使用了這個數據。此時用到的數據是還沒有提交的數據。

    • 丟失修改:在一個事務讀取一個數據時,另外一個事務也訪問了該數據,那么在第一個事務中修改了這個數據后,第二個事務也修改了這個數據。這樣第一個事務內的修改結果就被丟失。

    • 不可重復讀:指在一個事務內多次讀同一數據。在這個事務還沒有結束時,另一個事務也訪問該數據。那么,在第一個事務中的兩次讀數據之間,由於第二個事務的修改導致第一個事務兩次讀取的數據可能不太一樣。這就發生了在一個事務內兩次讀到的數據是不一樣的情況,因此稱為不可重復讀。

    • 幻讀:它發生在一個事務讀取了幾行數據,接着另一個並發事務插入/刪除了一些數據時。在隨后的查詢中,第一個事務就會發現多了/少了一些原本不存在的記錄,就好像發生了幻覺一樣。

  • 事務隔離級別有哪些?MySQL的默認隔離級別是?

    • READ-UNCOMMITTED(讀取未提交): 最低的隔離級別,允許讀取尚未提交的數據變更,可能會導致臟讀、幻讀或不可重復讀

    • READ-COMMITTED(讀取已提交): 允許讀取並發事務已經提交的數據,可以阻止臟讀,但是幻讀或不可重復讀仍有可能發生

    • REPEATABLE-READ(可重復讀):  對同一字段的多次讀取結果都是一致的,除非數據是被本身事務自己所修改,可以阻止臟讀和不可重復讀,但幻讀仍有可能發生

    • SERIALIZABLE(可串行化): 最高的隔離級別,完全服從ACID的隔離級別。所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,也就是說,該級別可以防止臟讀、不可重復讀以及幻讀

  • MySQL鎖機制與InnoDB鎖算法

    • 為了解決並發、數據安全的問題,采用鎖機制。

    • 按照鎖粒度將數據庫鎖分為表級鎖和行級鎖

      • 表級鎖:對當前操作的整張表加鎖,實現簡單 ,資源消耗也比較少,加鎖快,不會出現死鎖 。其鎖定粒度最大,觸發鎖沖突的概率最高,並發度最低,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:性能好,且靈活方便。但是引入新的組件造成系統更加復雜,可用性降低,編碼更加復雜,系統成本增加。

  • 一條SQL語句在MySQL中如何執行?

     

     

    MySQL分為Server層(所有跨存儲引擎的功能在此實現)和存儲引擎層(主要負責數據的存儲和讀取,采用可以替換的插件式架構,支持InnoDB、MyISAM、Memory等)。

    0.客戶端和server之間通過連接器連接,登錄MySQL時進行身份認證和權限相關。

    1.應用程序把查詢SQL語句發送給服務器端執行

    2.查詢緩存:接收到查詢請求后,並不會直接去數據庫查詢,而是在數據庫的查詢緩存中找是否有相應的查詢數據。如果語句不在查詢緩存中,就會繼續后面的執行階段,執行完成后,執行結果會被存入查詢緩存中。

    3.查詢優化處理,生成執行計划(如果沒有命中緩存)/將一個SQL轉換為一個執行計划

      * 解析SQL:MySQL解析SQL語句,生成一棵對應的解析樹。 
      * 預處理:根據一些MySQL規則進一步檢查解析樹是否合法,如數據表和列是否存在,解析列名和別名,是否有歧義。
      * 優化SQL執行計划:優化器是在表里面有多個索引的時候,決定使用哪個索引;或者在一個語句有多表關聯的時候,決定各個表的連接順序,將SQL語句轉化成執行計划,一條查詢可以有很多種執行方式,最后都返回相同的結果,最后找到其中最好的執行計划。

    4.MySQL根據相應的執行計划完成整個查詢:執行計划是一個數據結構,其中有大量的操作需要通過調用存儲引擎實現的接口完成。

    5.將查詢結果返回客戶端

  • 一條SQL語句執行得很慢的原因有哪些?

    • 大多數情況下很正常,偶爾很慢

      1.數據庫在刷新臟頁:redolog寫滿了;內存不夠用了;MySQL認為系統“空閑”的時候;MySQL正常關閉的時候

      2.執行時遇到鎖,如表鎖、行鎖。通過show processlist查看當前狀態

    • 一直執行得很慢

      1.沒用到索引,只能走全表掃描:字段沒有索引;字段有索引但沒有用上索引(如果字段左邊做了運算,那么查詢時就不會用上索引。需要把運算放在字段右邊);函數操作導致沒有用上索引。

      2.數據庫選錯索引:主鍵索引存放的值是整行字段的數據,非主鍵索引上存放的值不是整行字段的數據,而是存放主鍵字段的值。系統通過預測而選擇走全表掃描或者走索引,但是由於統計的失誤,導致系統沒有走索引,而是走了全表掃描。


  • 免責聲明!

    本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



     
    粵ICP備18138465號   © 2018-2025 CODEPRJ.COM