1. 程式人生 > >MySQL(邏輯分層,儲存引擎,sql優化,索引優化以及底層實現(B+Tree))

MySQL(邏輯分層,儲存引擎,sql優化,索引優化以及底層實現(B+Tree))

一 , 邏輯分層

  

連線層:連線與執行緒處理,這一層並不是MySQL獨有,一般的基於C/S架構的都有類似元件,比如連線處理、授權認證、安全等。

服務層:包括快取查詢、解析器、優化器,這一部分是MySQL核心功能,包括解析、優化SQL語句,查詢快取目錄,內建函式(日期、時間、加密等函式)的實現。

引擎層:負責資料儲存,儲存引擎的不同,儲存方式、資料格式、提取方式等都不相同,這一部分也是很大影響資料儲存與提取的效能的;對儲存層的抽象。

儲存層:儲存資料,檔案系統。

二 , 儲存引擎

檢視資料庫支援的儲存引擎:show engines;

如果要想檢視資料庫預設使用哪個引擎,可以通過使用命令: show variables like '%storage_engine%';

指定資料庫物件的引擎:
create table tb(
id int(4) auto_increment ,
name varchar(5),
dept varchar(5) ,
primary key(id)
)ENGINE=MyISAM AUTO_INCREMENT=1
DEFAULT CHARSET=utf8 ;

檢視建表語句:show create table default_table;

InnoDB,MyISAM的主要區別:

InnoDB:在MySQL5.5開始作為預設的儲存引擎,支援事務,行級鎖,適合高併發場景,XA協議支援分散式事務。

MyISAM:不支援事務,效能優先,表級鎖,不適合高併發場景。

三, sql優化

  3.1.1  mysql 內部實現索引原理(B+Tree)  參考(https://blog.csdn.net/chuixue24/article/details/80027689)

    3.1.1.1 ,  二叉樹

      

     3.1.1.2 ,  B-Tree

          

        B-Tree中的每個節點根據實際情況可以包含大量的關鍵字資訊和分支,如下圖所示為一個3階的B-Tree: 
        索引

每個節點佔用一個盤塊的磁碟空間,一個節點上有兩個升序排序的關鍵字和三個指向子樹根節點的指標,指標儲存的是子節點所在磁碟塊的地址。兩個關鍵詞劃分成的三個範圍域對應三個指標指向的子樹的資料的範圍域。以根節點為例,關鍵字為17和35,P1指標指向的子樹的資料範圍為小於17,P2指標指向的子樹的資料範圍為17~35,P3指標指向的子樹的資料範圍為大於35。

      模擬查詢關鍵字29的過程:

      1. 根據根節點找到磁碟塊1,讀入記憶體。【磁碟I/O操作第1次】 
      2. 比較關鍵字29在區間(17,35),找到磁碟塊1的指標P2。
      3. 根據P2指標找到磁碟塊3,讀入記憶體。【磁碟I/O操作第2次】
      4. 比較關鍵字29在區間(26,30),找到磁碟塊3的指標P2。
      5. 根據P2指標找到磁碟塊8,讀入記憶體。【磁碟I/O操作第3次】
      6. 在磁碟塊8中的關鍵字列表中找到關鍵字29。

    分析上面過程,發現需要3次磁碟I/O操作,和3次記憶體查詢操作。由於記憶體中的關鍵字是一個有序表結構,可以利用二分法查詢提高效率。而3次磁碟I/O操作是影響整個B-Tree查詢效率的決定因素。

      B-Tree相對於AVLTree縮減了節點個數,使每次磁碟I/O取到記憶體的資料都發揮了作用,從而提高了查詢效率。

     3.1.1.3 ,  B+Tree(查詢任意資料的次數是 n)

      B+Tree是在B-Tree基礎上的一種優化,使其更適合實現外儲存索引結構,InnoDB儲存引擎就是用B+Tree實現其索引結構。

從上一節中的B-Tree結構圖中可以看到每個節點中不僅包含資料的key值,還有data值。而每一個頁的儲存空間是有限的,如果data資料較大時將會導致每個節點(即一個頁)能儲存的key的數量很小,當儲存的資料量很大時同樣會導致B-Tree的深度較大,增大查詢時的磁碟I/O次數,進而影響查詢效率。在B+Tree中,所有資料記錄節點都是按照鍵值大小順序存放在同一層的葉子節點上,而非葉子節點上只儲存key值資訊,這樣可以大大加大每個節點儲存的key值數量,降低B+Tree的高度。

B+Tree相對於B-Tree有幾點不同:

  1. 非葉子節點只儲存鍵值資訊。
  2. 所有葉子節點之間都有一個鏈指標。
  3. 資料記錄都存放在葉子節點中。

將上一節中的B-Tree優化,由於B+Tree的非葉子節點只儲存鍵值資訊,假設每個磁碟塊能儲存4個鍵值及指標資訊,則變成B+Tree後其結構如下圖所示: 
索引

通常在B+Tree上有兩個頭指標,一個指向根節點,另一個指向關鍵字最小的葉子節點,而且所有葉子節點(即資料節點)之間是一種鏈式環結構。因此可以對B+Tree進行兩種查詢運算:一種是對於主鍵的範圍查詢和分頁查詢,另一種是從根節點開始,進行隨機查詢。

上面都應該知道B+Tree 了吧,所以我們在建立索引時,會生成一個B+Tree  如果我們在只查詢索引欄位時,sql 語句就直接去B+Tree 查,不會再去資料表中查了,這樣提升效能是很重要的。 還有就是對於總是修改的欄位不要對他建立索引,因為欄位修改了,B+Tree 結構就要重構,這要是會降低效能的。

  3.1.1 索引分類:

      主鍵索引:是一種特殊的唯一索引,一個表只能有一個主鍵,不允許有空值。一般是在建表的時候某一列定為主鍵時,就預設的建立了對應的主鍵索引。

      唯一索引:索引列的值必須唯一,但允許有空值。

      單列索引:對於表中的某一列,新增的索引。

      複合索引:多個列構成的索引(跟書的一級,二級,三級 目錄一樣),使用時要遵循最佳左字首特性,如果我們建立了(area, age, salary)的複合索引,那麼其實相當於建立了(area,age,salary)、(area,age)、(area)三個索引。

           因此我們在建立複合索引時應該將最常用作限制條件的列放在最左邊,依次遞減。

 

   3.2.2 如何正確的建立索引呢?

      3.2.2、建立索引      

         create 索引型別 索引名 on 表(欄位)
         單值:  create index dept_index on tb(dept);
         唯一:create unique index name_index on tb(name) ;
         複合索引: create index dept_name_index on tb(dept,name);

        查詢索引:
          show index from 表名 ;
          show index from 表名 \G

        刪除索引:
          drop index 索引名 on 表名 ;
          drop index name_index on tb ;

      3.2.2、SQL解析順序          接下來再走一步,讓我們看看一條SQL語句的前世今生。         首先看一下示例語句             SELECT DISTINCT  .....   FROM .....  JOIN  .....  ON   .....  WHERE.....   GROUP BY    .....   HAVING  .....   ORDER BY   .....   LIMIT ..... 

            然而它的執行順序是這樣的

            FROM   .....  ON  .....    JOIN  .....   WHERE     ..... GROUP BY     .....  HAVING  .....    SELECT    DISTINCT   .....  ORDER BY   .....  LIMIT   .....

         3.2.3 如何建立索引           

      一般說來,索引應建立在那些將用於JOIN,WHERE判斷和ORDERBY排序的欄位上。儘量不要對資料庫中某個含有大量重複的值的欄位建立索引。對於一個ENUM型別的欄位來說,出現大量重複值是很有可能的情況.

      3.2.4     使用索引時,有一些技巧:

          1.索引不會包含有NULL的列

           只要列中包含有NULL值,都將不會被包含在索引中,複合索引中只要有一列含有NULL值,那麼這一列對於此符合索引就是無效的。

         2. 索引要建立在經常進行select操作的欄位上。而經常修改的欄位,沒沒必要建立索引了,因為,你建立了索引會生成一個B+樹,你修改了該索引的欄位後,這個B+樹就需要修改,反而對效能不是很好。

         3. 複合索引 : 複合索引,不要跨列或無序使用(最佳左字首)

         4.like語句操作: 一般情況下不鼓勵使用like操作,如果非使用不可,注意正確的使用方式。like ‘%aaa%’不會使用索引,而like ‘aaa%’可以使用索引。

            5. 不要在索引上進行任何操作(計算、函式、型別轉換),否則索引失效

            6.不使用NOT IN 、<>、!=操作,但<,<=,=,>,>=,BETWEEN,IN是可以用到索引的

            7.索引要建立在經常進行select操作的欄位上。

               這是因為,如果這些列很少用到,那麼有無索引並不能明顯改變查詢速度。相反,由於增加了索引,反而降低了系統的維護速度和增大了空間需求。

            8.索引要建立在值比較唯一的欄位上。

            9.對於那些定義為text、image和bit資料型別的列不應該增加索引。因為這些列的資料量要麼相當大,要麼取值很少。

            10.在join操作中(需要從多個數據表提取資料時),mysql只有在主鍵和外來鍵的資料型別相同時才能使用索引,否則及時建立了索引也不會使用。

 三, sql效能問題

    a.分析SQL的執行計劃  : explain   ,可以模擬SQL優化器執行SQL語句,從而讓開發人員 知道自己編寫的SQL狀況

    b.MySQL查詢優化其會干擾我們的優化(mysql服務層有一個sql優化器),可以對我們寫的sql進行優化,這是我們控制不了的。

    查詢執行計劃:  explain +SQL語句     explain SELECT * from book ;

      

    

id : 編號
select_type :查詢型別
table :表
type :索引型別 system>const>eq_ref>ref>range>index>all ,要對type進行優化的前提:有索引 一般能達到range 就行。
possible_keys :預測用到的索引
key :實際使用的索引
key_len :實際使用索引的長度
ref :表之間的引用
rows :通過索引查詢到的資料量
Extra :額外的資訊 下面是他可能發出的情況

  i). using filesort : 效能消耗大;需要“額外”的一次排序(查詢)  。常見於 order by 語句中。 解決:where哪些欄位,就order by那些欄位2

  ii). using temporary:效能損耗大 ,用到了臨時表。一般出現在group by 語句中。 解決: 避免:查詢那些列,就根據那些列 group by .

  iii). using index :效能提升; 索引覆蓋(覆蓋索引)。原因:不讀取原檔案,只從索引檔案中獲取資料 (不需要回表查詢)
只要使用到的列 全部都在索引中,就是索引覆蓋using index

  iii).using where (需要回表查詢)。

    假設age是索引列
    但查詢語句select age,name from ...where age =...,此語句中必須回原表查Name,因此會顯示using where.  解決 吧name  也新增到