MySQL——RDS下的分區表實踐

實踐背景

      項目中有的表空間太大,且行數太多,故決定對一些表進行分庫分表。再研究選型方案的時候發現經常使用的一些分庫分表的解決方案對業務代碼修改較多,故決定採用MySQL的分區方案。html

      其實在我我的看來,分區表就是MySQL幫咱們實現了底層的分庫分表,不須要涉及業務代碼的修改,不須要關注分佈式事務。由於就訪問數據庫而言,邏輯上仍是隻有一個表,可是實際上確有多個物理分區對象組成,會根據具體的分區規則查詢具體的分區。mysql

      介紹一下此次實踐的表,表空間大小172G,1億2千萬條記錄。sql

      數據庫版本:RDS MySQL 5.6數據庫

      工具:阿里雲DTS分佈式

1、爲何分區?

   優勢:

  •      對已過時或者不須要保存的數據,能夠經過刪除與這些數據有關的分區來快速刪除數據,它的效率遠比DELETE高
  •      在where子句中包含分區條件時,能夠只掃描必要的一個或者多個分區來提升查詢效率

       例以下面語句:函數

        SELECT * FROM t PARTITION(p0,p1)WHERE c <5 僅選擇與WHERE條件匹配的分區p0和p1中的記錄工具

  •      涉及聚合函數SUM()、COUNT()的查詢時,會在每一個分區上並行處理
  •      分區把本來一個表的數據存儲在多個物理磁盤上,實現了更高的IOPS

   缺點:

  •      沒法使用外鍵,不支持全文索引(如今應該也沒什麼公司還在用外鍵吧)
  •      分區鍵設計不太靈活,若是不走分區鍵,很容易出現全表鎖
  •     開發寫一個SQL,不清楚mysql是怎麼玩的

2、RANGE分區

    目前MySQL支持範圍分區(RANGE),列表分區(LIST),哈希分區(HASH)以及KEY分區四種。測試

    本文是以範圍分區(RANGE)對時間進行的分區的,故我就簡單介紹一下RANGE分區。更多分區類型詳見官方文檔MySQL 5.6 分區類型阿里雲

 

    基於一個給定連續區間的列值,根據區間分配分區。最多見的是基於時間字段。其實基於分區的列最好是整型,若是日期型的可使用函數轉換爲整型。MySQL 5.6支持的分區函數spa

    本例中使用TO_DAYS函數

    

CREATE TABLE members (
    id VARCHAR(25) NOT NULL,
    firstname VARCHAR(25) NOT NULL,
    lastname VARCHAR(25) NOT NULL,
    username VARCHAR(16) NOT NULL,
    email VARCHAR(35),
    joindate DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
    PRIMARY KEY (id,joindate) USING BTREE,
    KEY idx_joindate (joindate) USING BTREE
)ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT
PARTITION BY RANGE (TO_DAYS(joindate)) (
    PARTITION p0 VALUES LESS THAN (TO_DAYS('1960-01-01')),
    PARTITION p1 VALUES LESS THAN (TO_DAYS('1970-01-01')),
    PARTITION p2 VALUES LESS THAN (TO_DAYS('1980-01-01')),
    PARTITION p3 VALUES LESS THAN (TO_DAYS('1990-01-01')),
    PARTITION p4 VALUES LESS THAN MAXVALUE
);

 PS:像例子中的若是你有主鍵或惟一索引,你必須把你的分區鍵也加上,其中joindate就是分區鍵,要不建立會失敗!

 PS:像上面加了LESS THAN MAXVALUE,後面就不能新加分區了!!!

示例:

以下查詢就會落在定義的p2分區內的索引上。故在查詢的時候帶上你的分區鍵就會走對應分區查詢數據,若是你的條件跨越多個分區進行聚合函數SUM()、COUNT()的查詢時,它會在每一個分區上並行處理。若是沒有帶分區鍵查詢就會全表查詢。

explain partitions select * from members WHERE joindate BETWEEN '1970-02-03' AND '1970-02-04';

 

 

我在遷移完數據進行查詢的時候發現一個特別有意思的現象,同一條SQL若是分區鍵的時間區間不同,它會根據rows行數少的走不一樣的範圍索引。至於它底層是怎麼實現的我就沒去研究了

 

3、分區管理

      簡單介紹了下範圍分區,接下來講一下對分區經常使用的一下操做。

      分區管理包括對於分區的增長,刪除,以及查詢。更多詳見官方文檔MySQL 分區管理

    1.增長分區

      對於RANGE和LIST分區

alter table table_name add partition (partition p0 values ...(exp))

#例
ALTER TABLE members ADD PARTITION (TO_DAYS('2021-03-01'));

    2.刪除分區

      刪除了分區,同時也將刪除該分區中的全部數據。若是刪除了分區致使分區不能覆蓋全部值,那麼插入數據的時候會報錯。

alter table table_name drop partition p0;

   3.查詢有多少個分區

SELECT * FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'members';

4、數據遷移

  前面說了那麼多概念,我說一下本次把大表數據遷移到分區表的過程。

  爲何會選擇DTS呢?由於它能夠不停機遷移數據,支持全量遷移和增量遷移,對原表影響不大。

 

  遷移過程以下:

  1.   首先在RDS的同一個實例裏面新建了一張同結構的分區表
  2.   使用DTS建立遷移任務,遷移時候不要選擇結構錢謙益,只選擇全量+增量遷移
  3.   而後還須要編輯下目標庫表名,也就是作下映射從A->B的遷移
  4.   停掉寫入數據的任務,當任務隊列爲空時,等待幾分鐘暫停並結束遷移任務
  5.   最後修改表名,完成數據遷移和切換(我在測試環境修改分區表名要一些時間,但RDS修改表名是秒改)

 

參考官方文檔:MySQL 5.6 分區

以上純屬我的觀點,若有不對歡迎指正。

相關文章
相關標籤/搜索