首頁  >  文章  >  資料庫  >  mysql聚集索引的有哪些缺點

mysql聚集索引的有哪些缺點

一个新手
一个新手原創
2017-09-19 09:35:561559瀏覽

 聚簇索引並不是一種單獨的索引類型,而是一種資料儲存方式(不是資料結構,而是儲存結構),具體細節依賴其實作方式,但innodb的叢集索引實際上是在同一個結構中保存了btree索引和資料行。

  當表有索引時,它的資料行實際上存放在索引的葉子頁中,屬於聚集表示資料行和相鄰的鍵值緊密地儲存在一起,因為無法同時把資料行存放在兩個不同的地方,所以一個表格只能有一個聚集索引。因為是儲存引擎負責實作索引,因此不是所有的儲存引擎都支援叢集索引。以下主要介紹innodb,但下面討論的原理對於任何支援叢集索引的引擎都適用:

   葉子頁包含了行的全部數據,但是節點頁只包含了索引列(或者可以說不葉子節點的節點頁包含的是索引值的索引,因為這些節點頁包含的值是從索引列中提取出來的)。

  innodb將透過主鍵聚集數據,如果沒有定義主鍵,Innodb會選擇第一個非空的唯一索引代替,如果沒有非空唯一索引,Innodb會隱式定義一個6位元組的rowid主鍵來作為聚集索引。 innodb只聚集在同一個頁面中的記錄,包含相鄰鍵值的頁面可能會相距甚遠。

  要注意:聚簇主鍵可能對效能有幫助,但也可能導致嚴重的效能問題,尤其是將表的儲存引擎從innodb轉換成其他引擎的時候。

 聚集的資料有一些重要的優點:

  A:可以把相關資料保存在一起,如:實現電子郵箱時,可以根據使用者ID來聚集數據,這樣只需要從磁碟讀取少量的資料頁就能取得某個使用者全部郵件,如果沒有使用聚集索引,則每封郵件都可能導致一次磁碟IO

  B:資料存取更快,聚集索引將索引和資料保存在同一個btree中,因此從聚集索引中獲取資料通常比在非聚集索引中查找要快

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

 聚集索引的缺點:

  A:叢集資料最大限度地提高了IO密集型應用程式的效能,但如果資料全部放在記憶體中,則存取的順序就沒有那麼重要了,聚集索引也沒有什麼優勢了

  B:插入速度嚴重依賴於插入順序,按照主鍵的順序插入是加載數據到innodb表中速度最快的方式,但如果不是按照主鍵順序加載數據,那麼在加載完成後最好使用optimize table命令重新組織一下表

  C:更新聚集索引列的代價很高,因為會強制innodb將每個被更新的行移動到新的位置

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

  E:聚集索引可能導致全表掃描變慢,尤其是行比較稀疏,或是因為頁分裂導致資料儲存不連續的時候

  F:二級索引可能比想像的更大,因為在二級索引的葉子節點包含了引用行的主鍵列。

  G:二級索引存取需要兩次索引查找,而不是一次

   因為二級索引葉子節點中保存的不是指向行的物理位置的指針,而是行的主鍵值。這意味著透過二級索引查找行,儲存引擎需要找到二級索引的葉子節點獲得對應的主鍵值,然後根據這個主鍵值去聚集索引中查找對應的行,這裡做了重複的工作,兩次btree查找而不是一次,對於innodb,自適應哈希索引能減少這樣的重複工作。

 innodb和myisam實體儲存的資料分佈比較:

  myisam:

  是按照資料插入的順序儲存在磁碟上的,myisam中的主鍵索引和二級索引在結構上並沒有什麼不同,主鍵索引就是一個名為primary的唯一非空索引。

  innodb:

  因為innodb支援聚集索引,所以使用非常不同的方式儲存相同的數據,innodb聚集索引包含了整個表的數據,而不是只有索引,因為在Innodb中,聚集索引就是表,所以不像myisam需要獨立的行儲存。聚集索引的每一個葉子節點都包含了主鍵值,事務ID,用於事務和MVCC的回滾指標以及所有剩餘列的值,如果主鍵是一個列前綴索引,innodb也會包含完整的主鍵列和剩下的列的值。

  還有一點和myisam不同的是,innodb的二級索引和聚集索引很不同,innodb二級索引的葉子節點中儲存的不是行指針,而是主鍵值,並以此作為指向行的指針,這樣的策略減少了當出現行移動或數據頁的分裂時二級索引的維護工作,使用主鍵值當做指針會讓二級索引佔用更多的空間,換來的好處是, innodb在移動行時無須更新二級索引中的這個指標。

   在innodb表中按主鍵順序插入行,如果正在使用Innodb表並且沒有什麼資料需要聚集,那麼可以定義一個代理鍵作為主鍵,這種主鍵的資料應該和應用無關,最簡單的方法是使用auto_increment自增列,這樣可以確保資料行是依序插入的,對於根據主鍵做關聯操作的效能也會更好。

  不要使用UUID作為聚集索引,否則效能會很糟糕,因為它使得聚集索引的插入變得完全隨機,使得資料沒有任何聚集特性。因為UUID作為主鍵插入行不僅花費的時間更長,而且索引也更大,這一方面是因為主鍵字段變長了,另外一方面毫無疑問是由於頁分裂導致時間變長和碎片導致的索引變大。因為主鍵的值是順序的,所以Innodb把每一筆記錄都存放在上一筆記錄的後面,當達到頁的最大填充因子時(innodb預設的最大填充因子是頁大小的十六分之十五,留出部分空間用於以後修改),下一筆記錄就會寫入新的頁中,一旦資料按照這種順序的方式加載,主鍵頁就會近似被順序的記錄填滿,這也正是所期望的結果(然而,二級索引頁可能是不一樣的)。

  在UUID主鍵下,因為新插入行的主鍵值不一定比前面的大,所以innodb無法簡單地總是把新行插入到索引的最後,而是需要為新的行尋找合適的位置,通常是已有資料的中間位置,並且分配新的空間,這會增加很多額外的工作,並導致資料分佈不夠優化,以下是使用UUID作為主鍵的一些缺點:

A:寫入的目標頁可能已經刷到磁碟上並從快取中移除,或者是還沒有被載入到快取中,innodb在插入前必須先找到並從磁碟讀取目標頁到記憶體中,這將導致大量的隨機IO

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

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

 把這些隨機值載入到聚集索引之後,也許需要做一次optimize table來重建表格並優化頁的填滿。使用innodb時應該盡可能地按照主鍵順序插入數據,並且盡可能地使用簡單增加的聚簇鍵的值來插入新行。

 註:順序的主鍵什麼時候會造成更糟的結果?

  對於高並發工作負載,在Innodb中按主鍵順序插入可能會造成明顯的爭用,主鍵的上界會稱為熱點,因為所有的插入都發生在這裡,所以並發插入可能導致間隙鎖爭用,另一個熱點可能是auto_increment鎖機制,如果遇到這個問題,則可能需要重新設計表或應用,或者更改innodb_autoinc_lock_mode配置。

以上是mysql聚集索引的有哪些缺點的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn