never too late~sql
索引(在MySQL中也叫作「鍵(key)」) 是存儲引擎用於快速找到記錄的一種數據結構。這是索引的基本功能。數據庫
索引對於良好的性能很是關鍵。尤爲是當表中的數據量愈來愈大時,索引對性能的影響躍愈發重要。在數據量較小且負載較低時,不恰當的索引對性能的影響可能還不明顯,可是當數據量逐漸增大時,性能則會急劇降低。數據結構
1、索引基礎性能
Q1:索引是如何工做的?優化
A1:要理解MySQL中索引是如何工做的,最簡單是方法就是區看一看一本書的目錄。假若想在一本書中找到某個特定命題,通常會先看書的「索引」,找到對應的頁碼。url
那麼在MySQL中,存儲引擎的用相似的方法使用索引,它先在索引中找到對應值,而後根據匹配的索引記錄找到對應的數據行。spa
Q2:MySQL支持的索引的類型?以及優缺點.net
A2:B-Tree 索引、哈希索引、空間數據索引、全文索引等其餘索引。指針
- B-Tree一般意味着全部的值都是按順序存儲的,而且每個葉子頁到跟的距離相同。葉子頁比較特殊,它的指針指向的是被索引的數據,而不是其餘的節點頁。
圖1 B-Tree (從技術上來講是B+tree)索引樹種的部分條目示例code
- 哈希索引基於哈希表實現,只有精確匹配索引全部列的查詢纔有效。對於每一行數據,存儲引擎都會對全部的索引列計算一個哈希碼。哈希索引將全部的哈希碼存儲在索引中,同時在哈希表中保存指向每一個數據行的指針。
限制之處:
(1)哈希索引只包含哈希值和行指針,而不存儲字段值。
(2)哈希索引數據不是按照索引值的順序排序的,因此沒法用於排序。
(3)不支持部分索引列匹配查找。
(4)只支持等值比較查詢
(5)哈希衝突多的話,索引維護操做的代價也會很高。
- 空間數據索引(R-Tree)
MyISAM 表支持空間索引,能夠用做地理數據存儲。這類索引無須前綴查詢。空間索引會從全部維度來索引數據。這一類型索引,接觸的不多,之後碰到再作詳細總結。
- 全文索引,這是一種特殊類型的索引,它查找的是文本中的關鍵詞。將來遇到了再總結。
2、彙集索引和非彙集索引
彙集索引和非彙集索引的根本區別是表記錄的排列順序和與索引的排列順序是否一致。
一、彙集索引
彙集索引表記錄的排列順序和索引的排列順序一致(以InnoDB彙集索引的主鍵索引來講,葉子節點中存儲的就是行數據,行數據在物理儲器中的真實地址就是按照主鍵索引樹造成的順序進行排列的),因此查詢效率快,只要找到第一個索引值記錄,其他就連續性的記錄在物理也同樣連續存放。彙集索引對應的缺點就是修改慢,由於爲了保證表中記錄的物理和索引順序一致,在記錄插入的時候,會對數據頁從新排序(由於在真實物理存儲器的存儲順序只能有一種,而插入新數據必然會致使主鍵索引樹的變化,主鍵索引樹的順序發生了改變,葉子節點中存儲的行數據也要隨之進行改變,就會發生大量的數據移動操做,因此效率會慢)。由於在物理內存中的順序只能有一種,因此彙集索引在一個表中只能有一個。
二、非彙集索引
非彙集索引制定了表中記錄的邏輯順序,可是記錄的物理和索引不必定一致(在邏輯上數據是按順序排存放的,可是物理上在真實的存儲器中是散列存放的),兩種索引都採用B+樹結構,非彙集索引的葉子層並不和實際數據頁相重疊,而採用葉子層包含一個指向表中的記錄在數據頁中的指針方式。非彙集索引層次多,不會形成數據重排。因此若是表的讀操做遠遠多於寫操做,那麼就可使用非彙集索引。
三、對比兩種索引的例子
彙集索引就相似新華字典中的拼音排序索引,都是按順序進行,例如找到字典中的「愛」,就裏面順序執行找到「癌」。而非彙集索引則相似於筆畫排序,索引順序和物理順序並非按順序存放的。總的來講,彙集索引的葉節點就是數據節點。而非聚簇索引的葉節點仍然是索引節點,只不過有一個指針指向對應的數據塊
索引建立Demo
CREATE DATABASE `IndexDemo` go USE `IndexDemo` go CREATE TABLE `ABC` ( `A` INT NOT NULL, `B` CHAR(10), `C` VARCHAR(10) ) go INSERT INTO `ABC` SELECT 1,'B','C' UNION SELECT 5,'B','C' UNION SELECT 7,'B','C' UNION SELECT 9,'B','C' go SELECT * FROM abc
這個時候插入一條數據,
INSERT INTO `abc` VALUES('6','B','C')
此時的查詢記錄以下:
添加彙集索引,再查詢數據顯示則以下,此時發現表的順序發生了變化,此時的排序按A字段的遞增排序。這就說明了使用匯集索引若是插入新數據會進行從新排序
四、彙集索引和非彙集索引的區別總結:
- 彙集索引一個表只能有一個,而非彙集索引一個表能夠存在多個
- 彙集索引存儲記錄是物理上連續存在,而非彙集索引是邏輯上的連續,物理存儲並不連續
- 彙集索引:物理存儲按照索引排序;彙集索引是一種索引組織形式,索引的鍵值邏輯順序決定了表數據行的物理存儲順序
- 非彙集索引:物理存儲不按照索引排序;非彙集索引則就是普通索引了,僅僅只是對數據列建立相應的索引,不影響整個表的物理存儲順序.
- 索引是經過B+樹的數據結構來描述的,咱們能夠這麼理解聚簇索引:索引的葉節點就是數據節點。而非聚簇索引的葉節點仍然是索引節點,只不過有一個指針指向對應的數據塊。
五、其餘問題
咱們須要搞清楚如下幾個問題:
第一:彙集索引的約束是惟一性,是否要求字段也是惟一的呢? 不要求惟一!
分析:若是認爲是的朋友,多是受系統默認設置的影響,通常咱們指定一個表的主鍵,若是這個表以前沒有彙集索引,同時創建主鍵時候沒有強制指定使用非彙集索引,SQL會默認在此字段上建立一個彙集索引,而主鍵都是惟一的,因此理所固然的認爲建立彙集索引的字段也須要惟一。
結論:彙集索引能夠建立在任何一列你想建立的字段上,這是從理論上講,實際狀況並不能隨便指定,不然在性能上會是惡夢。
第二:爲何彙集索引能夠建立在任何一列上,若是此表沒有主鍵約束,即有可能存在重複行數據呢?
粗一看,這還真是和彙集索引的約束相背,但實際狀況真能夠建立彙集索引。
分析其緣由是:若是未使用 UNIQUE 屬性建立彙集索引,數據庫引擎將向表自動添加一個四字節 uniqueifier 列。必要時,數據庫引擎 將向行自動添加一個 uniqueifier 值,使每一個鍵惟一。此列和列值供內部使用,用戶不能查看或訪問。
第三:是否是彙集索引就必定要比非彙集索引性能優呢?
若是想查詢學分在60-90之間的學生的學分以及姓名,在學分上建立彙集索引是不是最優的呢?
答:否。既然只輸出兩列,咱們能夠在學分以及學生姓名上建立聯合非彙集索引,此時的索引就造成了覆蓋索引,即索引所存儲的內容就是最終輸出的數據,這種索引在比以學分爲彙集索引作查詢性能更好。就是說咱們用學分去創建非彙集索引,那麼搜索出來以後結點中的索引數據區只存有學分的數據,還須要根據葉子節點中數據區中的地址去查詢,可是若是直接將要查詢的學分字段和姓名字段建立一個聯合索引(也是非彙集索引),這樣在索引樹中查找到數據以後直接就能在節點的索引數據區取得兩個索引值,就不用再經過葉子節點中數據區裏面的地址再去查詢一次了。
第四:在MySQL數據庫中經過什麼描述彙集索引與非彙集索引的?
索引是經過B+樹的形式進行描述的,咱們能夠這樣區分彙集與非彙集索引的區別:InnoDB中的彙集索引的葉節點就是最終的數據節點,InnoDB中的非彙集索引葉子節點指向的是相應的主鍵值。而MyISAM中非彙集索引的主鍵索引樹和二級索引樹的葉節仍然是索引節點,但它有一個指向最終數據的指針。
第五:在主鍵是建立彙集索引的表在數據插入上爲何比主鍵上建立非彙集索引錶速度要慢?
彙集索引的缺點是對錶進行修改速度較慢,這是爲了保持表中的記錄的物理順序與索引的順序一致,而把記錄插入到數據頁的相應位置,必須在數據頁中進行數據重排,下降了執行速度。插入數據時速度要慢(時間花費在「物理存儲的排序」上,也就是首先要找到位置而後插入)。非彙集索引指定了表中記錄的邏輯順序,但記錄的物理順序和索引的順序不一致,彙集索引和非彙集索引都採用了B+樹的結構,但非彙集索引的葉子層並不與實際的數據頁相重疊,而採用葉子層包含一個指向表中的記錄在數據頁中的指針的方式。非彙集索引比彙集索引層次多,添加記錄不會引發數據順序的重組。這就是爲何主鍵上建立非彙集索引比主鍵上建立彙集索引在插入數據時要快的真正緣由。
參考文章:
【MySQL】MySQL的存儲引擎和索引詳解(彙集索引和非彙集索引)
《高性能MySQL》