【问题标题】:Oracle: how to drop a subpartition of a specific partitionOracle:如何删除特定分区的子分区
【发布时间】:2012-09-04 02:15:29
【问题描述】:

我正在使用带有间隔分区和列表子分区的 oracle 11 表,如下所示(简化):

CREATE TABLE LOG
(
  ID NUMBER(15, 0) NOT NULL PRIMARY KEY
, MSG_TIME DATE NOT NULL
, MSG_NR VARCHAR2(16 BYTE)
) PARTITION BY RANGE (MSG_TIME) INTERVAL (NUMTOYMINTERVAL (1,'MONTH'))
  SUBPARTITION BY LIST (MSG_NR)
    SUBPARTITION TEMPLATE (
     SUBPARTITION login VALUES ('FOO')
   , SUBPARTITION others VALUES (DEFAULT)
   )
   (PARTITION oldvalues VALUES LESS THAN (TO_DATE('01-01-2010','DD-MM-YYYY')));

如何在不知道子分区(系统生成的)名称的情况下删除特定月份的特定子分区?有一个语法"alter table ... drop subpartition for (subpartition_key_value , ...)",但我看不到指定删除子分区的月份的方法。 partition administration guide 也没有给出任何示例。 8-}

【问题讨论】:

    标签: oracle oracle11g partitioning database-partitioning


    【解决方案1】:

    您可以使用元数据表来获取特定的子分区名称:

    SQL> insert into log values (1, sysdate, 'FOO');
    
    1 row(s) inserted.
    
    SQL> SELECT p.partition_name, s.subpartition_name, p.high_value, s.high_value
      2    FROM    user_tab_partitions p
      3         JOIN
      4            user_tab_subpartitions s
      5         ON s.table_name = p.table_name
      6        AND s.partition_name = p.partition_name
      7        AND p.table_name = 'LOG';
    
    PARTITION_NAME  SUBPARTITION_NAME  HIGH_VALUE   HIGH_VALUE
    --------------- ------------------ ------------ ----------
    OLDVALUES       OLDVALUES_OTHERS   2010-01-01   DEFAULT
    OLDVALUES       OLDVALUES_LOGIN    2010-01-01   'FOO'
    SYS_P469754     SYS_SUBP469753     2012-10-01   DEFAULT
    SYS_P469754     SYS_SUBP469752     2012-10-01   'FOO'
    
    SQL> alter table log drop subpartition SYS_SUBP469752;
    
    Table altered.
    

    如果您想动态删除一个分区,使用ALL_TAB_SUBPARTITIONS 视图找到它可能会很棘手,因为HIGH_VALUE 列可能不容易查询。在这种情况下,您可以使用DBMS_ROWID 来查找给定行的子分区object_id

    SQL> insert into log values (4, sysdate, 'FOO');
    
    1 row(s) inserted.
    
    SQL> DECLARE
      2     l_rowid_in         ROWID;
      3     l_rowid_type       NUMBER;
      4     l_object_number    NUMBER;
      5     l_relative_fno     NUMBER;
      6     l_block_number     NUMBER;
      7     l_row_number       NUMBER;
      8  BEGIN
      9     SELECT rowid INTO l_rowid_in FROM log WHERE id = 4;
     10     dbms_rowid.rowid_info(rowid_in       =>l_rowid_in     ,
     11                           rowid_type     =>l_rowid_type   ,
     12                           object_number  =>l_object_number,
     13                           relative_fno   =>l_relative_fno ,
     14                           block_number   =>l_block_number ,
     15                           row_number     =>l_row_number   );
     16     dbms_output.put_line('object_number ='||l_object_number);
     17  END;
     18  /
    
    object_number =15838049
    
    SQL> select object_name, subobject_name, object_type 
      2    from all_objects where object_id = '15838049';
    
    OBJECT_NAME     SUBOBJECT_NAME  OBJECT_TYPE
    --------------- --------------- ------------------
    LOG             SYS_SUBP469757  TABLE SUBPARTITION
    

    【讨论】:

      【解决方案2】:

      事实证明,“subpartition for”语法确实有效,尽管这似乎是 Oracle 不想告诉您的一个秘密。 :-)

      ALTER TABLE TB_LOG_MESSAGE DROP SUBPARTITION FOR 
            (TO_DATE('01.02.2010','DD.MM.YYYY'), 'FOO')
      

      这将删除包含 MSG_TIME 2010/02/01 和 MSG_NR FOO 的子分区。 (没有必要存在具有此确切 MSG_TIME 和 MSG_NR 的实际行。但是,如果没有这样的子分区,则会引发错误。)

      【讨论】:

      【解决方案3】:

      感谢您的帖子 - 它对我非常有用。

      在上述脚本中的一个观察结果是识别分区并删除它:

      dbms_rowid.rowid_info 返回的object_id 不是all_objects 表的object_id。它实际上是data_object_id。据观察,通常这些 id 匹配。但是,在多次截断分区表后,这些 id 在我的数据库中出现了分歧。因此,改用data_object_id 来找出分区的名称可能是合理的:

      select object_name, subobject_name, object_type 
      from all_objects where data_object_id = '15838049';
      
      From the table description of ALL_OBJECTS:
      

      OBJECT_ID 对象的对象编号 DATA_OBJECT_ID 包含对象的段的对象编号

      http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_rowid.htm

      在上述链接中提供的示例代码中,DBMS_ROWID.ROWID_OBJECT(row_id) 用于派生与dbms_rowid.rowid_info 给出的相同信息。但是,围绕此示例的文档提到它是来自 ROWID 的数据对象编号。

      例子

      此示例返回 EMP 表中一行的 ROWID,提取 来自 ROWID 的数据对象编号,使用 ROWID_OBJECT 函数 在 DBMS_ROWID 包中,然后显示对象编号:

      DECLARE object_no INTEGER; row_id ROWID; ...开始
      SELECT ROWID INTO row_id FROM emp 其中empno = 7499; object_no := DBMS_ROWID.ROWID_OBJECT(row_id); DBMS_OUTPUT.PUT_LINE('obj.#是 '|| object_no); ...

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-11-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-07
        • 1970-01-01
        相关资源
        最近更新 更多