本文為墨天輪數據庫管理服務團隊第86期技術分享,內容原創,作者為技術顧問蘭珊,如需轉載請聯繫小墨(VX:modb666)並註明來源。如需查看更多文章可關注【墨天輪】公眾號。
一、報告概述
當單表數據量增長至千萬級甚至更大規模時,數據庫系統往往會面臨顯著的性能瓶頸與運維挑戰:
- 數據訪問的性能急劇下降,全表掃描耗時隨數據量指數級增長,索引訪問也難以降低範圍掃描的IO消耗;
- 系統維護難度陡增,數據歸檔、備份及DDL操作(如添加字段、分區調整)因數據規模膨脹而耗時數倍增長,甚至引發長時間鎖表阻塞業務;
- 資源爭用問題凸顯,高併發場景下I/O吞吐量達到甚至超過磁盤或網絡帶寬上限,同時大表操作導致的鎖競爭(如行鎖升級為表鎖)進一步加劇系統延遲。
針對此類問題,分區表技術通過將數據按特定規則(如範圍、哈希、列表)分片存儲到不同物理段,可有效分散數據訪問負載、加速數據歸檔與備份、減少鎖衝突範圍,從而在保證業務連續性的同時提升系統可擴展性。
二、常用分區類型
| 分區類型 | 適用場景 | 示例 |
|---|---|---|
| 範圍分區 | 時間序列數據(如訂單、日誌) | PARTITION BY RANGE (order_date) |
| 列表分區 | 離散值分類(如地區、狀態) | PARTITION BY LIST (region) |
| 哈希分區 | 均勻分佈數據,減少熱點 | PARTITION BY HASH (user_id) |
| 複合分區 | 多級分區(如先範圍再哈希) | PARTITION BY RANGE (date) SUBPARTITION BY HASH (id) |
三、實施步驟
3.1.表數據評估
- 分析數據分佈:統計時間字段範圍、高頻查詢條件、數據增長趨勢。
- 選擇分區鍵:優先選擇 高頻查詢條件字段或者數據傾斜比較明顯的字段。
- 確定分區粒度:例如按天、月分區,需平衡分區數量與單分區數據量(建議單分區不超過 5000 萬行)。
3.2.創建分區表
示例:按時間範圍分區(按月分區)
CREATE TABLE sales_partitioned (
sale_id NUMBER,
sale_date DATE,
customer_id NUMBER,
amount NUMBER
)
PARTITION BY RANGE (sale_date)
INTERVAL (NUMTOYMINTERVAL(1, 'MONTH')) -- 自動按每月創建新分區
(
PARTITION p_initial VALUES LESS THAN (TO_DATE('2023-01-01', 'YYYY-MM-DD'))
);
3.3.表數據遷移
當基於表數據情況、業務特徵等信息對分區表進行設計後,下一步就需要將原表中的數據遷移至新的分區表,根據數據量、環境情況、業務要求等不同,表數據遷移可以採取如下幾種方案:
方案一:在線重定義
1. 驗證表可重定義
EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE('SCHEMA_NAME', 'ORIG_TABLE');
2. 開始重定義
BEGIN
DBMS_REDEFINITION.START_REDEF_TABLE(
uname => 'SCHEMA_NAME',
orig_table => 'ORIG_TABLE',
int_table => 'INTERIM_TABLE',
options_flag => DBMS_REDEFINITION.CONS_USE_ROWID
);
END;
3. 同步數據
EXEC DBMS_REDEFINITION.SYNC_INTERIM_TABLE('SCHEMA_NAME', 'ORIG_TABLE', 'INTERIM_TABLE');
4. 完成重定義
EXEC DBMS_REDEFINITION.FINISH_REDEF_TABLE('SCHEMA_NAME', 'ORIG_TABLE', 'INTERIM_TABLE');
方案二:分區交換(適合歷史數據遷移)
1. 創建臨時表(與原表結構相同)
CREATE TABLE tmp_sales AS SELECT * FROM sales WHERE 1=0;
2. 遷移數據到臨時表
INSERT /*+ APPEND */ INTO tmp_sales SELECT * FROM sales WHERE sale_date < DATE '2023-01-01';
3. 交換分區
ALTER TABLE sales_partitioned
EXCHANGE PARTITION p_initial WITH TABLE tmp_sales
WITHOUT VALIDATION;
方案三:數據泵導出導入
1. 使用數據泵導出
expdp username/password@database
tables=SCHEMA_NAME.ORIGINAL_TABLE_NAME
directory=DATA_PUMP_DIR
dumpfile=data_only_export.dmp
logfile=data_only_export.log
content=DATA_ONLY
2. rename舊錶
ALTER TABLE old_table_name RENAME TO new_table_name;
3. 創建新分區表
CREATE TABLE sales_partitioned (
sale_id NUMBER,
sale_date DATE,
customer_id NUMBER,
amount NUMBER
)
PARTITION BY RANGE (sale_date)
INTERVAL (NUMTOYMINTERVAL(1, 'MONTH')) -- 自動按每月創建新分區
(
PARTITION p_initial VALUES LESS THAN (TO_DATE('2023-01-01', 'YYYY-MM-DD'))
);
4. 使用數據泵導入
impdp scott/tiger@database
directory=DATA_PUMP_DIR
dumpfile=emp_data.dmp
logfile=emp_data_imp.log
content=DATA_ONLY
四、分區改造後優化要點
4.1.表索引重建
分區表上往往存在索引,但不同的索引類型在分區表改造時的表現也各有不同,需要根據業務特性、維護需求、環境等情況選擇適合特定分區表的索引類型。常見的分區索引類型包括:全局索引、本地索引,這些索引的特性如下。
1、全局索引:全表唯一性約束,但維護成本高。
語法:
CREATE INDEX index_name
ON table_name (column_list)
GLOBAL PARTITION BY
RANGE(column_list) |
HASH(column_list) [PARTITIONS n] |
LIST(column_list)
(
PARTITION partition_name VALUES LESS THAN (value) [TABLESPACE tablespace_name],
PARTITION partition_name VALUES LESS THAN (value) [TABLESPACE tablespace_name],
...
PARTITION partition_name VALUES LESS THAN (MAXVALUE) [TABLESPACE tablespace_name]
)
[PARALLEL n];
示例
1)範圍分區的全局索引
CREATE INDEX idx_sales_global ON sales(sale_id)
GLOBAL PARTITION BY RANGE (sale_id)
(
PARTITION p1 VALUES LESS THAN (1000) TABLESPACE ts_idx1,
PARTITION p2 VALUES LESS THAN (5000) TABLESPACE ts_idx2,
PARTITION p3 VALUES LESS THAN (MAXVALUE) TABLESPACE ts_idx3
);
2)哈希分區的全局索引
CREATE INDEX idx_sales_hash ON sales(sale_id)
GLOBAL PARTITION BY HASH (sale_id) PARTITIONS 4;
3)列表分區的全局索引
CREATE INDEX idx_sales_list ON sales(region)
GLOBAL PARTITION BY LIST (region)
(
PARTITION p_east VALUES ('EAST') TABLESPACE ts_idx1,
PARTITION p_west VALUES ('WEST') TABLESPACE ts_idx2,
PARTITION p_other VALUES (DEFAULT) TABLESPACE ts_idx3
);
2、本地索引:按分區獨立維護,建議優先使用。
語法:
CREATE INDEX index_name
ON table_name (column_list)
LOCAL
[PARTITION partition_name [TABLESPACE tablespace_name]
[PARAMETERS ('physical_attributes')], ...]
[PARALLEL n];
示例
– 簡單本地分區索引
CREATE INDEX idx_sales_local ON sales(sale_date) LOCAL;
– 帶表空間的本地分區索引
CREATE INDEX idx_sales_local ON sales(sale_date) LOCAL
(
PARTITION p1 TABLESPACE ts_idx1,
PARTITION p2 TABLESPACE ts_idx2,
PARTITION p3 TABLESPACE ts_idx3
);
– 在分區表上創建本地分區索引
CREATE TABLE sales (
sale_id NUMBER,
sale_date DATE,
amount NUMBER
) PARTITION BY RANGE (sale_date) (
PARTITION p1 VALUES LESS THAN (TO_DATE('2023-01-01','YYYY-MM-DD')),
PARTITION p2 VALUES LESS THAN (TO_DATE('2023-04-01','YYYY-MM-DD')),
PARTITION p3 VALUES LESS THAN (MAXVALUE)
);
CREATE INDEX idx_sales_date ON sales(sale_date) LOCAL;
本地分區索引意味着每個表分區都有一個對應的索引分區,維護成本低,當表分區維護時索引會自動維護,但是不能跨分區。
業務人員應根據實際的業務需求、維護需求等情況進行選擇和創建。此外,
可以使用 ALTER INDEX … REBUILD PARTITION … 可以重建單個索引分區,也可以使用 USER\_PART\_INDEXES 和 USER\_IND\_PARTITIONS 視圖查詢分區索引信息。
4.2.分區表使用時的注意事項
1、分區剪裁:儘量確保 WHERE 條件包含分區鍵,避免全分區掃描。
2、業務兼容性:確保應用程序的SQL包含分區鍵條件。
3、鎖競爭:避免在高峯期執行分區維護操作。
墨天輪從樂知樂享的數據庫技術社區蓄勢出發,全面升級,提供多類型數據庫管理服務。墨天輪數據庫管理服務旨在為用户構建信賴可託付的數據庫環境,併為數據庫廠商提供中立的生態支持。
服務官網:https://www.modb.pro/service