web-dev-qa-db-ja.com

簡素化/自動化されたデータファイルの空きディスク領域の再利用

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ツール?

8
Frosty Z

短い答えはNoです。残念ながら、Oracleでこれを行うには、「退屈なクエリのビッグスタック」が必要です。あなたがリンクした記事は、その主題に関して入手可能な最良の情報の一部です。データファイルは実際に断片化されるため、最高のセグメントの下に空き領域が存在する場合でも、RESIZEが実行されても、Oracleはそれを自動的に統合しません。

テーブルスペースを「デフラグ」するには、これらのセグメントをデータファイルの最後ではなく、最初に移動する必要があります。テーブルの場合、これはオフラインプロセスであるため、移動中はテーブルを使用できません。インデックスはオフラインで移動することも、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を受け取るため、移動の進行中はオブジェクトが存在しないので、少し時間がかかる場合でも、そのプロセスを手動で制御します。

5
Leigh Riffel

このページ から発想を得た部分的なソリューション:

空き領域は再編成されませんが、データファイルの終わりで使用可能な空き領域が自動的に検出され、適切な「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;
3
Frosty Z

何日かグーグルをサーフィンした後、私は削除後にテーブルスペースの空きスペースを取り戻すための最もシンプルで明確な例を見つけました。これが役に立てば幸い

リンク: http://www.dbforums.com/Oracle/976248-how-reduce-tablespaces-used-space-after-delete-records-2.html

ソリューション:

ALTER TABLE MOVE demo

それぞれに約1kのサイズの9999行のテーブルを作成してみましょう。

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.

Now- "surprise"-テーブルは今でも同じエクステントを使用しています:

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

STATUSが有効でない場合は、手動でインデックスを再構築できます。

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アルベルト

2
vishal0108

データファイルをまったく縮小する前に、自問してみてください。遠くない将来、関連するテーブルスペース内に新しいセグメントを再び作成しますか?はいの場合、縮小しても意味がありません。スペースは新しいセグメントに再利用されるだけで、そのままにしておくことで、自分自身とシステムの労力を大幅に節約できます。

2
Uwe Hesse

前に述べたように、そのテーブルスペース内の200以上のテーブルをすべて移動して、データファイル内のスペースを解放し、サイズを変更してスペースを取り戻す必要があります。ただし、これらのクエリをすべて実行する代わりに、12c Enterprise Managerがこのタスクを実行します。 Database Home> Storage> Tablespaceに移動する必要があります。作業するテーブルスペースを選択し、[再編成]をクリックします。実行しようとしているSQLステートメントを表示するオプションが表示されます。それらのコピーを取得して自分で実行するか、EMでジョブをスケジュールできます。

実際には、別のテーブルスペースを作成し、すべてのオブジェクトを新しいテーブルスペースに移動し、インデックスを再構築して、古いテーブルスペースからオブジェクトを削除します。

考えられる欠点がいくつかあります。これはオフピーク時に行う必要があります。そうしないと、リソースがビジーであるというエラーメッセージが表示されます。データスペース(テーブルスペースではない)の最後に向かって、名前に「reorg」が追加されます。

1
Srikanthan