MySql優化之索引

mysql優化

在日常的開發中,我們大多數都是和數據庫打交道的。而數據庫在項目中其着至關重要的作用,因此數據庫優化的實現,對我們的項目有着非常顯著的作用。而一般的數據庫庫優化可以分爲下面幾個方面。

設計方面

  1. 字段類型的選項,根據存儲數據的長度儘可能的佔用更少的存儲空間,儘可能定長,儘可能使用整數代替字符,像存儲ip可以轉換成整數進行存儲。
  2. 實體間的關係設計
  3. 範式的選擇
  4. 存儲引擎的選擇,我們一般用到的是innodb和mysiam,
    • MyISAM: 擅長處理快速的查詢和插入. 典型的web程序的形態.
    • Innodb: 擅長大量併發, 處理大量的更新操作. 支持事務, 外鍵約束.

功能方面

  1. 索引,使用索引,共分爲四種,普通索引,唯一索引,主鍵索引,全文索引。
  2. 查詢緩存,可以修改配置文件,進行查詢數據的緩存。
  3. 分表分區,使用partition關鍵字進行分區,然後根據插入的數據,根據分區算法,算出要存儲到那個分區,常用的分區算法:
    • hash,均勻分配,提供一個整數值字段, 利用該字段的值, 對分區數量進行求餘, 劃分分區。
    • key,支持非整數字段, 先利用該字段, 計算整數值(類似crc32), 然後, 再求餘運算.
    • list,需要提供每個分區所存儲數據的邏輯條件. 滿足條件的數據, 可以被存儲到該分區中。
    • range,提供一個小於表達式, 作爲分區的條件。僅僅支持小於表達式。

架構層面

  1. 負載均衡集羣,將負載(工作任務,訪問請求)進行平衡、分攤到多個操作單元(服務器,數據庫)上進行執行。是解決高性能,單點故障(高可用),擴展性(水平伸縮)的終極解決方案。
  2. 讀寫分離的處理,將讀,寫操作, 分開到不同的MySQL服務器完成. 稱之爲讀寫分離.注意主從複製。
  3. 冷熱數據分離,常用與不常用的數據分開。

應用層面(SQL應該如何寫)

  1. 多表聯查
  2. 單表查詢
  3. 儘可能避免哪些低效的SQL

索引

索引(index): 採用完整數據中的部分內容作爲關鍵字, 建立於完整數據位置間的 一種映射關係, 稱之爲索引。簡單來說就是關鍵字於記錄位置的映射, 就是索引.

索引是最常規, 最重要的優化措施。在不改變設計結構, 不增加分佈式的數據庫服務器的基礎上, 提升查詢速度!也是性價比最高一種優化措施。

使用索引優點

  1. 大大加快數據的檢索速度;
  2. 創建唯一性索引,保證數據庫表中每一行數據的唯一性;
  3. 加速表和表之間的連接;
  4. 在使用分組和排序子句進行數據檢索時,可以顯著減少查詢中分組和排序的時間。

但是如要注意的注意的是:索引需要佔物理空間。並且當對錶中的數據進行增加、刪除和修改的時候,索引也要動態的維護,降低了數據的維護速度。

在mysql中共分爲四種索引

  1. 普通索引,對關鍵字沒有要求。
  2. 唯一索引,要求關鍵字不能重複。
  3. 主鍵索引,主鍵自動成爲主鍵索引。
  4. 全文索引,我們通常使用插件來完成全文索引。

主鍵索引

我們在創建一張表的時候,往往是需要指定一個主鍵的,使用PRIMARY KEY關鍵字進行聲明當前的字段是主鍵字段,主鍵字段是不能重複並且不能爲空的。

主鍵索引的創建

主鍵索引可以在建表的時候,直接指定,也可以在創完表後手動的指定。

  • 建表時指定

    create table student_index(
        id int auto_increment, 
        name varchar(20),
        -- 建表的時候,直接指定主鍵是哪個字段。
        PRIMARY KEY (id)
    )charset=utf8 engine = myisam;
    
  • 建表過後指定

    alter table student_index add primary key (id);
    

在一個表中,最多只能有一個主鍵。並且主鍵索引的速度最快,效率最高。主鍵索引通常表的一個字段,整型的,並且是auto_increment(自增長)。

創建完主鍵索引後,可以使用show index from 表名\G指令查看當前表的索引。

mysql> show  index  from student_index\G
*************************** 1. row ***************************
        Table: student_index
   Non_unique: 0
     Key_name: PRIMARY(索引名)
 Seq_in_index: 1
  Column_name: id(索引id)
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null:
   Index_type: BTREE(索引類型)
      Comment:
Index_comment:
1 row in set (0.13 sec)

主鍵索引的刪除

當我們不想使用主鍵的時候,我們可以刪除主鍵索引,刪除主鍵:

ALTER TABLE 表名 DROP PRIMARY KEY;

刪除主鍵時,如果主鍵時自增長,這時需要把自增長去掉,才能正確的刪除主鍵。

ALTER TABLE student_index modify id int;

刪除完畢後,使用show index from 表名\G,可以看到是爲空的。

唯一索引

當我們在創建表時,希望一個字段的值是不能重複的,我們可以設置當前字段爲唯一索引。使用unique關鍵字進行聲明。

唯一索引的創建

唯一索引的創建也是分爲兩種的,創建表的時候直接指定,創建完畢之後在指定。

  • 建表時指定

    create table student_index(
        id int,
        name varchar(20),
        student_id int,
        -- 指定student_id爲唯一索引
        unique key (student_id)
    )charset=utf8 engine = myisam;
    
  • 建表過後指定

    ALTER TABLE student_index ADD UNIQUE (student_id);
    

在一個表中可以有多個唯一索引,唯一索引的列的值不能重複,但是可以爲空(如果你設置了)。

創建完唯一索引後,可以使用show index from 表名\G指令查看當前表的索引。

mysql> show  index  from student_index\G
*************************** 1. row ***************************
        Table: student_index
   Non_unique: 0
     Key_name: student_id
 Seq_in_index: 1
  Column_name: student_id
    Collation: A
  Cardinality: NULL
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment:
Index_comment:
1 row in set (0.00 sec)

唯一索引的刪除

當然,我們也可以刪除唯一索引的。

ALTER TABLE 表名 DROP INDEX 索引名;

刪除完畢後,使用show index from 表名\G,可以看到是爲空的。

普通索引

我們在一張表中如果某個字段,不是主鍵,也不是唯一的值,有好多的重複值,這時就可以創建普通索引

普通索引的創建

  • 建表時指定

    create table student_index(
        id int,
        name varchar(20),
        student_id int,
        -- 創建普通索引
        index (name)
    )charset=utf8 engine = myisam;
    
  • 建表過後指定

    ALTER TABLE student_index ADD INDEX (name);
    

在一個表中,可以有多個普通索引,如果我們某個字段的值,存在重複的記錄,那麼我們只能選擇普通索引,因此普通索引使用的是最多.
使用show index from 表名\G指令查看當前表的索引。

普通索引的刪除

當然,我們也可以刪除普通索引的。

ALTER TABLE 表名 DROP INDEX 索引名;

刪除完畢後,使用show index from 表名\G,可以看到是爲空的。

索引的使用

我們創建索引的目的是爲了提高查找數據的效率,當我們寫完sql語句之後,mysql會根據sql語句的結構,自動的啓用索引,一般是在where,order by,join這三個關鍵字後面的字段如果存在索引,就會啓用索引。
並且如果我們查詢的字段如果是索引,也是會啓用索引的。

在這裏我構建一張大容量的表,數據量爲七百萬條數據,因爲索引只用在數據非常多時候才能看出來明顯的效果。

explain – 獲取執行計劃

explain關鍵字的作用,就是獲取當前sql語句的執行計劃。

當我們從客戶端輸入sql語句到我們得到結果,其中是有一些過程的。

這裏寫圖片描述

如果我們在sql語句的前面添加explain關鍵字,我們得到的數據就不是查詢的數據而是如圖中的執行計劃。

mysql> explain select * from student where id = 253219\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE -- 簡單的查詢
        table: student -- 查詢的那張表
         type: const -- 最快的一種查詢,僅僅需要匹配一條記錄
possible_keys: PRIMARY 
          key: PRIMARY -- 真正會用到的索引
      key_len: 4
          ref: const
         rows: 1 -- 估計需要從數據庫中獲取1條數據即可。
        Extra:
1 row in set (0.00 sec)

由sql語句可知,我們的id是主鍵索引,所以在執行計劃中sql開啓可primary索引,進行數據的查找。

如果我們的sql語句中並沒有使用到索引,那麼mysql並不會啓用索引。

mysql> explain select * from student where first_name like '%C%'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: student
         type: ALL
possible_keys: NULL
          key: NULL 
      key_len: NULL
          ref: NULL
         rows: 7855683
        Extra: Using where
1 row in set (0.00 sec)

可以看到並沒有開啓索引。

上面我們說過,在where,order by,join關鍵字後面的關鍵字如果有索引,都會啓用索引進行數據的查找,這裏可以使用explain關鍵字,查看執行計劃進行驗證。

索引的創建

在上面我們知道使用索引,會大大的縮短查詢數據的時間,但是我們應該在那些字段上建立索引呢?

創建索引需要了解表的結構,同時明白我們在該表上常執行的sql語句並且統計SQL的權重以及頻率。
結構+操作是決定索引的要素.

同時如果們可以where,orderby, join 所對應的字段後邊增加索引。

索引的數據結構

創建完索引,索引的存儲可以分爲三種:

  • BTree索引
  • 聚簇索引(B+Tree)
  • Hash索引

BTree索引

BTree數據結構是索引存儲在磁盤上的不二選擇。BTree是一中排序完成的結構。可以看成是一個層級的結構,每層中都是排序好的關鍵字。

一個Btree的節點, 存儲多個排序好的索引關鍵字,而關鍵字之間是子節點指針,指向下一個BTree節點。

這裏寫圖片描述

在圖中可以看到數據是按照某種順序進行排序的,這樣在查詢的時候,就可以快速的得到想要的結果,圖中只是簡單的描述了兩層。

BTree的數據結構最重要的特點: 減少磁盤IO, 增加獲取的關鍵字的數量。一層節點的大小, 取決於一次性磁盤IO的數據大小, 512(K)Bytes. 2者保持一致可以保證, 一次磁盤IO讀取開銷, 儘可能多的獲取關鍵字數量。假設, 關鍵字的大小, 導致一個節點可以存儲1000個關鍵字. 那麼2層的Btree可以存儲
1000 + (1000+1)*1000 = 100w意味着, 2次磁盤開銷 就可以在100w的關鍵字中進行檢索!

MySQL的無論創建的(普通, 唯一, 主鍵, 全文)索引, 都是存在在Btree結構中。

聚簇索引, B+Tree

B+Tree, 是在Btree的基礎上, 做了些調整和一些變化。

當我們mysql的存儲引擎選擇是innodb的時候,我們向數據庫中插入數據, innodb的記錄的順序, 依據表中的主鍵進行排序的。

在MySQL的所有表的索引中, 只有一個索引例外, 不是存儲在BTree結構中, 就是innodb表的主鍵索引.
而是存儲在B+Tree中.B+Tree是一個聚簇(聚集)結構。
典型的結構特徵:

這裏寫圖片描述

索引的關鍵字是和索引對應的記錄存儲在一起。

由於記錄和主鍵存儲在一起,記錄的位置是不固定。
那麼innodb的非主鍵索引, 不是聚簇的, 存儲記錄位置時, 不是存儲的磁盤位置, 而是存儲的是, 記錄的主鍵值.
如果使用innodb進行檢索, 先是利用關鍵字, 確定主鍵值, 再利用主鍵值, 在聚簇的主索引上, 找到記錄. 需要經過二次檢索。

Hash索引

hash, 利用key可以快速獲取一個對應的值, 就是hash算法.而hash索引, 就是利用關鍵字, 就可以快速的確定關鍵字對應的記錄位置.

hash索引, 利用內存的快速尋址達到的目的。僅僅在磁盤上的索引被載入內存時, 纔會被轉換成hash結構, 便於在內存中快速確定。是內部優化的措施, 而不是存儲磁盤上索引的措施.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章