暂无图片
暂无图片
6
暂无图片
暂无图片
暂无图片

oracle查询数据文件的剩余空间或者查询表空间使用率慢的原因及解决方案

原创 szrsu 2024-08-07
1397

我们在查询数据文件的剩余空间或者查询表空间使用率时,可能会碰见查询很慢的情况,主要原因是在于查询表空间使用情况的时候,需要从dba_free_space视图中获取剩余空间大小。
如果该视图中对象过多,查询dba_free_space视图的效率特别低,就会造成查询缓慢的现象。有时候在系统运行很长一段时间后,我们再去查询表空间使用情况,发现相同的查询语句执行时间会变长,也是同样的原因造成的。

1、查看回收站的记录数

sys@orcl(2776)> select count(*) from dba_recyclebin; COUNT(*) ---------- 20000 已用时间: 00: 00: 00.08

当前回收站有20000条记录,我们看一下查询表空间使用,需要花多少时间?
image.png
image.png
上图可以看到,查询表空间花了27s左右。

2、查询缓慢的原因

我们看一下查询dba_free_space需要花多少时间:

select /*+ gather_plan_statistics */count(1) from dba_free_space;

image.png
查看dba_free_space记录数,要花31s左右。

官方这个文档 Queries on DBA_FREE_SPACE are Slow (文档 ID 271169.1) 有说明 dba_free_space 是个视图,基表中有:sys.recyclebin$,当回收站中内容过大,会拖慢对该视图的查询。

看下查询语句的执行计划,主要耗时在哪里?

set linesize 200 pagesize 999 select * from table(dbms_xplan.display_cursor(null,null,'advanced -PROJECTION -bytes iostats,last'));

image.png
上图可以看到,执行计划主要耗时是在16-24行。

3、解决方法

业务用户清理回收站:Purge the recyclebin.
For example:
SQL> purge recyclebin;
Recyclebin purged.
Or, as SYSDBA for system wide purging. --或sysdba用户清理全局回收站
SQL> purge dba_recyclebin;
Recyclebin purged.

--清空回收站 SQL> purge dba_recyclebin; DBA Recyclebin purged. SQL> select count(1) from dba_recyclebin; COUNT(1) ---------- 0

–清空回收站后,重新查询表空间使用情况,1s不到就查询出了。
image.png

–此时重新看下查询dba_free_space的执行计划

select /*+ gather_plan_statistics */count(1) from dba_free_space;
set linesize 200 pagesize 999
select * from table(dbms_xplan.display_cursor(null,null,'advanced -PROJECTION -bytes iostats,last'));

image.png

可以看到原先的耗时比较多的16-24行,现在耗时已经大大减少了。

注意:在ORACLE 12C中,各个PDB和CDB之间回收站是私有的,所以对每个PDB回收站进行单独的清空。

#查看CDB中回收站对象数量 SQL> select count(1) from dba_recyclebin; COUNT(1) ---------- 123 #清空回收站 SQL> purge dba_recyclebin; DBA Recyclebin purged. SQL> select count(1) from dba_recyclebin; COUNT(1) ---------- 0 #切换到PDB中再次查看 SQL> ALTER SESSION SET CONTAINER=ZHIXIN; Session altered. SQL> select count(1) from dba_recyclebin; COUNT(1) ---------- 91 PDB中的回收站对象是没有清空的,需要单独清理回收。 #清空回收站 SQL> purge dba_recyclebin; DBA Recyclebin purged. SQL> select count(1) from dba_recyclebin; COUNT(1) ---------- 0

每次都要手动清理比较麻烦,我们考虑定期去清理,创建一个job,当回收站记录达到500时,就开始清除7天前的记录。

–创建job调度过程实现自动化

create or replace procedure clear_recyclebin is recy_count number(9); time_drop varchar2(2000); query_str varchar2(1000); cursor c_drop_time is select owner,original_name from dba_recyclebin where droptime < to_char((sysdate - interval '7' day), 'yyyy-mm-dd hh24:mi:ss'); begin select count(1) into recy_count from dba_recyclebin; if recy_count >= 500 then for time_drop in c_drop_time loop query_str := 'purge table '||time_drop.owner||'.'||time_drop.original_name; execute immediate query_str; dbms_output.put_line(query_str); end loop; end if; end clear_recyclebin; declare v_count int:=0; begin select count(*) into v_count from user_scheduler_jobs where job_name=upper('clear_recyclebin_job'); if v_count>0 then dbms_scheduler.drop_job(upper('clear_recyclebin_job')); end if; dbms_scheduler.create_job( job_name=>'clear_recyclebin_job', job_type => 'STORED_PROCEDURE', job_action=>'CLEAR_RECYCLEBIN', start_date => sysdate, repeat_interval=>'FREQ=MINUTELY;INTERVAL=1', enabled=>true); end;

–创建定时job

declare v_count int:=0; begin select count(*) into v_count from user_scheduler_jobs where job_name=upper('clear_recyclebin_job'); if v_count>0 then dbms_scheduler.drop_job(upper('clear_recyclebin_job')); end if; dbms_scheduler.create_job( job_name=>'clear_recyclebin_job', job_type => 'STORED_PROCEDURE', job_action=>'CLEAR_RECYCLEBIN', start_date => sysdate, repeat_interval=>'Freq=Daily;Interval=1', enabled=>true); end;
最后修改时间:2024-08-08 10:15:38
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论