1. 程式人生 > 其它 >MySQL之分割槽表

MySQL之分割槽表

介紹

對於使用者來說,分割槽表是一個獨立的邏輯表,但是底層由多個物理子表組成。實現分割槽的程式碼實際上是對一組底層表的控制代碼物件(Handler Object)的封裝,對於分割槽表的請求,都會通過控制代碼物件轉化成對儲存引擎的介面呼叫。

MySQL實現分割槽表的方式——對底層表的封裝——意味著索引也是按照分割槽的子表定義的,而沒有全域性索引。

MySQL在建立表時使用PARTITION BY子句定義每個分割槽存放的資料。在執行查詢的時候,優化器根據分割槽定義過濾那些沒有我們需要資料的分割槽,這樣查詢就無須掃描所有分割槽——只需要查詢包含需要資料的分割槽就可以了。

分割槽的一個主要目的就是將資料按照一個較粗的粒度分在不同的表中。這樣做可以將相關的資料存放在一起,另外,如果想一次批量刪除整個分割槽的資料也會變得很方便。

在下面的場景中,分割槽可以起大很大的作用:

  • 表非常大,以至於無法全部都放在記憶體中,或者只在表的最後部分有熱點資料 ,其他均是歷史資料。
  • 分割槽表的資料更容易維護。例如,可以對一個獨立分割槽進行優化、檢查、修復、批量刪除等操作。
  • 分割槽表的資料可以分佈在不同的物理裝置上,從而高效地利用多個硬體裝置。
  • 可以使用分割槽表來避免某些特殊的瓶頸。

分割槽表本身也有一些限制,其中比較重要的幾點:

  • 一個表最多隻能有1024個分割槽。
  • 如果分割槽欄位中有主鍵或者唯一索引的列,那麼所有主鍵列和唯一索引列都必須包含進來。
  • 分割槽表中無法使用外來鍵約束。

分割槽表的原理

分割槽表上的操作按照下面的操作邏輯進行:

  • SELECT查詢:當查詢一個分割槽表時,分割槽層先開啟並鎖住所有的底層表,優化器先判斷是否可以過濾部分分割槽,然後再呼叫對應的儲存引擎介面訪問各個分割槽的資料。
  • INSERT操作:當寫入一條記錄時,分割槽層先開啟並鎖住所有的底層表,然後確定哪個分割槽接收這條記錄,再將記錄寫入對應底層表。
  • DELETE操作:當刪除一條記錄時,分割槽層先開啟並鎖住所有的底層表,然後確定資料對應的分割槽,最後對相應底層表進行刪除操作。
  • UPDATE操作:當更新一條記錄時,分割槽層先開啟並鎖住所有的底層表,MySQL先確定需要更新的記錄在哪個分割槽,然後取出資料並更新,再判斷更新後的資料應該放在哪個分割槽,最後對底層表進行寫入操作,並對原資料所在的底層表進行刪除操作。

雖然每個操作都會“先開啟並鎖住所有的底層表”,但這並不是說分割槽表在處理過程中是鎖住全表的。如果儲存引擎能夠自己實現行級鎖,例如InnoDB,則會在分割槽層釋放對應表鎖。這個加鎖和解鎖過程與普通InnoDB上的查詢類似。

分割槽表的型別

MySQL支援多種分割槽表。最多的是根據範圍進行分割槽,每個分割槽儲存落在某個範圍的記錄,分表表達式可以是列,也可以是包含列的表示式。還支援鍵值、雜湊和列表分割槽,不過很少用到。

如何使用分割槽表

為了保證大資料量的可擴充套件性,一般有以下兩個策略:

  • 全量掃描資料,不要任何索引。

    可以使用簡單的分割槽方式存放表,不要任何索引,根據分割槽的規則大致定位需要的資料位置。只要能夠使用WHERE條件,將需要的資料限制在少數分割槽中,則效率是很高的。使用該策略假設不用將資料完全放入記憶體中,同時還假設需要的資料全部在磁碟上,因為記憶體相對較小,資料很快會被擠出記憶體,所以快取起不來任何作用。適用於以正常的方式訪問大量資料的時候。警告:必須將查詢需要掃描的分割槽個數限制在一個很小的數量。

  • 索引資料,並分離熱點。

    如果資料又明顯的“熱點”,而且除了這部分資料,其他資料很少被訪問到,那麼可以將這部分熱點資料單獨放在一個分割槽中,讓這個分割槽能夠有機會都快取中記憶體中。這樣查詢就可以只訪問一個很小的分割槽表,能夠使用索引,也能夠有效的使用快取。

什麼情況下會出問題

上面介紹的分割槽策略都基於兩個非常重要的假設:查詢都能夠過濾(prunning)掉很大額外的分割槽、分割槽本身並不會帶來很多額外的代價。而事實證明,這兩個假設在某些場景下會有問題,下面介紹一些可能會遇到的問題。

  • NULL值會使分割槽過濾無效

    關於分割槽表一個容易讓人誤解的地方就是分割槽的表示式的值可以是NULL:第一個分割槽是一個特殊分割槽。如果第一個分割槽非常大,特別是當使用“全量掃描資料,不要任何索引”的策略時,代價會非常大,而且掃描兩個分割槽來查詢列也不是我們使用分割槽表的初衷。為了避免這種情況,可以建立一個“無用”的第一分割槽。

  • 分割槽列和索引列不匹配

    如果定義的分割槽列和索引列不匹配,會導致查詢無法進行分割槽過濾。

  • 選擇分割槽的成本可能很高

    如範圍分割槽。

  • 開啟或鎖住所有底層表的成本可能很高

    當查詢訪問分割槽表的時候,MySQL需要開啟並鎖住所有的底層表,這是分割槽表的另一個開銷。這個操作在分割槽過濾之前發生,所以無法通過分割槽過濾降低此開銷,並且該開銷也和分割槽型別無關,會影響所有的查詢。

  • 維護分割槽的成本可能很高

    某些分割槽維護操作速度可能很慢,例如重組分割槽或者類似ALTER語句的操作:這類操作需要複製資料。重組分割槽的原理與ALTER類似,先建立一個臨時的分割槽,然後將資料複製到其中,最後再刪除原分割槽。

其他一些限制:

  • 所有分割槽都必須使用相同的儲存引擎。
  • 分割槽函式中可以使用的函式和表示式也有一些限制。
  • 某些儲存引擎不支援分割槽。