首页 > 数据库 > 国内数据库 > 国产数据库分区表居然可以直接“撤回”成普通表了
在数据库运维这条路上,有些技术当年看起来是“高级配置”,过几年却往往变成“历史包袱”。
分区表就是最典型的一类。
系统刚上线时,按年、按月、按业务维度切分,看起来专业又稳妥;
但几年之后,很多库开始变得越来越难调:SQL 越跑越慢,优化器越来越玄,分区规则复杂到没人敢轻易碰,新同事更是绕着走。
慢慢地,一个问题就绕不开了:
如果当年的分区设计并不合适,现在还能不能改?
现实却往往很残酷——在大多数数据库里,这几乎意味着重建表、搬数据、停业务,代价不小,也风险不低。
ALTER TABLE … EXCHANGE PARTITION … WITH TABLE …
粗体第一反应是:
这玩意要真靠谱,那不是“小功能”,是运维体系级能力。
于是,我做了一次完整实操测试,模拟如下真实场景:
不是导数据、不是 CTAS、不是 COPY。
是 真正意义上的:分区表 → 普通表
CREATE TABLE SHIJW.CW_MZSFMX_INTERIM ( JLID NUMBER(10), BMID NUMBER(4), ZKID NUMBER(4), BRBH VARCHAR2(28), BRXM VARCHAR2(20), DWDM VARCHAR2(5), ZHID NUMBER(8), XMID NUMBER(8), FLM VARCHAR2(8), TJM VARCHAR2(4), MC VARCHAR2(100), KZJB VARCHAR2(1), YZLB VARCHAR2(2), DJ NUMBER(8,2), SL NUMBER(4), ZFJE NUMBER(9,2), JZJE NUMBER(9,2), JMJE NUMBER(9,2), ZLJE NUMBER(9,2), ZFBL NUMBER(3,2), YSID NUMBER(5), JYID NUMBER(10), SFYQ VARCHAR2(2), ZTBZ VARCHAR2(1), ZLHDID NUMBER(9), JMID NUMBER(8), SFLX VARCHAR2(1), SFRYID NUMBER(8), SFSJ DATE, SPBZ VARCHAR2(1), BZDM VARCHAR2(2), BAFLM VARCHAR2(3) ) PARTITION BY RANGE (SFSJ) ( PARTITION CW_MZSFMX_p1 VALUES LESS THAN (DATE '2011-01-01'), PARTITION CW_MZSFMX_p2 VALUES LESS THAN (DATE '2012-01-01'), PARTITION CW_MZSFMX_p3 VALUES LESS THAN (DATE '2013-01-01'), PARTITION CW_MZSFMX_p4 VALUES LESS THAN (DATE '2014-01-01'), PARTITION CW_MZSFMX_p5 VALUES LESS THAN (DATE '2015-01-01'), PARTITION CW_MZSFMX_p6 VALUES LESS THAN (DATE '2016-01-01'), PARTITION CW_MZSFMX_p7 VALUES LESS THAN (DATE '2017-01-01'), PARTITION CW_MZSFMX_p8 VALUES LESS THAN (DATE '2018-01-01'), PARTITION CW_MZSFMX_p9 VALUES LESS THAN (DATE '2019-01-01'), PARTITION CW_MZSFMX_p10 VALUES LESS THAN (DATE '2020-01-01'), PARTITION CW_MZSFMX_p11 VALUES LESS THAN (DATE '2021-01-01'), PARTITION CW_MZSFMX_p12 VALUES LESS THAN (DATE '2022-01-01'), PARTITION CW_MZSFMX_p13 VALUES LESS THAN (DATE '2023-01-01'), PARTITION CW_MZSFMX_p14 VALUES LESS THAN (DATE '2024-01-01'), PARTITION CW_MZSFMX_p15 VALUES LESS THAN (DATE '2025-01-01') );
CREATE SEQUENCE SHIJW.SEQ_CW_MZSFMX START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; BEGIN FOR i IN 1..100000 LOOP INSERT INTO shijw.CW_MZSFMX_INTERIM ( JLID, BMID, ZKID, BRBH, BRXM, DWDM, ZHID, XMID, FLM, TJM, MC, KZJB, YZLB, DJ, SL, ZFJE, JZJE, JMJE, ZLJE, ZFBL, YSID, JYID, SFYQ, ZTBZ, ZLHDID, JMID, SFLX, SFRYID, SFSJ, SPBZ, BZDM, BAFLM ) VALUES ( shijw.SEQ_CW_MZSFMX.NEXTVAL, TRUNC(DBMS_RANDOM.VALUE(1,10)), TRUNC(DBMS_RANDOM.VALUE(1,20)), 'BR'||LPAD(i,6,'0'), '患者'||MOD(i,100), 'DW'||MOD(i,50), TRUNC(DBMS_RANDOM.VALUE(10000,99999)), TRUNC(DBMS_RANDOM.VALUE(100,9999)), 'FL'||MOD(i,10), 'TJ'||MOD(i,20), '测试项目'||MOD(i,200), 'A', '01', ROUND(DBMS_RANDOM.VALUE(10,500),2), TRUNC(DBMS_RANDOM.VALUE(1,20)), ROUND(DBMS_RANDOM.VALUE(50,2000),2), ROUND(DBMS_RANDOM.VALUE(50,2000),2), ROUND(DBMS_RANDOM.VALUE(0,100),2), ROUND(DBMS_RANDOM.VALUE(10,500),2), ROUND(DBMS_RANDOM.VALUE(0.1,1),2), TRUNC(DBMS_RANDOM.VALUE(1,50)), TRUNC(DBMS_RANDOM.VALUE(100000,999999)), 'N', '1', 0, TRUNC(DBMS_RANDOM.VALUE(1,500)), '1', TRUNC(DBMS_RANDOM.VALUE(10,100)), DATE '2011-01-01' + TRUNC(DBMS_RANDOM.VALUE(0, 5000)), '0', '01', '001' ); IF MOD(i,1000)=0 THEN COMMIT; END IF; END LOOP; COMMIT; END; /
SELECT JLID, BMID, BRBH FROM SHIJW.CW_MZSFMX_INTERIM PARTITION (CW_MZSFMX_p3);
CREATE TABLE SHIJW.CW_MZSFMX ( JLID NUMBER(10), BMID NUMBER(4), ZKID NUMBER(4), BRBH VARCHAR2(28), BRXM VARCHAR2(20), DWDM VARCHAR2(5), ZHID NUMBER(8), XMID NUMBER(8), FLM VARCHAR2(8), TJM VARCHAR2(4), MC VARCHAR2(100), KZJB VARCHAR2(1), YZLB VARCHAR2(2), DJ NUMBER(8,2), SL NUMBER(4), ZFJE NUMBER(9,2), JZJE NUMBER(9,2), JMJE NUMBER(9,2), ZLJE NUMBER(9,2), ZFBL NUMBER(3,2), YSID NUMBER(5), JYID NUMBER(10), SFYQ VARCHAR2(2), ZTBZ VARCHAR2(1), ZLHDID NUMBER(9), JMID NUMBER(8), SFLX VARCHAR2(1), SFRYID NUMBER(8), SFSJ DATE, SPBZ VARCHAR2(1), BZDM VARCHAR2(2), BAFLM VARCHAR2(3) );
BEGIN DBMS_STATS.GATHER_TABLE_STATS( ownname => 'SHIJW', tabname => 'CW_MZSFMX_INTERIM', granularity => 'ALL' ); END; /
FROM USER_TAB_PARTITIONS WHERE TABLE_NAME = 'CW_MZSFMX_INTERIM' ORDER BY PARTITION_POSITION;
示例结果:
CW_MZSFMX_P2 7347 CW_MZSFMX_P3 7245 ...
ALTER TABLE SHIJW.CW_MZSFMX_INTERIM EXCHANGE PARTITION CW_MZSFMX_p2 WITH TABLE CW_MZSFMX INCLUDING INDEXES UPDATE GLOBAL INDEXES;
输出:
Succeed.
原分区表:
select count(*) from SHIJW.CW_MZSFMX_INTERIM; 92653
目标普通表:
select count(*) from shijw.CW_MZSFMX; 7347
熟悉 Oracle 的 DBA 应该会很有共鸣:
在 Oracle 世界里,如果要对一张“大表”做结构调整,通常会想到一个包:
DBMS_REDEFINITION.START_REDEF_TABLE
它的核心思想是:
在不影响业务的情况下,在线重构一张表的物理结构。
分区调整、字段变更、表结构重排,本质上都可以通过 redefinition 绕一圈来完成。
这在 Oracle 体系里,是一条极其成熟也极其“工程化”的能力路径。
而这次在 YashanDB V23.5 上体验 EXCHANGE PARTITION,给我非常相似的感觉:
• 并不追求“语法像不像”
• 而是解决同一类问题:在线改结构
• 把风险从“人”转移到“系统”
• 把重构从“项目动作”变成“日常运维能力”
如果说 DBMS_REDEFINITION 代表的是 Oracle 多年积累出来的结构重构能力,
那 YashanDB 在分区撤回这条路径上,已经开始走向真正的“工程化数据库”。
对 DBA 来说,最有价值的从来不是多一条语法,而是多一条:
可以在生产环境里“安全改结构”的路。
作者:Digital Observer(施嘉伟)
Oracle ACE Pro
PostgreSQL ACE Partner
Oracle OCM、KCM、PGCM、YCP、DB2 、MySQL OCP、PCTP、PCSD、OCI、PolarDB技术专家、达梦师资认证,从业11年+
ITPUB认证专家、崖山YVP、KWDB MVP、PolarDB开源社区技术顾问、HaloDB技术顾问、TiDB社区技术布道师、青学会MOP技术社区专家顾问、国内某高校企业实践指导教师
公众号/墨天轮/金仓社区/IF Club:Digital Observer;CSDN/PGfans:施嘉伟;ITPUB:sjw1933

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/23825935/viewspace-3107575/ ,如需转载,请注明出处,否则将追究法律责任。