如何在 Oracle SQL 中优化或在没有循环的情况下执行此操作
Posted
技术标签:
【中文标题】如何在 Oracle SQL 中优化或在没有循环的情况下执行此操作【英文标题】:How to optimize this or do this without a loop in 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();
能否请您告诉我可以优化的方法? 在此先感谢:)
【问题讨论】:
我可以,但这不是您需要考虑的重点吗? 【参考方案1】:这只扫描表一次,所以应该更快。
它通过为dba_extents
中的每一行生成一个虚拟行集来生成每个block_id
(cross 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 和其他人可以看到您的意思。请参阅此处以供参考:***.com/help/how-to-answer 不幸的是我不能使用动态 sql以上是关于如何在 Oracle SQL 中优化或在没有循环的情况下执行此操作的主要内容,如果未能解决你的问题,请参考以下文章