Mysql第八天 分區與分表

分區表

主要提供如下的特性,或者適合如此場景:

  • 數據量非常大, 或者只有表中最後的部分有熱點數據,其他均爲歷史數據
  • 分區表數據更容易維護,可以對獨立的分區刪除等操作
  • 分區表的數據可以分佈在不同的物理設備上,從而高效地利用多個硬件設備。
  • 可以避免一些特殊瓶頸,比如InnoDB的單個索引的互斥訪問
  • 可以備份和恢復獨立的分區

創建分區表

通常有這麼幾種分法,因爲主鍵或者是唯一約束鍵必須有一部分包含在分區鍵中,所以一般要不無主鍵,要不就按照自增主鍵的id進行範圍分區,要不就把分區字段和主鍵一起作爲聯合主鍵。
還有一些其他的限制,比如分區鍵的運算結果必須爲整數

Range分區

CREATE TABLE biz_order(
id bigint(20) NOT NULL AUTO_INCREMENT,
created DATETIME NOT NULL COMMENT '創建時間',
PRIMARY KEY (id, created)) ENGINE=InnoDB PARTITION BY RANGE(YEAR(created))(
  PARTITION p_2010 VALUES LESS THAN (2015),
  PARTITION p_latest VALUES LESS THAN MAXVALUE);

這種分區,最新的那個區顯然會有最多的熱點數據。 可以再使用Hash子分區來減少競爭
- 除了使用YEAR, TO_DAY等日期函數外,還可以使用其數學函數,比如取模,按7取模是周幾等

List分區

是用IN來做列值匹配的集合。 比如可以按照地區來分爲東西南北幾個區:

PARTITION BY LIST(store_id)
    PARTITION pNorth VALUES IN (3,5,6,9,17),
    PARTITION pEast VALUES IN (1,2,10,11,19,20),
    PARTITION pWest VALUES IN (4,12,13,14,18),
    PARTITION pCentral VALUES IN (7,8,15,16)
);

這種如果插入語句不在IN中,則會插入失敗

Hash分區

PARTITIONS爲分區的數量, 即會根據分區鍵的值計算出一個hash值,然後以4爲模進行存儲,好處是,不用再重新建分區了。

PARTITION BY HASH(store_id)
PARTITIONS 4;

還有Key分區,用的太少,不說了

操作分區表

增加刪除分區等語句看這裏

分區表由多個底層表構成,底層表跟普通表沒什麼區別,其索引也是分別在各個表中的索引。 分區表只是會在一個很粗的粒度上決定一下去哪個底層表繼續查詢。

  • SELECT 鎖住底層表,優化器先判斷可以過濾部分的分期,然後再調用存儲引擎接口訪問各個分區
  • INSERT DELETE同行
  • UPDATE 操作會需要設計更新後判斷在哪個分區,如果插入到了新分區,那麼則刪除原分區中的數據。
  • 使用WHERE語句最好能夠明確用到分區的關鍵字,這樣可以很好的命中分區
  • 鎖住底層表不一定是表鎖,會用到存儲引擎自己的行級鎖

如何使用

使用分區表肯定是因爲數據量非常大,這個時候索引已經不能很好的起作用了。
可以不使用索引,而用粗粒度的命中分區表,然後全表掃描。

或者是針對熱點數據,單獨使用一個區讓這個區都能夠放到緩存中,這樣就會有一個熱點的很小的分區,可以對其使用索引。

另外一些可能的問題:

  • NULL值,因爲TO_DAY等方法NULL值爲無效入參,會把值放在第一個分區,這個時候SELECT的時候可能會需要查找第一個和命中的分區這樣兩個分區,這樣可能會有很多的性能損耗,解決辦法是使第一個分區儘可能的小,第二個辦法是直接使用RANGE COLUMNS()而不使用函數
  • 分區列和索引列應該用同一個列,如果不是,會導致無法過濾的問題
  • 尋找分區的成本可能會比較高
  • 維護分區的成本,比如alter等語句改變分區個數,或者其他涉及數據遷移的操作

分區表的查詢

要在WHERE後面帶分區列,且不能是表達式
使用EXPLAIN PARTITIONS SELECT來判斷是否進行了分區過濾

分表

分區表還是一張表,是一種邏輯上的實現,主要解決的是單表數據過大,索引效率低的問題,很適合大量歷史數據,少量活躍數據的場景。把數據保存在不同的區域。

分表是真的有多張表,基於分表還可以做分庫,可以提升併發性能,以及磁盤I/O的性能。

二者可以配合使用。

使用集羣的方式

要配合複製使用,僅僅是把查詢請求進行了分攤。
但是這樣不會影響代碼層。

使用業務邏輯劃分

可一個根據用戶id來分,每個用戶一張表,這樣需要每有新的用戶都建表了。

還有常用的做法是預先設計好比如100張表,然後對數據的一個字段做hash,然後對100取模。

又或者根據時間來進行分割,這種的好處是,如果根據時間做統計的時候可以不用UNION

上面的分表方式都不能解決根據服務器壓力進行選擇的問你,並且也不能比較均勻的保存數據。

分表之後要考慮這樣幾個操作以後可能會帶來的問題:

  • 分頁, 主要看分頁情況下排序的字段是什麼,如果是時間,那麼按照時間段分表是比較好的, 如果會涉及到多個表的UNION,那麼就會比較耗費性能。
  • 插入, 更新。 主要是更新的時候的主鍵的問題,因爲分表之後主鍵不唯一了,因此需要用分表列和自增列做聯合主鍵。
  • 分組,統計。 這個跟分頁考慮的情況差不多,也是主要涉及排序的問題。比如如果每次都是需要按照用戶統計信息的話,那麼按照用戶分表的選擇是沒錯的。
  • 表的分發跟業務很比較大的關係。要儘量考慮比較多的因素和場景。
  • 通用一些的解決辦法是,對分頁字段使用搜索引擎
  • 或者對分頁和排序字段單獨列一張表不分,作爲查詢的索引。

使用merge存儲引擎

基本表:
CREATE TABLE TEST_MERGE_1(
ID INT(5) NOT NULL,
VALUE VARCHAR(100) NOT NULL,
PRIMARY KEY(ID)
);
CREATE TABLE TEST_MERGE_2(
ID INT(5) NOT NULL,
VALUE VARCHAR(100) NOT NULL,
PRIMARY KEY(ID)
);
MERGE表:
CREATE TABLE TEST_MERGE(
ID INT(5) NOT NULL,
VALUE VARCHAR(100) NOT NULL,
PRIMARY KEY(ID)
) TYPE=MRG_MyISAM INSERT_METHOD=LAST UNION=(TEST_MERGE_1,TEST_MERGE_2);

基本表必須是MYISAM類型的。
基本表的數據結構必須一致。
order by等語句,我想的是因爲Merge表裏有基本表共同的索引,所以,排序的時候應該是,都先比較第一個,然後再。。。有點像常用的大文件分成多個小文件,然後分別排序,最後merge的過程。

主要是能夠提供比較好的編碼界面。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章