索引那些事兒----基於Mysql



武漢加油!!!

背景

數據庫是什麼? 這個問題大家都知道吧, 用來存放數據的, 生活中你在銀行中存的金額, 或者一個戶籍所中存放的戶籍以及個人信息, 在比如一個學校的學生信息等等, 這些都存放在我們的數據庫裏面. 對不數據庫中的數據一般採用一些DML語句(insert, update, delete)來進行數據操作. 想要查看數據庫裏面的數據使用select語句進行數據的查詢.

對於數據在數據庫裏面的存放, 可以簡單理解爲類似Excel表格, 表格裏面每一行代表一條數據. 一個Sheet頁來代表一類數據.
一個例子 現在我們有一張excel表格, 裏面存放了一個學校的學生信息, 包含學號, 姓名, 班級,年級等等信息

  • 如果, 如果這張表裏面只存放了較少的數據(幾十條, 或者十幾條), 那現在讓你找到關於張三學生的信息, 我們便開始從上到下或者從下到上開始瀏覽每一行數據, 直到找到張三, 便完成了數據的查詢.
  • 但是, 數據量大了, 這個excel存放了成千上萬條數據, 再讓你找出來張三, 你還是需要從上到下, 或者從下到上開始找張三, 這一次因爲數據變多了, 導致你可能一眼找到張三, 可能要瀏覽一段時間才能找出來張三.

上面的例子, 便是一個數據查詢經典的問題, 那麼如何解決這個問題呢? 通過索引即可

另一個例子 張三買了一本書《鋼鐵是怎樣煉成的》看完了一遍之後, 時隔半年突然想起了人最寶貴的東西是生命.生命對人來說只有一次.因此,人的一生應當這樣度過:當一個人回首往事時,不因虛度年華而悔恨,也不因碌碌無爲而羞愧.. 但是忘記了後半句, 只記得是在某一章(我記得是好像是在整書結尾來着), 然後張三通過目錄找到了這一章, 很快便從這一章裏面找到了這句話的後半句.

那麼這個目錄便可以理解爲一個索引, 最主要的目的就是加快查詢的速度

索引

在上面通過兩個生活中的例子, 描述了索引是什麼以及索引的功能, 在我們的數據庫中, 道理也是一樣的,
索引: 索引用於快速找出在某個列中有一特定值的行,不使用索引,MySQL必須從第一條記錄開始讀完整個表,直到找出相關的行,表越大,查詢數據所花費的時間就越多,如果表中查詢的某列有一個索引,MySQL能夠快速到達一個位置去搜索數據文件,那麼將會節省很大一部分時間
索引存儲類型: 當把某一列作爲索引的時候, 數據查詢就變成了 先找索引, 再根據索引找這一條數據. 爲了進一步提升所以的查詢效率, 就引入了一些數據結構算法來提升效率MySQL中的索引的存儲類型有兩種:BTREE、HASH。 也就是用樹或者Hash值來存儲該字段

  • 優點:
    • 理論上任何字段類型都可以被建立索引.
    • 顯著提高查詢的速度
  • 缺點:
    • 索引的創建需要消耗時間, 並且索引也需要維護, 維護的也會增加工作量
  • 何時使用 :
    • 對於經常作爲查詢條件的字段優先建立索引
    • 數據經常變動的表避免過多建立索引
    • 數據量較小的表, 儘可能不去建立索引, 因爲由於數據較少可能查詢全部花費的時間比遍歷索引時間更少.

存儲引擎

對於Mysql首先要知道的是:索引是在存儲引擎中實現的,也就是說不同的存儲引擎,會使用不同的索引, 所以先來認識一下mysql幾種存儲引擎.

MySQL有一個被稱爲“Pluggable Storage Engine Architecture”(可替換存儲引擎架構)的特性,也就意味着MySQL數據庫提供了多種存儲引擎。用戶可以根據不同的需求爲數據表選擇不同的存儲引擎,用戶也可以根據自己的需要編寫自己的存儲引擎。

存儲引擎種類
引擎名稱 解釋
CSV 基於 CSV 格式文件存儲數據(應用於跨平臺的數據交換)
Archive 將數據壓縮後進行存儲,非常適合存儲大量的獨立的,作爲歷史記錄的數據,但是隻能進行插入查詢操作
Falcon 一種新的存儲引擎,支持事物處理
Memory 內存存儲引擎,擁有極高的插入,更新和查詢效率。但是會佔用和數據量成正比的內存空間。只在內存上保存數據,意味着數據可能會丟失
MRG_MyISAM(MERGE) 將多個表聯合成一個表使用,在超大規模數據存儲時很有用
ISAM MyISAM的前身,MySQL5.0以後不再默認安裝
MyISAM 高速引擎,擁有較高的插入,查詢速度,但不支持事務
InnoDB 5.5版本後MySQL的默認數據庫,支持事務和行級鎖定,比MyISAM處理速度稍慢

表格中列舉的是Mysql支持的幾種存儲引擎的, 其中後兩種是生產開發中使用最多的方案, 下面我們重點介紹一下.

MyISAM引擎

這種引擎又可以細分爲動態, 靜態, 壓縮三種:

  • 靜態MyISAM:如果數據表中的各數據列的長度都是預先固定好的,服務器將自動選擇這種表類型。因爲 數據表中每一條記錄所佔用的空間都是一樣的,所以這種表存取和更新的效率非常高。

  • 動態MyISAM:如果數據表中出現varcharxxxtext或xxxBLOB字段時,服務器將自動選擇這種表類型。相對於靜態MyISAM,這種表存儲空間比較小,但由於每條記錄的長度不一,所以多次修改數據後,數據表中的數據就可能離散的存儲在內存中,進而導致執行效率下降。同時,內存中也可能會出現很多碎片。因此,這種類型的表要經常用optimize table 命令或優化工具來進行碎片整理

  • 壓縮MyISAM:以上說到的兩種類型的表都可以用myisamchk工具壓縮。這種類型的表進一步減小了佔用的存儲,但是這種表壓縮之後不能再被修改。另外,因爲是壓縮數據,所以這種表在讀取的時候要先時行解壓縮。

  • 優點: 有着較高的查詢和寫入速度, 獨立於操作系統, 不受 win 和linux的限制

    • 適用於選擇密集型的表。MyISAM存儲引擎在篩選大量數據時非常迅速,插入密集型的表。MyISAM的併發插入特性允許同時選擇和插入數據。
  • 缺點: 不支持事務

InnoDB引擎

InnoDB表類型可以看作是對MyISAM的更新產品,它提供了事務行級鎖機制外鍵約束的功能, 而且還支持子等增加列AUTO_INCREMENT屬性.

不過, 因爲它會在主內存中建立其專用的緩衝池用於高速緩衝數據和索引, 所以InnoDB的表比MyISAM需要更多的內存和存儲.

==備註, 即便在同一個數據庫中, 也可以將多種存儲引擎混用, 如果需要支持事務, 可以選擇InnoDB, 如果該數據庫需要一個用於查詢的臨時表,可以選擇MEMORY存儲引擎 ==

索引方式

在mysql中 InnoDB和MyISAM引擎默認存儲索引的結構爲B+Tree, 並且此處B+樹索引又分爲了兩類

  • 聚集索引:指索引項的排序方式和表中數據記錄排序方式一致的索引,每張表只能有一個聚集索引,聚集索引的葉子節點存儲了整個行數據。
    一個例子: 新華字典, 大家都用過吧, 把字典看做一張具體的數據表, 那麼字典的目錄就是聚集索引, 並且字典中的拼音目錄是根據從a到z來進行排列的, 而且字典中每個字也是按照拼音的首部a-z進行排列的, 這就是索引項的排序方式和表中數據記錄排序方式一致。
    真實場景 對於InnoDB引擎表, 通常我們會設置一個主鍵, 並且多數時候主鍵是自增的, 那此刻主鍵便是一個聚集索引, 如果我們對一張數據表沒有明確設定主鍵的時候, 對於InnoDB引擎表又怎麼處理呢?

    • 首先, 如果一張表主鍵被定義了, 那麼這個主鍵就是一個聚集索引
    • 其次, 如果主鍵沒有被顯示的定義, 那個該表的第一個唯一非空索引會作爲聚集索引
    • 最後, 如果沒有主鍵, 並且唯一索引裏面裏面也沒有合適的, 那麼innodb內部會生成一個隱藏的主鍵作爲聚集索引,這個隱藏的主鍵是一個6個字節的列,該列的值會隨着數據的插入自增。
  • 非聚集索引:非聚集索引中索引的邏輯順序與磁盤上行的物理存儲順序不同,一個表中可以擁有多個非聚集索引。葉子節點並不包含行記錄的全部數據。葉子節點除了包含鍵值以外,還存儲了一個指向改行數據的聚集索引建的書籤。

在這裏我們引入了一個詞, 唯一索引有人可能會看不懂, 這個下面即將說到的索引類型的中的一種, 相信看完後續篇幅應該就明白了.

索引類型

爲了提高查詢的效率, 我們才使用了索引, 但是索引爲了應對不同的場景又分爲如下幾種

  • 單列索引
    • 普通索引
    • 唯一索引
    • 主鍵索引
  • 組合索引
  • 全文索引
  • 空間索引
單列索引之普通索引

首先要明白的是, 單列索引是指, 一個索引只包含一個列, 但是一個表中可以建立多個單列索引
下面在來看普通索引, 顧名思義, 就是把在某一張數據表中的某一列作爲索引, 是Mysql中最基本的索引類型, 沒有什麼限制並且允許在定義索引的列中插入重複值和空值

創建方式

  • 直接創建索引
CREATE INDEX index_name ON table(column(length));
  • 修改表結構方式創建索引
ALTER TABLE table_name ADD INDEX index_name ON (column(length));
  • 創建表的時候創建索引
CREATE TABLE `table` (
    `id` int(11) NOT NULL AUTO_INCREMENT ,
    `column1` char(255) CHARACTER NOT NULL ,
    `column2` text CHARACTER NULL ,
    PRIMARY KEY (`id`),
    INDEX index_name (column1(length))
)
單列索引之唯一索引

普通索引類似,不同的就是:索引列的值必須唯一,但允許有空值。如果是組合索引,則列值的組合必須唯一, 也就是類似A+B, B+C, C+D這種, 一個數據表中不能出現兩個A+B。

創建方式

  • 直接創建索引
CREATE UNIQUE INDEX indexName ON table(column(length));
  • 修改表結構方式創建索引
ALTER TABLE table_name ADD UNIQUE indexName ON (column(length));
  • 創建表的時候創建索引
CREATE TABLE `table` (
    `id` int(11) NOT NULL AUTO_INCREMENT ,
    `column1` char(255) CHARACTER NOT NULL ,
    `column2` text CHARACTER NULL ,
    PRIMARY KEY (`id`),
    UNIQUE indexName (column1(length))
)
單列索引之主鍵索引

可以看做是唯一索引的變種,一個表只能有一個主鍵不允許有空值。一般是在建表的時候同時創建主鍵索引

創建方式

  • 直接創建索引
CREATE TABLE `table` (
    `id` int(11) NOT NULL AUTO_INCREMENT ,
    `column1` char(255) CHARACTER NOT NULL ,
    `column2` text CHARACTER NULL ,
    PRIMARY KEY (`id`)
)
組合索引

指多個字段上創建的索引,只有在查詢條件中使用了創建索引時的第一個字段,索引纔會被使用。使用組合索引時遵循最左前綴集合

解說說明最左前綴集合
一個例子 一張表中, 我們把 name, age, address創建索引, 那麼索引中就按照name/age/address的順序放置,
我們在使用的時候可以使用(name, age, address), 或者(name, age)又或者(name, address) 可以看到name就被看做我們的最左前綴.

如果查詢的時候使用(age, address), 或者(age, name)這樣的順序是不會根據索引進行查詢數據的.也就是稱作一種無效查詢.

創建方式

ALTER TABLE `table` ADD INDEX name_age_address ((name, age, address); 
全文索引

主要用來查找文本中的關鍵字,而不是直接與索引中的值相比較, 用在一堆文字中,通過其中的某個關鍵字等,就能找到該字段所屬的記錄行, 例如武漢加油, 通過武漢, , 等等關鍵字可以搜到對應的整條數據.
這種索引方式在很多非關係型的數據庫中都有體現, 例如ES, 或者MongoDB

特別注意在mysql中全文索引只有在MyISAM引擎纔可以使用, 並且只有char、varchar,text 列上可以創建全文索引

空間索引

空間索引是對空間數據類型的字段建立的索引,MySQL中的空間數據類型有四種,GEOMETRY、POINT、LINESTRING、POLYGON
mysql5.7及以後版本支持, 創建時候使用SPATIAL關鍵字, 並且涉及的列不能爲空.

這種索引, 筆者在目前的生產開發中, 沒有遇到過, 避免說的不完整誤導大家, 如果有需要的同學可以去參考下面一些文檔
空間索引和 ST_Geometry
MySQL5.7版本空間數據參考文檔
MySQL支持的空間數據格式
ST_Within

總結

  • 爲什麼使用索引?
    • 加快查詢效率
  • 索引的類別有?
    • 單列索引
      • 普通索引
      • 唯一索引
      • 主鍵索引
    • 組合索引
    • 全文索引
    • 空間索引

說到了索引, 就不得不提起視圖, 那視圖又是怎麼回事, 移步《視圖那些事兒----基於Mysql》

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