【问题标题】:How to optimize this or do this without a loop in Oracle SQL如何在 Oracle SQL 中优化或在没有循环的情况下执行此操作
【发布时间】:2020-03-29 02:42:34
【问题描述】:

我有下面的代码,这个代码应该告诉我们给定表有多少数据块没有一行。我有 15 秒的时间限制,但是当我第一次运行它时,它需要 103 秒才能运行。我试图通过消除循环进行优化,但我做不到,我什至想不出没有循环的解决方案。

create or replace procedure num_of_rows IS
 cnt NUMBER;
 total NUMBER;
BEGIN 
 total := 0;
 FOR rec IN (select file_id, block_id, blocks from dba_extents 
             where owner='TABLE_OWNER' and segment_name='TABLE_NAME')
 LOOP
  FOR i in 1..rec.blocks LOOP
   SELECT count(*) into cnt FROM TABLE_OWNER.TABLE_NAME 
   WHERE dbms_rowid.rowid_relative_fno(ROWID) = rec.file_id
   AND dbms_rowid.rowid_block_number(ROWID) = rec.block_id+i-1;
   IF cnt = 0 THEN total := total + 1; END IF;
  END LOOP;
 END LOOP;
 dbms_output.put_line(total);
END num_of_rows;



set serveroutput on
execute num_of_rows();

能否请您告诉我可以优化的方法? 在此先感谢:)

【问题讨论】:

  • 我可以,但这不是您需要考虑的重点吗?

标签: sql database oracle plsql query-optimization


【解决方案1】:

这只扫描表一次,所以应该更快。

它通过为dba_extents 中的每一行生成一个虚拟行集来生成每个block_idcross apply 需要 Oracle 12.1),然后排除表中存在的块。

select count(*)
from   dba_extents x
       cross apply (select x.block_id + rownum - 1 as block_id from dual connect by rownum <= x.blocks) x2
where  owner = 'TABLE_OWNER'
and    segment_name = 'TABLE_NAME'
and    ( x.relative_fno, x2.block_id )
       not in
       ( select distinct dbms_rowid.rowid_relative_fno(rowid) as rowid_relative_fno
              , dbms_rowid.rowid_block_number(rowid) as rowid_block_number
         from  table_owner.table_name );

【讨论】:

    【解决方案2】:

    如果您可以使用动态 SQL,那就去吧。您可以通过将 2FORLOOP-2SELECT 重写为单个查询来实现,这将提高性能。

    【讨论】:

    • 欢迎来到 SO!请提供重写示例,以便 OP 和其他人可以看到您的意思。请参阅此处以供参考:stackoverflow.com/help/how-to-answer
    • 不幸的是我不能使用动态 sql
    猜你喜欢
    • 2015-02-12
    • 2016-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-16
    • 1970-01-01
    • 2013-06-08
    相关资源
    最近更新 更多