如何在 Oracle 循环中的 select 语句中执行 alter 命令?

How to execute alter command within select statement in a loop in Oracle?

我正在尝试通过脚本重建模式的索引,但我卡在了通过 select 语句获取字符串 ALTER INDEX OWNER.INDEX_NAME REBUILD NOLOGGING 的位置,但我没有得到如何执行alter命令,请指导:

我试图为 str 分配第二个 for 循环中使用的 select 查询的值,然后执行它但出现错误。

IS
STR VARCHAR2(5000);
BEGIN

    FOR T IN (
     SELECT USERNAME FROM DBA_USERS WHERE USERNAME ='REPORT'
      )
     LOOP
     
     FOR CUR IN 
     (
       SELECT ' ALTER INDEX '||OWNER||'.'||INDEX_NAME|| ' REBUILD NOLOGGING; ' FROM DBA_INDEXES 
         WHERE  OWNER=T.USERNAME AND TEMPORARY='N'
       )
        
        LOOP 
       --- EXECUTE IMMEDIATE STR ;
       INSERT INTO INDEX_REBUILD_HISTORY 
         SELECT DISTINCT  OWNER, TRUNC(LAST_DDL_TIME) from DBA_OBJECTS where OBJECT_TYPE = 'INDEX' 
         AND 
         OWNER=T.USERNAME ;
         COMMIT;
    
         
    END LOOP;
    END LOOP;
    
    END ; 

“它出错了。”没有您收到的实际错误没有帮助。那就是说你犯了很多其他人犯的同样的错误,你不应该包括“;”作为动态的一部分 SQL - 它不是语句的一部分,它仅供您的客户用来了解何时将代码发送到数据库。

FOR CUR IN 
     (
       SELECT ' ALTER INDEX '||OWNER||'.'||INDEX_NAME|| ' REBUILD NOLOGGING' ddl_cmd FROM DBA_INDEXES 
         WHERE  OWNER=T.USERNAME AND TEMPORARY='N'
       )
...
EXECUTE IMMEDIATE CUR.ddl_cmd ;

(我还为该列指定了别名,以便您可以在循环中很好地使用它。

然后

  INSERT INTO INDEX_REBUILD_HISTORY 
         SELECT DISTINCT  OWNER, TRUNC(LAST_DDL_TIME) from DBA_OBJECTS where OBJECT_TYPE = 'INDEX' 
         AND 
         OWNER=T.USERNAME ;

没有过滤您刚刚重建的索引,它似乎不会获得完全有用的信息。

也就是说…… 离线重建所有索引并使它们不可恢复真的值得吗?可能不会,如果您不止一次这样做并且从中受益,那么您的数据模型可能会有所改变以提供帮助。仔细阅读 Richard Foote 的演讲,他是一位知名的 Oracle 索引专家 https://richardfoote.files.wordpress.com/2007/12/index-internals-rebuilding-the-truth.pdf 我怀疑您是否会认为重建所有索引是一个解决方案而放弃它。

您使用动态sql。而且您不需要外循环。 dba_indexes:

中可用的过滤器
create procedure bld_idx
is
vsql varchar2(500);

for x in (select owner,
                 index_name
          from dba_indexes
          where owner = 'REPORT'
          and TEMPORARY='N'
          )
loop
  vsql := ' ALTER INDEX '||x.OWNER||'.'||x.INDEX_NAME|| ' REBUILD NOLOGGING; ';
  dbms_output.put_line(vsql);  --  debugging only
  execute immediate vsql;
end loop;
end;

注1:以上是我的头脑。可能存在一些小的语法问题,但如果是这样,您应该能够解决它们。

不是2:重建索引不是正常过程中需要做的事情。 Richard Foote 可能是 Oracle 索引内部结构的最高权威,他是这样说的:https://richardfoote.wordpress.com/2007/12/11/index-internals-rebuilding-the-truth/