oracle ORA-14075:分区维护操作只能在分区索引上执行

uubf1zoe  于 2023-11-17  发布在  Oracle
关注(0)|答案(1)|浏览(277)

我有几个Oracle表,每个表都在“日期”列上分区。例如,我有一个分区的Oracle表,其中包含以下列:

id,date,customer_id,code,name,last_name

字符串
它的主键在“id,date”上,也在“date”字段上进行了分区。此外,我在“customer_id”和“code”上定义了两个单独的索引。我有一个Python程序,我必须使表的每个索引不可用,并在将数据加载到每个表后,使用此查询选择表的所有索引,并重建当前日期分区的每个索引。代码如下:

def rebuild_index_partition(self,date, table_name):
            query = "(select partition_name pname from all_tab_partitions where table_name like upper('%{0}%') and " \
            "to_date(trim('''' from regexp_substr(extractvalue(dbms_xmlgen.getxmltype('select high_value from all_tab_partitions " \
            "where table_name='''||table_name||''' and table_owner = '''||table_owner||''' and partition_name = '''||partition_name||'''')," \
            "'//text()'),'''.*?''')),'syyyy-mm-dd hh24:mi:ss')= to_date({1}, 'yyyymmdd', 'nls_calendar=persian') + 1)".format(
        table_name, date)
            df = pd.read_sql(query,self.conn)
            pname = df.loc[0, 'PNAME']
            index_query = f'''select distinct a.index_name index_name from all_ind_columns a, all_indexes b where a.index_name=b.index_name and a.table_name = upper('{table_name}') '''
            df_index = pd.read_sql(index_query,self.conn)
            list_index = df_index['INDEX_NAME'].tolist()
            for i in list_index:
                rebuild_index = "alter index {0} rebuild partition {1}".format(i, pname)
                self.execute(rebuild_index)
       return


问题是当运行rebuildindex时,它会给出以下错误:

ORA-14075: partition maintenance operations may only be performed on partitioned indices
   14075. 00000 -  "partition maintenance operations may only be performed on partitioned indices"
      *Cause:    Index named in ALTER INDEX partition maintenance operation
       is not partitioned, making a partition maintenance operation,
       at best, meaningless
     *Action:   Ensure that the index named in ALTER INDEX statement
       specifying a partition maintenance operation is, indeed,
       partitioned


这是因为主键没有分区。我不知道如何使主键分区,本地索引。
请你指导我如何解决这个问题好吗?
任何帮助真的很感激。

kt06eoxx

kt06eoxx1#

你只需要对 * 非 * 分区索引使用alter index abc rebuild,对 * 分区索引使用alter index abc rebuild partition xyz(在每个分区上循环)。这里有一个PL/SQL块,它可以处理所有这些。如果你喜欢在客户端环境中执行循环,你可以根据你的编程环境调整这里看到的内容,但这说明了方法:

BEGIN
  FOR rec_index IN (SELECT index_owner,index_name
                      FROM all_indexes
                     WHERE table_name = upper('{table_name}')
                       AND status = 'UNUSABLE') -- partitioned indexes will say N/A and so be skipped here
  LOOP
    EXECUTE IMMEDIATE 'ALTER INDEX "'||rec_index.index_owner||'"."'||rec_index.index_name||'" REBUILD';
  END LOOP;
   
  FOR rec_index IN (SELECT ip.index_owner,
                           ip.index_name, 
                           ip.partition_name
                      FROM all_ind_partitions ip,
                           all_indexes i
                     WHERE i.table_name = upper('{table_name}')
                       AND i.owner = ip.index_owner
                       AND i.index_name = ip.index_name
                       AND ip.status = 'UNUSABLE')
  LOOP
    EXECUTE IMMEDIATE 'ALTER INDEX "'||rec_index.index_owner||'"."'||rec_index.index_name||'" REBUILD PARTITION "'||rec_index.partition_name||'"';
  END LOOP;
END;

字符串
但如果我可以提出一个建议,如果你正在做日常维护和无效的全球索引,你应该重新评估这些索引是否应该是全局索引。你最好将 all 索引作为本地索引。唯一的例外是,如果你有针对唯一或接近唯一的索引的高频率查找,唯一的值,并且你有非常大的分区数量。在这种情况下,你需要保持它的全局性。但是如果列不接近-如果它是唯一的,或者如果对其进行查找的频率较低或分区的数量相对较小,则可能值得将其设置为本地,以避免每次不必要的全索引重建。

更新:帮助您按照要求将PK本地化,如果您创建的表是这样的:

create table tmp1 (col1 integer, constraint pk_tmp1 primary key (col1)) partition by . . .;


然后强制执行约束的索引被隐式地绑定到约束,并且当你删除约束时也会删除。所以,只需使用using index子句删除并重新添加约束:

alter table tmp1 drop constraint pk_tmp1;
alter table tmp1 add constraint pk_tmp1 primary key (col1) using index local;


如果索引是创建的,约束是后来添加的,像这样:

create table tmp1 (col1 integer) partition by . . .;
create unique index pk_tmp1 on tmp1(col1);
alter table tmp1 add constraint pk_tmp1 primary key (col1) using index pk_tmp1;


然后你有一个单独的索引和约束,必须单独处理它们。然后你需要删除约束,删除索引,重新创建索引,然后重新添加约束:

alter table tmp1 drop constraint pk_tmp1;
drop index pk_tmp1;
create unique index pk_tmp1 on tmp1(col1) local;
alter table tmp1 add constraint pk_tmp1 primary key (col1) using index pk_tmp1;


如果您希望完全删除表并重新创建它(没有必要这样做,会导致数据丢失),您可以这样做:

drop table tmp1;     
create table tmp1 (col1 integer, constraint pk_tmp1 primary key (col1) using index local) partition by . . .;

相关问题