How To Change the Partition Column Of A Partitioned Table Using DBMS_Redefinition [ID 846405.1]

本文提供了一步一步的指导,说明如何使用DBMS_REdefinition包将现有分区表的分区列转换为完全不同的分区列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

How To Change the Partition Column Of A Partitioned Table Using DBMS_Redefinition [ID 846405.1]


 

Modified 22-OCT-2009     Type HOWTO     Status PUBLISHED

 

In this Document
  Goal
  Solution
  References


Applies to:

Oracle Server - Enterprise Edition - Version: 10.2.0.4 to 11.2.0.2.0
Information in this document applies to any platform.

Goal

The purpose of this document is to provide step by step instructions on how to convert the partitioned column of an existing partitioned table to have a completely different partitioned column using dbms_redefinition package.

Solution

1) Create partitioned table (This is the table that needs to be redefined) with the name SALES.  We plan to repartition this table to use the MONTH_NO as the partitioning column.

Note:  The table already has a PK on this defined in the Create statement.

CREATE TABLE sales ( 
acct_no NUMBER(5), 
acct_name CHAR(30), 
amount_of_sale NUMBER(6), 
week_no INTEGER, 
month_no integer, 
sale_details VARCHAR2(1000), 
PRIMARY KEY (acct_no, acct_name, week_no)) 
PARTITION BY LIST (week_no) ( 
PARTITION part1234 VALUES (1, 2, 3, 4) tablespace users, 
PARTITION part5678 VALUES (5, 6, 7, 8) tablespace users, 
PARTITION partdefault VALUES (DEFAULT) tablespace users); 

insert into sales values (1,'acc 1',1,52,12,'sales details 1'); 
insert into sales values (2,'acc 2',2,51,12,'sales details 2'); 
insert into sales values (3,'acc 3',3,50,12,'sales details 3'); 
insert into sales values (4,'acc 4',4,1,1,'sales details 4'); 
insert into sales values (5,'acc 5',5,2,1,'sales details 5'); 
commit;

2) Gather statistics on the table:

EXEC DBMS_STATS.gather_table_stats('RK_MVIEW', 'SALES', cascade => TRUE);

3) Create a Partitioned Interim Table:

CREATE TABLE interim_sales ( 
     acct_no NUMBER(5), 
     acct_name CHAR(30), 
     amount_of_sale NUMBER(6),  
     week_no INTEGER, 
     month_no integer, 
     sale_details VARCHAR2(1000), 
     PRIMARY KEY (acct_no, acct_name, month_no))  
     PARTITION BY LIST (month_no) ( 
     PARTITION int_part1 VALUES (1) tablespace users, 
     PARTITION int_part12 VALUES (12) tablespace users, 
     PARTITION int_partdefault VALUES (DEFAULT) tablespace users);

4) Start the Redefinition Process: 

a) Check the redefinition is possible using the following command:

EXEC Dbms_Redefinition.can_redef_table('RK_MVIEW', 'SALES');

b)If no errors are reported, start the redefintion using the following command:

BEGIN  
DBMS_REDEFINITION.start_redef_table(  
uname => 'RK_MVIEW',   
orig_table => 'SALES',  
int_table => 'INTERIM_SALES');  
END;  

c) Optionally synchronize new table with interim name before index creation:

BEGIN  
dbms_redefinition.sync_interim_table(  
uname => 'RK_MVIEW',   
orig_table => 'SALES',  
int_table => 'INTERIM_SALES');   
END;  

d) Gather statistics on the new table:

EXEC DBMS_STATS.gather_table_stats('RK_MVIEW', 'INTERIM_SALES', cascade => TRUE); 

e) Complete the Redefintion Process:

BEGIN  
dbms_redefinition.finish_redef_table(  
uname => 'RK_MVIEW',   
orig_table => 'SALES',  
int_table => 'INTERIM_SALES');  
END;  

At this point the interim table has become the "real" table and their names have been switched in the name dictionary. 

f) Remove original table which now has the name of the interim table:

DROP TABLE INTERIM_SALES;

g) Check whether partitioning is successful or not:

SELECT partition_name 
FROM user_tab_partitions 
WHERE table_name = 'SALES';                                                                                                      

PARTITION_NAME 
------------------ 
INT_PART1 
INT_PART12 
INT_PARTDEFAULT

 

 

------------------------------------------------------------------------------

<think>我们正在讨论的是在Flink的CREATE MATERIALIZED TABLE语句中设置主键的问题。根据引用[1]中的信息,当连接器作为TableSink时,必须通过定义的主键来发送更新日志(changelog)。因此,在创建物化表时,我们需要定义主键。 在Flink SQL中,创建物化表的语法与创建普通表类似,可以在表定义中通过PRIMARY KEY子句来声明主键。注意,Flink要求主键必须被声明为NOT ENFORCED,因为Flink本身不强制主键约束,而是由连接器(如HBase、Paimon等)来保证。 以下是在CREATE MATERIALIZED TABLE语句中设置主键的示例: ```sql CREATE MATERIALIZED TABLE catalog_name.db_name.MyMaterializedTable PRIMARY KEY (id) NOT ENFORCED -- 在这里声明主键 WITH ( 'connector' = '...', ... ) AS SELECT id, name, age FROM source_table; ``` ### 关键点说明: 1. **主键位置**:在表名之后,WITH子句之前,使用`PRIMARY KEY (列名) NOT ENFORCED`来声明主键。 2. **主键字段**:主键可以是一个或多个字段。如果是多个字段,用逗号分隔,例如:`PRIMARY KEY (id, ts) NOT ENFORCED`。 3. **NOT ENFORCED**:必须加上`NOT ENFORCED`,因为Flink不会检查主键约束,而是由底层的存储系统(如HBase、Paimon)来维护主键的唯一性。 4. **与WITH子句的配合**:根据引用[1],如果底层存储系统(如HBase)要求主键,那么我们必须定义主键。同时,在WITH子句中可能需要指定连接器相关的参数,例如HBase的rowkey字段(通常就是主键)。 ### 示例:创建物化表并设置主键 假设我们有一个数据源表`source_table`,包含字段`id`(唯一标识)、`name`和`age`。我们想创建一个物化表,将结果写入到HBase,并设置`id`为主键。 ```sql CREATE MATERIALIZED TABLE MyHBaseSink PRIMARY KEY (id) NOT ENFORCED -- 设置主键 WITH ( 'connector' = 'hbase-2.2', 'table-name' = 'my_table', 'zookeeper.quorum' = 'localhost:2181', 'sink.buffer-flush.max-size' = '1mb', 'sink.buffer-flush.max-rows' = '1000', 'sink.buffer-flush.interval' = '2s', 'sink.parallelism' = '1' ) AS SELECT id, name, age FROM source_table; ``` 在这个例子中,我们声明了`id`为主键,这样HBase连接器就会使用`id`作为行键(rowkey)来更新或插入数据[^1]。 ### 注意事项: - 如果物化表的目标是支持更新的表(如HBase、Paimon等),则必须定义主键,否则在写入更新或删除操作时可能会出错(如题中出现的`Append only writer can not accept row with RowKind DELETE`错误)。 - 主键的选择:通常选择能够唯一标识记录的字段。如果源表是CDC数据(如Debezium),主键通常就是源表的主键。 ### 相关问题 1. 在Flink中创建物化表时,如果不设置主键会有什么后果? 2. 如何为Flink物化表设置复合主键? 3. Flink物化表支持哪些连接器?不同连接器对主键的要求有何不同? 4. 在Flink物化表中,主键字段是否必须包含在SELECT语句中?</think>### 在 Flink CREATE MATERIALIZED TABLE 语句中设置主键的方法 在 Flink SQL 中为物化表设置主键是确保数据更新和删除操作正确的关键步骤。以下是详细配置方法: #### 🔑 核心语法结构 ```sql CREATE MATERIALIZED TABLE [catalog_name].[db_name].table_name PRIMARY KEY (column1, column2, ...) NOT ENFORCED -- 主键声明位置 WITH ( 'connector' = '...', -- 其他连接器参数 ) AS SELECT ... FROM ...; ``` #### ✅ 完整示例(以 Paimon 为例) ```sql CREATE MATERIALIZED TABLE inventory_db.product_sales_materialized PRIMARY KEY (product_id, sale_date) NOT ENFORCED -- 声明复合主键 WITH ( 'connector' = 'paimon', 'path' = 's3://data-warehouse/product_sales', 'changelog-producer' = 'lookup', 'merge-engine' = 'deduplicate' -- 支持更新/删除 ) AS SELECT product_id, CAST(event_time AS DATE) AS sale_date, COUNT(*) AS total_sales, SUM(amount) AS total_revenue FROM kafka_sales_stream GROUP BY product_id, CAST(event_time AS DATE); ``` #### ⚙️ 关键配置说明 1. **主键位置** 在表名之后、WITH 子句之前声明 `PRIMARY KEY` 2. **NOT ENFORCED 必要性** Flink 本身不强制主键约束(由存储系统实现),必须添加 `NOT ENFORCED`[^1] 3. **复合主键语法** 多字段主键用逗号分隔: `PRIMARY KEY (col1, col2) NOT ENFORCED` 4. **连接器适配** 不同连接器需对应配置: ```sql -- HBase 需指定 rowkey WITH ('rowkey' = 'product_id') -- JDBC 需数据库主键支持 WITH ('primary-key' = 'product_id,sale_date') ``` #### 💡 最佳实践建议 1. **主键选择原则** - 选择唯一标识记录的字段(如业务主键) - 避免使用可空字段 - 复合主键字段总长度不宜过长(HBase 限制) 2. **更新性能优化** 对于频繁更新的表,添加索引字段: ```sql PRIMARY KEY (product_id, update_time) NOT ENFORCED -- 时间戳辅助排序 ``` 3. **主键字段验证** 确保 SELECT 语句包含所有主键字段: ```sql -- 错误示例(缺少 sale_date) AS SELECT product_id, total_sales FROM ... -- 正确示例 AS SELECT product_id, sale_date, total_sales FROM ... ``` 4. **与源表主键一致** 当源表有主键时,物化表应保持相同主键结构: ```sql -- 源表定义 CREATE TABLE source (id BIGINT PRIMARY KEY, ...) -- 物化表对应 PRIMARY KEY (id) NOT ENFORCED ``` #### ⚠️ 常见错误规避 1. **缺失 NOT ENFORCED** ```sql -- 错误 PRIMARY KEY (product_id) -- 正确 PRIMARY KEY (product_id) NOT ENFORCED ``` 2. **主键字段未出现在 SELECT** ```sql -- 错误(缺少 region_id) PRIMARY KEY (product_id, region_id) AS SELECT product_id, ... -- 缺少 region_id ``` 3. **连接器不支持主键** ```sql -- 纯追加连接器(如kafka)不支持主键更新 WITH ('connector' = 'kafka') -- 不能处理DELETE ``` --- ### 🔍 主键工作原理示意图 ```mermaid graph LR A[Flink 流处理作业] --> B{主键声明} B -->|存在| C[生成变更日志<br>INSERT/UPDATE/DELETE] B -->|缺失| D[仅追加模式<br>无法处理删除] C --> E[存储系统按主键更新] D --> F[遇到删除操作时报错] ``` --- ### 📚 相关问题 1. 如何在 Flink 物化表中设置复合主键? 2. 当主键字段来源于表达式时如何处理?例如 `PRIMARY KEY (DATE_FORMAT(ts))` 3. 不同存储系统(HBase/JDBC/Paimon)对主键的实现差异有哪些? 4. 如何监控 Flink 物化表的主键冲突? 5. 物化表主键和源表主键不一致时会产生什么后果?[^2] 6. 在流批一体场景下,主键声明对批处理任务有何影响?[^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值