ora-14097 根源是 oracle 在 sys.col$ 字典中字节级比对 column_id、类型、精度、空值性、隐藏/未使用列、默认值及约束等,任一差异即报错;ctas 会丢失 column_id 顺序、not null 约束、隐藏列、未使用列和 default 值,导致比对失败。
ora-14097 不是类型写错了,而是 oracle 在字节级比对 sys.col$ 字典记录时发现硬性不一致——字段顺序、默认值、隐藏列、未使用列、约束状态任一不同都会直接拒绝交换。
为什么 CTAS 生成的交换表总报 ORA-14097
CREATE TABLE AS SELECT * 会丢掉 column_id 物理顺序、NOT NULL 约束、隐藏列、未使用列、default 值等元数据。Oracle 不看语义,只按 user_tab_columns.column_id 逐字段比对。
- 用
SELECT column_name, column_id FROM user_tab_columns WHERE table_name IN ('SRC_TAB', 'EXCH_TAB') ORDER BY column_id对比两表字段顺序,错一位就失败 -
DESC和DBMS_METADATA.GET_DDL输出可能看起来一样,但内部sys.col$记录的default$、property(是否隐藏)、intcol#(内部列序)已不同 - 即使所有列名/类型/长度都一致,只要源表有
DEFAULT SYSDATE而交换表是DEFAULT NULL,也会触发错误
如何验证并修复字段级元数据差异
必须查字典视图,不能靠肉眼或 DDL 输出判断:
- 对比核心四字段:
SELECT column_name, data_type, data_length, data_precision, nullable FROM user_tab_columns WHERE table_name IN ('SRC_TAB', 'EXCH_TAB') ORDER BY table_name, column_id - 检查隐藏列:
SELECT column_name, hidden_column FROM user_tab_cols WHERE table_name = 'SRC_TAB' AND hidden_column = 'YES';交换表需用ALTER TABLE exch_tab ADD COLUMN ... INVISIBLE补齐 - 清理未使用列:
SELECT column_name FROM user_tab_cols WHERE table_name = 'SRC_TAB' AND column_name LIKE 'SYS_NC%' OR unused_col = 'YES';交换表执行ALTER TABLE exch_tab DROP UNUSED COLUMNS - 补全约束:
ALTER TABLE exch_tab MODIFY (col_name NOT NULL)或ADD CONSTRAINT exch_pk PRIMARY KEY (col1, col2)
kfed repair 后为什么 ASM 还看不到磁盘
修复磁盘头只是第一步,kfed repair 成功后 ASM 实例仍无法识别该盘,大概率是 AFD(ASM Filter Driver)未接管——asmcmd afd_lsdsk 显示状态不是 a(active),而是空或 d(disabled)。
-
kfed read /dev/sdi | egrep 'kfbh.type|dsknum|grpname'确认kfbh.type是KFBTYP_DISKHEAD且dsknum、grpname正确,仅说明磁盘头恢复成功 - 必须运行
asmcmd afd_lsdsk,确认目标设备状态为a;若为d,需执行afd_label重新标记或检查 udev 规则是否匹配 AFD 设备名 - RAC 环境下,每个节点都要单独验证 AFD 状态,不能只在单节点操作
重建物化视图日志前必须查清的三个依赖点
基表主键变更后,盲目 DROP MATERIALIZED VIEW LOG 可能导致其他 MV 刷新中断,必须先确认影响范围:
- 查复用关系:
SELECT log_owner, log_table, master FROM dba_mview_logs WHERE master = 'YOUR_TABLE',确认是否被多个 MV 共享 - 查 ON COMMIT MV:
SELECT mview_name FROM dba_mviews WHERE refresh_mode = 'COMMIT' AND master_table = 'YOUR_TABLE',这类 MV 必须停调度再操作 - 查 MV 定义中实际引用的列:
SELECT text FROM dba_views WHERE view_name = 'YOUR_MV_NAME',确保新主键列全部出现在 SELECT 列表或 WHERE 条件中,否则WITH PRIMARY KEY日志无效
最易被忽略的是:修复后没验证 AFD 状态就急着 ALTER DISKGROUP MOUNT,或者重建日志前没确认 MV 是否真在用那个日志——这些步骤跳过,问题只会原样重现。











