【问题标题】:Oracle Forced dropping of Foreign Key during purge on Interval Partitioned TablesOracle 在间隔分区表的清除期间强制删除外键
【发布时间】:2013-11-03 03:47:42
【问题描述】:

我们有几个按天间隔分区的表。在进行清除工作以删除一天的分区时,我们的 DBA 通知我们,在执行清除之前,我们必须将所有外键删除到任何表中。这似乎是一个不必要的步骤,因此,我正在求助于 stackoverflow 的智慧。

 parentTable     childTable
 ID   (PK)       ID   (PK)(FK)
 date (PK)       date (PK)(FK)
                 otherKey(PK)

 parentTable             childTable
 ID     date         ID    date    otherKey  
 1       10/23        1     10/23     a
 2       10/23        2     10/23     a
 3       10/23        3     10/23     a
 1       10/24        1     10/24     a
 2       10/24        2     10/24     a
                      2     10/24     b

问题是,如果我们要从 childTable 中删除 10/23 分区(首先),然后是 parentTable,我们是否必须在清除之前删除/禁用外键约束,然后再创建它?是否存在必须发生这种情况的数据情况(可能不像我上面的示例所示)。

【问题讨论】:

  • DBA 给了你什么理由?
  • 即使按照正确的顺序删除,数据库也能够发现主键存在并且不会处理父表,除非所有引用父表的 FK 都被删除。并不是说它会导致基于记录值的违规行为。在删除分区时,在分区表中,Oracle 会查看是否存在正在使用的外键约束。如果是这样,它不允许从父表中删除一个分区(任何分区)。

标签: oracle database-design foreign-keys purge sql-drop


【解决方案1】:

不是一个直接的答案,但听起来您在这里真正想要的是参考分区,它会:

  • 级联分区维护操作
  • 允许更简单的查询
  • 提供两个表的分区在逻辑上关联的元数据
  • 可能会在插入子表时增加少量开销。

http://docs.oracle.com/cd/B28359_01/server.111/b32024/partition.htm#CACIHDII

【讨论】:

    【解决方案2】:

    有一天我会学会在那里管理我的代码,所以..

    CREATE OR REPLACE PROCEDURE manage_constraints (i_status IN varchar2)
    
    IS
    
       CURSOR ref_cons
    
       IS
    
          SELECT constraint_name, table_name, status
    
          FROM user_constraints
    
          WHERE constraint_type in ( 'R')  ; -- YOu can disable more constraints type 
    
    
       v_status   VARCHAR2 (10);
    
       v_sql      VARCHAR2 (300);
    
    BEGIN
    
       FOR e_cons IN ref_cons
    
       LOOP
    
          v_sql   :=
    
                'ALTER TABLE '
    
             || e_cons.table_name
    
             || ' '
    
             || i_status
    
             || '  CONSTRAINT '
    
             || e_cons.constraint_name;
    
    
          --DBMS_OUTPUT.put_line (v_sql);
    
          EXECUTE IMMEDIATE v_sql;
    
       END LOOP;
    
    EXCEPTION
    
       WHEN OTHERS
    
       THEN
    
          RAISE;
    
    END;
    
    
    --exec manage_constraints('DISABLE');
    
    --exec manage_constraints('ENABLE');
    

    您可以在此处禁用所有约束,然后再启用它们。

    select * from user_constraints
    

    检查约束类型...希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      看来DBA是对的,测试用例场景:

      CREATE TABLE parent_tab (
        id NUMBER PRIMARY KEY,
        start_date DATE
      )
      PARTITION BY RANGE (start_date)
      INTERVAL(NUMTODSINTERVAL(1, 'DAY'))
      ( 
         PARTITION pos_data_p2 VALUES LESS THAN (TO_DATE('01-01-2013', 'DD-MM-YYYY')) 
      );
      
      INSERT INTO parent_tab VALUES (1, DATE '2012-01-01');
      INSERT INTO parent_tab VALUES (2, DATE '2013-01-02');
      INSERT INTO parent_tab VALUES (3, DATE '2013-01-03');
      
      CREATE TABLE child_tab (
         start_date DATE,
         parent_tab_id NUMBER REFERENCES parent_tab(id)
      )
      PARTITION BY RANGE (start_date)
      INTERVAL(NUMTODSINTERVAL(1, 'DAY'))
      ( 
         PARTITION pos_data_p2 VALUES LESS THAN (TO_DATE('01-01-2013', 'DD-MM-YYYY'))
      );
      
      INSERT INTO child_tab VALUES (DATE '2012-01-01', 1);
      INSERT INTO child_tab VALUES (DATE '2013-01-02', 2);
      INSERT INTO child_tab VALUES (DATE '2013-01-03', 3);
      
      COMMIT;
      
      SELECT table_name, partition_name FROM user_tab_partitions WHERE table_name IN ('PARENT_TAB', 'CHILD_TAB');
      
      TABLE_NAME                     PARTITION_NAME               
      ------------------------------ ------------------------------
      CHILD_TAB                      POS_DATA_P2                    
      CHILD_TAB                      SYS_P69                        
      CHILD_TAB                      SYS_P70                        
      PARENT_TAB                     POS_DATA_P2                    
      PARENT_TAB                     SYS_P67                        
      PARENT_TAB                     SYS_P68                        
      
      ALTER TABLE child_tab DROP PARTITION SYS_P69;
      
      > table CHILD_TAB altered.
      
      ALTER TABLE parent_tab DROP PARTITION SYS_P67;
      
      ALTER TABLE parent_tab DROP PARTITION SYS_P67
      Error report:
      SQL Error: ORA-02266 -  "unique/primary keys in table referenced by enabled foreign keys"
      *Cause:    An attempt was made to truncate a table with unique or
                 primary keys referenced by foreign keys enabled in another table.
                 Other operations not allowed are dropping/truncating a partition of a
                 partitioned table or an ALTER TABLE EXCHANGE PARTITION.
      *Action:   Before performing the above operations the table, disable the
                 foreign key constraints in other tables. You can see what
                 constraints are referencing a table by issuing the following
                 command:
                 SELECT * FROM USER_CONSTRAINTS WHERE TABLE_NAME = "tabnam";
      

      编辑

      正如作者指出的,禁用约束有效:

      SELECT table_name, constraint_name, constraint_type FROM user_constraints WHERE table_name = 'CHILD_TAB';
      
      TABLE_NAME                     CONSTRAINT_NAME                CONSTRAINT_TYPE
      ------------------------------ ------------------------------ ---------------
      CHILD_TAB                      SYS_C0033723                   R               
      
      ALTER TABLE child_tab DISABLE CONSTRAINT SYS_C0033723;
      
      ALTER TABLE parent_tab DROP PARTITION SYS_P67;
      
      > table PARENT_TAB altered.
      
      ALTER TABLE child_tab ENABLE CONSTRAINT SYS_C0033723;
      

      【讨论】:

      • 谢谢,但是从我正在阅读的内容来看,“在对表执行上述操作之前,禁用其他表中的外键约束”不必删除和创建 FK 约束,它们可以只是被禁用,它应该工作。这很容易,因为所有这些表都在同一个模式中,禁用此所有者/模式中的所有 FK,执行所有删除分区,然后重新启用它们。
      • @user2210179 你说得对,我在答案中添加了一个例子。
      猜你喜欢
      • 1970-01-01
      • 2018-06-13
      • 2015-05-23
      • 2021-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多