一、分區表
1. 什么是分區表?
對用戶來說,分區表是一個獨立的邏輯表,但是底層由多個物理子表組成(所以索引也是按照分區的子表定義的,而沒有全局索引)。實現分區的代碼實際上是對一組底層表的句柄對象的封裝。對分區表的請求,都會通過句柄對象轉化成對存儲引擎的接口調用。
MySQL在創建表時,使用partition by子句定義每個分區存放的數據。在執行查詢的時候,優化器會根據分區定義過濾那些沒有我們需要的數據的分區。
分區的一個主要目的是將數據按照一個較粗的粒度分布在不同的表中,這樣可以將相關的數據存放在一起,如果想一次批量刪除整個分區的數據也會變得很方便。
2. 分區表發揮大作用的場景:
(1)表非常大以至於無法全部都放在內存中,或者只在表的最后部分有熱點數據,其他均是歷史數據。
(2)分區表的數據更容易維護。
(3)分區表的數據可以分布在不同的物理設備上。
(4)可以使用分區表來避免某些特殊的瓶頸,例如InnoDB單個索引的互斥訪問。
(5)如果需要,還可以備份和恢復獨立的分區,這在非常大的數據集的場景下效果非常好。
3. 分區表的限制:
(1)一個表最多只能有1024個分區。
(2)在MySQL5.1中,分區表達式必須是整數,或者是返回整數的表達式。在MySQL5.5中,某些場景中可以直接使用列來進行分區。
(3)如果分區字段中有主鍵或者唯一索引的列,那么所有主鍵列和唯一索引列都必須包含進來。
(4)分區表中無法使用外鍵約束。
(5)所有分區都必須使用相同的存儲引擎。
(6)分區函數中可以使用的函數和表達式也有一些限制。
(7)某些存儲引擎不支持分區。
(8)對於MyISAM表,使用分區表時需要打開更多的文件描述符。
4. 分區表的原理:
存儲引擎管理分區的各個底層表和管理普通表一樣(所有的底層表都必須使用相同的存儲引擎),分區表的索引只是在各個底層表上各自加上一個完全相同的索引。
在分區表上的查詢操作都需要分區層首先打開並鎖住所有的底層表,然后確定需要操作的分區,最后再采取相應操作。
5. 分區表的類型:
MySQL支持范圍、鍵值、哈希、列表分區。其中有些還支持子分區,通過子分區可以將數據切成多個小片,大大降低互斥量的競爭問題。
分區表達式可以是列,也可以是列的表達式,可以使用各種函數,但是返回的值要是一個確定的整數;分區表達式不能是一個常數。
6. 如何使用分區表:
分區不需要精確定位每條數據的位置,所以無須額外的數據結構記錄每個分區有哪些數據,代價非常低,只需要一個簡單的表達式就可以表達每個分區存放的是什么數據。
保證大量數據可擴展性的兩個策略:
(1)全量掃描數據,不要任何索引。
(2)索引數據,並分離熱點。
7. 什么情況下會出現問題:
(1)NULL值會使分區過濾無效
分區表達式的值可以是NULL,對應的記錄會存放到第一個分區中。例如,如果按partition by range year(order_date)分區,那么所有order_date為NULL或是一個非法值的時候,記錄都會被放到第一個分區。查詢某個范圍的數據記錄時MySQL會檢查包含第一個分區在內的兩個分區,如果第一個分區非常大的話代價會很大。
解決方法:
<1> 創建一個沒用的分區。例如上面的例子可以使用partition p_nulls values less than (0)來創建第一個分區。
<2> 在MySQL5.5之后可以直接使用列本身而不是基於列的函數進行分區:partition by range columns (order_date)。
(2)分區列和索引列不匹配
如果定義的索引列和分區列不匹配,會導致查詢無法進行分區過濾。
(3)選擇分區的成本可能很高
范圍分區找到目標分區服務器需要掃描所有的分區定義列表,隨着分區數增長,成本會越來越高。在應用開發中應該限制分區數量,一般100左右已經夠用了。其他分區類型則沒有這個問題。
(4)打開並鎖住所有底層表的成本可能很高
當查詢訪問分區表的時候,MySQL需要打開並鎖住所有的底層表,這個操作在分區過濾之前發生,所以無法通過分區過濾降低此開銷,並且該開銷和分區類型無關,會影響所有查詢。這對一些本身操作非常快的查詢會帶來明顯的額外開銷。
解決方法:
使用批量操作的方式來降低單個操作的此類開銷,例如使用批量插入、一次刪除多行數據,等等。
(5)維護分區的成本可能很高
重組分區或類似alter語句的操作,需要復制數據。
8. 查詢優化:
(1)在where條件中帶入分區列,即使看似多余,這樣優化器通過分區過濾可以讓查詢掃描更少的數據。可以使用explain partitions觀察優化器是否執行了分區過濾。
(2)MySQL只能在使用分區列本身進行比較時才能過濾分區,而不能根據基於分區列的表達式的值去過濾分區,即使這個表達式就是分區表達式也不行。
(3)若分區表是關聯操作的第二張表,且關聯條件是分區鍵,MySQL就只會在對應的分區里匹配行。但explain無法顯示這種情況下的分區過濾,因為這是運行時的分區過濾,而不是查詢優化階段的。
二、合並表
1. 什么是合並表?
合並表是一種早期的、簡單的分區實現,和分區表相比有一些不同的限制,並且缺乏優化。分區表嚴格來說是一個邏輯上的概念,用戶無法訪問底層的各個分區,但是合並表允許用戶單獨訪問各個字表。分區表和優化器的結合更緊密,這也是未來發展的趨勢,而合並表是一種即將被淘汰的技術。
合並表其實就是使用一個merge存儲引擎邏輯表來封裝多個myisam存儲引擎物理子表,邏輯表和子表的結構完全相同(包括字段、索引等)。刪除一個合並表,它的子表不會受任何影響,而如果刪除其中一個子表則可能會有不同的后果,這要視操作系統而定。
2. 合並表的一些限制和行為:
(1)在使用create語句創建一個合並表的時候,並不會檢查各個子表的兼容性。如果子表的定義稍有不同,那么MySQL就可能創建出一個無法使用的合並表。
(2)在合並表上無法使用replace語法,無法使用自增字段。
(3)如果一個查詢訪問合並表,那么它需要訪問所有子表,這有時候會導致很差的性能,應該對子表的個數進行限制。
3. 分區所不能提供的特性:
(1)一個MyISAM表可以是多個合並表的子表。
(2)可以通過直接復制.frm、.MYI、.MYD文件來實現在不同的服務器之間復制各個子表。
(3)在合並表中可以很容易地添加新的子表,直接修改合並表的定義就可以了。
(4)可以創建一個合並表,讓它只包含需要的數據。
(5)如果相對某個子表做備份、恢復、修改、修復或者別的操作時,可以先將其從合並表中刪除,操作結束后再將其加回去。
(6)可以使用myisampack工具來壓縮所有的子表。