简化/自动的数据文件可用磁盘空间回收


8

在Oracle 11g版本上:

谷歌搜索之后,我找不到删除表后回收可用空间的简单方法。

我已经找到了很多解释,说明数据文件是如何碎片化的,为了将“空空间”移动到数据文件末尾(逐表...,即使当您有200张桌子!?)

然后,您必须通过“猜测”可以减少的数据量来减少数据文件的大小,或者您必须确切地知道“块大小”是什么...最后,您不应该忘记“重建索引”。

参见例如:http : //asktom.oracle.com/pls/asktom/f?p=100 :11:0 ::::P11_QUESTION_ID : 54178027703899

http://www.oracle-base.com/articles/misc/ReclaimingUnusedSpace.php

是否有一个简单的PL / SQL过程,在给定表空间名称或数据文件名称的情况下,该过程会完成该工作?还是任何类似的Oracle工具?


有趣的信息:检查表空间是“本地管理”还是“目录管理”。前者似乎可以更好地处理“碎片整理”数据文件。请参阅:orafaq.com/node/3
Frosty Z

Answers:


5

简短的答案是“ 否”。不幸的是,在Oracle中执行此操作的方法确实需要“大量无聊的查询”。您链接到的文章是有关该主题的一些最佳信息。数据文件的确确实是零散的,因此即使在最大段之下仍存在可用空间,a结束后Oracle也不会自动合并它RESIZE

要对表空间进行“碎片整理”,您需要将这些段移动到数据文件的开头而不是结尾。对于表来说,这是一个脱机过程,这意味着在进行移动时表将不可用。索引可以脱机移动,也可以通过Enterprise Edition联机移动。由于您有停机窗口,因此建议您按照以下步骤操作。

A.缩小数据文件,使可用空间超出高水位线。可以按以下步骤完成(查询类似于Frosty Z的过程):

SELECT ceil( blocks*(a.BlockSize)/1024/1024) "Current Size",
   ceil( (nvl(hwm,1)*(a.BlockSize))/1024/1024 ) "Smallest Poss.",
   ceil( blocks*(a.BlockSize)/1024/1024) -
   ceil( (nvl(hwm,1)*(a.BlockSize))/1024/1024 ) "Savings",
   'alter database datafile '''|| file_name || ''' resize ' || 
      ceil((nvl(hwm,1)*(a.BlockSize))/1024/1024/100)*100  || 'm;' "Command"
FROM (SELECT a.*, p.value BlockSize FROM dba_data_files a 
JOIN v$parameter p ON p.Name='db_block_size') a
LEFT JOIN (SELECT file_id, max(block_id+blocks-1) hwm FROM dba_extents GROUP BY file_id ) b
ON a.file_id = b.file_id
WHERE ceil( blocks*(a.BlockSize)/1024/1024) - ceil( (nvl(hwm,1)*(a.BlockSize))/1024/1024 ) 
   > 100 /* Minimum MB it must shrink by to be considered. */
ORDER BY "Savings" Desc;

B.在将内容缩小到高水位线之后,找出移动表段仍将受益的表空间。

SELECT DISTINCT tablespace_name FROM
(      
    SELECT tablespace_name, block_id + blocks LastBlock,
       lead(block_id) OVER (PARTITION BY File_ID 
          ORDER BY tablespace_name, file_id, block_id) NextBlock
       FROM dba_free_space 
) WHERE LastBlock <> NextBlock AND NextBlock IS NOT NULL;

C.对于每个这些表空间,确定需要移动哪些段。(将USERS替换为表空间的名称,或将其与上一个查询合并)

SELECT distinct de.segment_name
FROM dba_extents de
JOIN
(
   SELECT tablespace_name, file_id, MIN(block_id) LowestFreeBlock
   FROM dba_free_space
   WHERE tablespace_name = 'USERS'
  GROUP BY tablespace_name, file_id
) dfs ON dfs.tablespace_name = de.tablespace_name AND dfs.file_id = de.file_id
WHERE de.tablespace_name = 'USERS'
AND de.block_id > dfs.LowestFreeBlock;

D.移动每个表并重建索引和统计信息。

E.重复步骤A。

我只是构建了大多数这些查询,因此您将需要在使用前对其进行彻底的测试。我想您可以创建一个过程,该过程将用于EXECUTE IMMEDIATE创建实际语句以动态运行,但是由于查询将收到ORA-08103:移动过程中对象不再存在,所以我认为最好是手动控制该过程如果确实需要更多时间/精力。


3

受此页面启发的部分解决方案:

它不会重新组织可用空间,但会自动检测数据文件末尾的可用空间并打印出正确的“ RESIZE”命令。

DECLARE
    BLKSIZE INTEGER;

BEGIN
    SELECT VALUE INTO BLKSIZE FROM V$PARAMETER WHERE NAME = 'db_block_size';

    FOR INDEX_ROW IN (
      SELECT 'ALTER DATABASE DATAFILE ''' || FILE_NAME || ''' RESIZE ' || CEIL( (NVL(HWM,1)*BLKSIZE)/1024/1024 ) || 'M;' SHRINK_DATAFILES FROM DBA_DATA_FILES DBADF,
            (SELECT FILE_ID, MAX(BLOCK_ID+BLOCKS-1) HWM FROM DBA_EXTENTS GROUP BY FILE_ID ) DBAFS
            WHERE DBADF.FILE_ID = DBAFS.FILE_ID(+) AND CEIL(BLOCKS*BLKSIZE/1024/1024)- CEIL((NVL(HWM,1)* BLKSIZE)/1024/1024 ) > 0
    ) LOOP
        DBMS_OUTPUT.PUT_LINE(INDEX_ROW.SHRINK_DATAFILES);
    END LOOP;
END;

2

在尝试完全收缩数据文件之前,请问自己:是否会在不久的将来在关联的表空间内再次创建新的段?如果是,则缩水没有意义。该空间将被重新用于您的新细分市场,并且保持原样,可以节省您自己和系统的大量工作。


2

谷歌浏览了几天后,我找到了最简单明了的示例,在删除后回收表空间中的可用空间。我希望这有帮助

链接:http//www.dbforums.com/oracle/976248-how-reduce-tablespaces-used-space-after-delete-records-2.html

解:

ALTER TABLE MOVE demo

让我们创建一个表,其中包含9999行,每行大小约为1k:

SQL> create table t (x char(1000) default 'x' primary key);
Table created.
SQL> insert /*+ append nologging */ into t(x) select rownum from all_objects where rownum < 10000;
9999 rows created.
SQL> commit;
Commit complete.

该表已分配给它29个扩展,总计1460万:

SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
29 14680064

让我们删除所有行:

SQL> delete from t;
9999 rows deleted.
SQL> commit;
Commit complete.

现在-“惊奇”-该表仍使用相同的扩展区:

SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
29 14680064

为什么呢 因为即使删除表的所有行,高水位线也不会降低-不会降低,以实现最大的并发性(Oracle一直非常重视最大化并发性,即性能和可伸缩性;这是其成功的主要原因在企业应用程序中)。

取消分配未使用的空间(= HWM上方的空间)无济于事(因为HWM上方没有大量未使用的空间):

SQL> alter table t deallocate unused;
Table altered.
SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
29 13959168

现在,让我们移动表,从本质上讲,这意味着克隆表(包括触发器,约束等),转移行,删除“旧”表并重命名新表-所有这些工作都是由内核完成的,因此超级安全即使在机器/服务器故障的情况下:

SQL> alter table t move;
Table altered.

现在,我们只分配了初始范围:

SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
1 65536

警告:通常,表上的许多/所有索引在移动后都是不可用的(不是这种情况,但我运行的是最新版本的9.2.0.4,它可能在表完全为空的情况下优化了流程):

SQL> col table_name form a30
SQL> col index_name form a30
SQL> set lines 123 
SQL> select table_name, index_name, status from user_indexes where table_name='T';

TABLE_NAME INDEX_NAME STATUS
------------------------------ ------------------------------ ------------------------
T SYS_C002573 VALID

如果状态不是有效的,则可以简单地手动重建索引:

SQL> alter index SYS_C002573 rebuild;
Index altered.

或者,您可以使整个过程自动化:

set serveroutput on size 100000
begin
for n in (select index_name from user_indexes where status <> 'VALID') loop
dbms_output.put_line ('rebuilding ' || n.index_name);
execute immediate 'alter index ' || n.index_name || ' rebuild';
end loop;
end;
/

例如,让我们手动将索引设置为UNUSABLE:

SQL> alter index SYS_C002573 unusable;
Index altered.

SQL> set serveroutput on size 100000
SQL> begin
2 for n in (select index_name from user_indexes where status <> 'VALID') loop
3 dbms_output.put_line ('rebuilding ' || n.index_name);
4 execute immediate 'alter index ' || n.index_name || ' rebuild';
5 end loop;
6 end;
7 /
rebuilding SYS_C002573

PL/SQL procedure successfully completed.

HTH Alberto


1

如前所述,您将必须移动该表空间中的所有200多个表以释放数据文件中的某些空间,然后调整大小以回收该空间。但是,不是运行所有这些查询,而是12c Enterprise Manager执行此任务。您将必须导航到Database Home> Storage> Tablespace。选择要使用的表空间,然后单击“重新组织”。它将提供一个选项来查看将要执行的SQL语句。您可以复制它们并自己运行,也可以在EM中安排工作。

它实际上创建了另一个表空间,将所有对象移动到新表空间,重建索引,并从旧表空间删除对象。

我有几个缺点可以想到。此操作应在非高峰时间完成,否则会出错,表明资源繁忙。数据文件(而非表空间)的名称将在末尾添加“ reorg”。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.