聚簇索引


https://wely.iteye.com/blog/2331907

聚簇索引並不是一種單獨的索引類型,而是一種數據存儲方式。具體的細節依賴於其實現方式,但innoddb 的聚簇索引實際上在同一個結構中保存了B-Tree索引和數據行。

  當表有聚簇索引時,它的數據實際上存放在索引的葉子頁(leaf page)中。術語‘聚簇’表示數據行和相鄰的鍵值聚簇的存儲在一起因為無法同時把數據行存放在兩個不同的地方,所以在一個表中只能有一個聚簇索引 (不過,覆蓋索引可以模擬多個聚簇索引的情況)。

  因為存儲引擎負責實現索引,因此不是所有的存儲引擎都支持聚簇索引

  一些數據庫服務器允許選擇哪個索引作為聚簇索引,但直到本書協寫作之前,還沒有任何一個MySQL內嵌的存儲引擎支持這一點InnoDb將通過主鍵聚集數據

  如果沒有定義主鍵,InnoDB 會選擇一個唯一的非空索引代替。如果沒有這樣的索引,InnoDB 會隱式定義一個主鍵來作為聚簇索引。InnoDB值聚集在同一個頁面中的記錄。。包含相鄰鍵值的頁面可能會相距很遠

  聚簇索引可能對性能有幫助,但也可能導致嚴重的性能問題。所以需要咨詢的考慮聚簇索引,尤其是將表的存儲引擎從InnoDB 該成其他的引擎的時候(返回來也一樣)。

 

  聚簇索引的一些重要優點:

  可以吧相關的數據保存在一起例如,實現電子郵箱時,可以根據用戶id來聚集數據這樣只需要從磁盤讀取少數的數據頁就能獲取某個用戶的全部郵件。如果沒有使用聚簇索引,則每封郵件都肯能導致一次io。

  數據訪問更快。聚簇索引將索引和數據保存在同一個B-Tree中,因此從聚簇索引中獲取數據通常比非聚簇索引中快。

  使用覆蓋索引掃描的查詢可以直接使用頁節點中的主鍵值。

 

  聚簇索引的缺點:

  聚簇索引最大限度的提高了io密集型應用的性能,但如果數據全部存放在內存中,則訪問的順序就沒那么重要了,聚簇索引也就沒有什么優勢了。

  插入速度嚴重依賴插入順序。按照主鍵的順序插入是加載數據到innodb表中速度最快的方式。但如果不是按照主鍵順序加載數據,那么加載完成后最好使用OPTIMIZE TABLE 命令來重新組織一下表。

  更新聚簇索引的代價很高,因為會強制InooDB將每個更新的數據移動到新的位置

  基於聚簇索引的表在插入行,或者主鍵被更新導致需要移動行的時候,可能面臨’頁分裂(page split)‘的問題。當行的主鍵值要求必須將這一行插入到某個已滿的頁中時。存儲引擎,存儲引擎會將該頁分裂成兩個頁面來容納該行,這就是一次頁分裂操作。頁分裂會導致表占用更多的存儲空間。

  聚簇索引可能導致全表掃描變慢,尤其是行比較稀疏,或者由於頁分裂導致數據存儲不連續的時候。

  二級索引(非聚簇索引)可能比想象的要更大,因為在二級索引的子節點包含了最優一個幾點可能讓人有些疑惑,為什么二級索引需要兩次索引查找?答案在於二級索引中保存的“行指針”的實質。要記住,二級索引葉子節點保存的不是只想物理位置的指針,而是行的主鍵值

  這意味着通過二級索引進行查找行,存儲引擎需要找到二級索引的子節點獲得對應的主鍵值,然后根據這個值去聚簇索引總超找到對應的行。這里做了重復的工作:兩次B-Tree查找,而不是一次。對於InnoDB,自適應哈希索引能夠減少這樣重復工作。

 

InnoDB 和 MyISAM的數據分布對比

  聚簇索引和非聚簇索引的數據分布有區別,以及對應的主鍵索引和二級索引的數據分布也有區別,通常會讓人感到困惑和意外。來看看InnoDB和MyISAM是如何存儲下面的這個表的:

  CREATE TABLE layout_test(

    col1 int not null,

    col2 int not null,

      primary key (col1),

    key(col2)

  );

  假設該表的主鍵取值為1-1w,按照隨機順序插入,並使用OPTIMIZE TABLE命令做了優化。換句話說,數據在磁盤的存儲方式已經最優,但進行的順序是隨機的。列col2的值是從1-100之間隨機賦值,所以有很多重復的值。

  •   MyISAM 的數據分布.。 MyISAM的數據分布非常簡單,所以先介紹它。MyIsam按照數據插入的順序存儲在磁盤上

  實際上,MyISAM 中主鍵索引和其他索引在結構上沒有什么不同。主鍵索引就是一個名為PRIMARY的唯一非空索引。

  •   InnoDB 的數據分布。因為InnoDB支持聚簇索引,索引使用非常不同的方式存儲同樣的數據。在InnoDB中,聚簇索引“就是”表,所以不像myISAM那樣需要獨立的行存儲。聚簇索引的每一個葉子節點都包含了主鍵值、事務id,用於事務和MVCC的回滾指針。這樣的策略減少了當前出現行移動或者數據頁分裂是二級索引的維護工作。使用主鍵值當作指針會讓二級索引占用更多的存儲空間,存儲,換來的好處是,InnoDB在移動行時,無需更新二級索引中的這個指針。InnoDB 的非葉子節點包含了索引列和一個紙箱下級節點的指針(下級節點可以是葉子節點,也可以是非葉子節點)。這對聚簇索引和二級索引都使用。

 

在InnoDB表中按照主鍵順序插入行

  如果正在使用InnoDB 表並且沒有什么數據需要聚集,那么可以定義一個代理鍵(surrogate key)作為主鍵,這種主鍵的數據應該和應用無關,組件的的方法是使用AUTO_INCREMENT自增列。這樣可以保證數據行是按照順序寫入,對於根據主鍵做關聯的操作性能也會更好。

  最好避免隨機的(不連續,且值的分布范圍非常大的)聚簇索引,特別是對於io密集型的應用。

   例如,從性能的角度考慮,使用UUID來作為聚簇索引則會很糟糕:它使得聚簇索引的插入變得完全隨機,這是最壞的情況,使得數據沒有任何聚集特性

  因為主鍵的值是順序的,索引InnoDB 把每一條記錄都存儲在上一條記錄的后面。當達到頁的最大填充因子時(InnoDB 默認的最大填充因子是頁大小的15/16 ,留出部分空間用於以后修改),下一條記錄就會寫入到新的頁中。一旦數據按照這種順序的方式加載,主鍵頁就會近似於被順序的記錄填滿,這也正是所期望的結果(然而二級索引頁可能不一樣)。

  使用UUID聚簇索引的表插入數據,因為新的行的主鍵值不一定比之前插入的大,所以InnoDB 無法簡單的總是把新行插入到索引的最后,而是需要為新的行尋找到合適的位置--通常是已有數據的中間位置--並且分配空間。這會增加很多的額外操作。並導致數據分布不夠優化。下面是總結的一些缺點:

  寫入的目標頁可能已經數到磁盤上並從緩存中移除,或者是還沒有被加載到緩存中,InnoDB在插入之前不得不先找到並從磁盤讀取目標頁到內存中。這將導致大量的磁盤io。

  因為寫入是亂序的,InnoDB 不得不頻繁的做分頁操作,以便為新的行分配空間。頁分裂會導致移動大量數據,一次插入最少需要修改三個頁面,而不是一個頁。

  由於頻繁的頁分裂,頁會變得稀疏,並且被不規則的填充,所以最終數據會有碎片。

  總結:使用InnoDB 時應該盡可能地按照主鍵順序插入數據,並且盡可能地使用單調增加的聚簇鍵的值來插入新行。

===================================================

https://blog.csdn.net/alexdamiao/article/details/51934917

https://www.jianshu.com/p/6636e4671f83

 

索引分為聚簇索引和非聚簇索引
以一本英文課本為例,要找第8課,直接翻書,若先翻到第5課,則往后翻,再翻到第10課,則又往前翻。這本書本身就是一個索引,即“聚簇索引”。
如果要找"fire”這個單詞,會翻到書后面的附錄,這個附錄是按字母排序的,找到F字母那一塊,再找到"fire”,對應的會是它在第幾課。這個附錄,為“非聚簇索引”。
由此可見,聚簇索引,索引的順序就是數據存放的順序,所以,很容易理解,一張數據表只能有一個聚簇索引。
聚簇索引要比非聚簇索引查詢效率高很多,特別是范圍查詢的時候。所以,至於聚簇索引到底應該為主鍵,還是其他字段,這個可以再討論。

1、MYSQL的索引
mysql中,不同的存儲引擎對索引的實現方式不同,大致說下MyISAM和InnoDB兩種存儲引擎。
MyISAM的B+Tree的葉子節點上的data,並不是數據本身,而是數據存放的地址。主索引和輔助索引沒啥區別,只是主索引中的key一定得是唯一的。這里的索引都是非聚簇索引
MyISAM還采用壓縮機制存儲索引,比如,第一個索引為“her”,第二個索引為“here”,那么第二個索引會被存儲為“3,e”,這樣的缺點是同一個節點中的索引只能采用順序查找

 
 

InnoDB 的數據文件本身就是索引文件,B+Tree的 葉子節點上的data就是數據本身,key為主鍵,這是 聚簇索引非聚簇索引,葉子節點上的data是主鍵 (所以聚簇索引的key,不能過長)。
為什么存放的主鍵,而不是記錄所在地址呢,理由相當簡單,因為記錄所在地址並不能保證一定不會變,但主鍵可以保證。
至於為什么主鍵通常建議使用自增id呢?

2、聚簇索引
聚 簇索引的數據的物理存放順序與索引順序是一致的,即:只要索引是相鄰的,那么對應的數據一定也是相鄰地存放在磁盤上的
如果主鍵不是自增id,那么可以想 象,它會干些什么,不斷地調整數據的物理地址、分頁,當然也有其他一些措施來減少這些操作,但卻無法徹底避免。
但,如果是自增的,那就簡單了,它只需要一 頁一頁地寫,索引結構相對緊湊,磁盤碎片少,效率也高。

聚簇索引不但在檢索上可以大大滴提高效率,在數據讀取上也一樣。比如:需要查詢f~t的所有單詞。
一個使用MyISAM的主索引,一個使用InnoDB的聚簇索引。兩種索引的B+Tree檢索時間一樣,但讀取時卻有了差異。
因為 MyISAM的主索引並非聚簇索引,那么他的數據的物理地址必然是凌亂的,拿到這些物理地址,按照合適的算法進行I/O讀取,於是開始不停的尋道不停的旋轉。 聚簇索引則只需一次I/O
不過, 如果涉及到大數據量的排序、全表掃描、count之類的操作的話,還是MyISAM占優勢些,因為索引所占空間小,這些操作是需要在內存中完成的

鑒於聚簇索引的范圍查詢效率,很多人認為使用主鍵作為聚簇索引太多浪費,畢竟幾乎不會使用主鍵進行范圍查詢。但若再考慮到聚簇索引的存儲,就不好定論了。


作者:Ddaidai
鏈接:https://www.jianshu.com/p/6636e4671f83
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權並注明出處。

 

 

=========================== 

聚簇索引是對磁盤上實際數據重新組織以按指定的一個或多個列的值排序的算法。特點是存儲數據的順序和索引順序一致
一般情況下主鍵會默認創建聚簇索引,且一張表只允許存在一個聚簇索引。

在《數據庫原理》一書中是這么解釋聚簇索引和非聚簇索引的區別的:
聚簇索引的葉子節點就是數據節點,而非聚簇索引的葉子節點仍然是索引節點,只不過有指向對應數據塊的指針。

因此,MYSQL中不同的數據存儲引擎對聚簇索引的支持不同就很好解釋了。
下面,我們可以看一下MYSQL中MYISAM和INNODB兩種引擎的索引結構。

如原始數據為:

 

MyISAM引擎的數據存儲方式如圖:

 


MYISAM是按列值與行號來組織索引的。它的葉子節點中保存的實際上是指向存放數據的物理塊的指針。
從MYISAM存儲的物理文件我們能看出,MYISAM引擎的索引文件(.MYI)和數據文件(.MYD)是相互獨立的。

 

而InnoDB按聚簇索引的形式存儲數據,所以它的數據布局有着很大的不同。它存儲數據的結構大致如下:

 

注:聚簇索引中的每個葉子節點包含主鍵值、事務ID、回滾指針(rollback pointer用於事務和MVCC)和余下的列(如col2)

INNODB的二級索引與主鍵索引有很大的不同。InnoDB的二級索引的葉子包含主鍵值,而不是行指針(row pointers),這減小了移動數據或者數據頁面分裂時維護二級索引的開銷,因為InnoDB不需要更新索引的行指針。其結構大致如下:

 


INNODB和MYISAM的主鍵索引與二級索引的對比:

 


InnoDB的的二級索引的葉子節點存放的是KEY字段加主鍵值

因此,通過二級索引查詢首先查到是主鍵值,然后InnoDB再根據查到的主鍵值通過主鍵索引找到相應的數據塊。而MyISAM的二級索引葉子節點存放的還是列值與行號的組合,葉子節點中保存的是數據的物理地址。

所以可以看出MYISAM的主鍵索引和二級索引沒有任何區別,主鍵索引僅僅只是一個叫做PRIMARY的唯一、非空的索引,且MYISAM引擎中可以不設主鍵。

參考資料:
高性能MYSQL
---------------------
作者:alexdamiao
來源:CSDN
原文:https://blog.csdn.net/alexdamiao/article/details/51934917
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!


免責聲明!

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



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