MySQL表分區
前言
表數據量過大時(一般指超過500萬條)時可以考慮分區或分表方式。
相比分表,分區更爲簡單,不需要對錶的列進行拆分,應用程序不需要修改,也不需要引入分表分庫的中間件。
表分區
常見的表分區是根據用戶id、或區域,或日期進行分區。
根據日期進行分區
常見按天或按月進行分區,取決於每個分區的數據量大小。
查看數據庫是否支持分區
show variables like '%partition%';
查看錶分區定義
show create table <table>;
增加分區
作爲分區的字段必須爲主鍵或唯一索引的一部分。
按天進行分區:
ALTER TABLE <table> ADD PARTITION BY RANGE (to_days(visit_date))
(
PARTITION p_20200401 VALUES LESS THAN (to_days('2020-04-02')),
PARTITION p_20200402 VALUES LESS THAN (to_days('2020-04-03')),
PARTITION p_20200403 VALUES LESS THAN (to_days('2020-04-04')),
PARTITION p_20200404 VALUES LESS THAN (to_days('2020-04-05')),
PARTITION p_20200405 VALUES LESS THAN (to_days('2020-04-06')),
PARTITION p_20200406 VALUES LESS THAN (to_days('2020-04-07')),
PARTITION p_20200407 VALUES LESS THAN (to_days('2020-04-08')),
PARTITION p_20200408 VALUES LESS THAN (to_days('2020-04-09')),
PARTITION p_20200409 VALUES LESS THAN (to_days('2020-04-10')),
PARTITION p_20200410 VALUES LESS THAN (to_days('2020-04-11')),
PARTITION p_20200411 VALUES LESS THAN (to_days('2020-04-12')),
PARTITION p_20200412 VALUES LESS THAN (to_days('2020-04-13')),
PARTITION p_20200413 VALUES LESS THAN (to_days('2020-04-14')),
PARTITION p_20200414 VALUES LESS THAN (to_days('2020-04-15')),
PARTITION p_20200415 VALUES LESS THAN (to_days('2020-04-16')),
PARTITION p_20200416 VALUES LESS THAN (to_days('2020-04-17')),
PARTITION p_20200417 VALUES LESS THAN (to_days('2020-04-18')),
PARTITION p_20200418 VALUES LESS THAN (to_days('2020-04-19')),
PARTITION p_20200419 VALUES LESS THAN (to_days('2020-04-20')),
PARTITION p_20200420 VALUES LESS THAN (to_days('2020-04-21')),
PARTITION p_20200421 VALUES LESS THAN (to_days('2020-04-22')),
PARTITION p_20200422 VALUES LESS THAN (to_days('2020-04-23')),
PARTITION p_20200423 VALUES LESS THAN (to_days('2020-04-24')),
PARTITION p_20200424 VALUES LESS THAN (to_days('2020-04-25')),
PARTITION p_20200425 VALUES LESS THAN (to_days('2020-04-26')),
PARTITION p_20200426 VALUES LESS THAN (to_days('2020-04-27')),
PARTITION p_20200427 VALUES LESS THAN (to_days('2020-04-28')),
PARTITION p_20200428 VALUES LESS THAN (to_days('2020-04-29')),
PARTITION p_20200429 VALUES LESS THAN (to_days('2020-04-30')),
PARTITION p_other VALUES LESS THAN (MAXVALUE)
);
按月分區:
ALTER TABLE <table> ADD PARTITION BY RANGE (to_days(visit_date))
(
PARTITION p_202001 VALUES LESS THAN (to_days('2020-02-01')),
PARTITION p_202002 VALUES LESS THAN (to_days('2020-03-01')),
PARTITION p_202003 VALUES LESS THAN (to_days('2020-04-01')),
PARTITION p_202004 VALUES LESS THAN (to_days('2020-05-01')),
PARTITION p_202005 VALUES LESS THAN (to_days('2020-06-01')),
PARTITION p_202006 VALUES LESS THAN (to_days('2020-07-01')),
PARTITION p_202007 VALUES LESS THAN (to_days('2020-08-01')),
PARTITION p_202008 VALUES LESS THAN (to_days('2020-09-01')),
PARTITION p_202009 VALUES LESS THAN (to_days('2020-10-01')),
PARTITION p_202010 VALUES LESS THAN (to_days('2020-11-01')),
PARTITION p_202011 VALUES LESS THAN (to_days('2020-12-01')),
PARTITION p_202012 VALUES LESS THAN (to_days('2021-01-01')),
PARTITION p_other VALUES LESS THAN (MAXVALUE)
);
早期的MySQL版本只支持整數來進行範圍分區,因此需要用to_days()
函數將日期轉換爲整數,較新的MySQL已經支持直接根據Date或Datetime類型的列來分區,對Timestamp類型的列還是需要用UNIX_TIMESTAMP()
函數將時間戳轉換爲整數。
參考:
查看執行計劃是否使用了分區
EXPLAIN PARTITIONS SELECT count(1) FROM <table> WHERE visit_date = '2020-04-01';
檢查partitions是否命中了正確的分區。
查看執行計劃
EXPLAIN SELECT count(1) FROM <table> WHERE visit_date = '2020-04-01';
執行計劃說明:
- type的性能好壞依次爲:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
- 一般要求type性能不應該低於range,最好能達到ref或以上
參考: