Quantcast
Channel: Thinking Out Loud
Viewing all articles
Browse latest Browse all 666

Moving Objects to Shrink Data Files

$
0
0

At a company I used to work for, I would frequently get asked, “There’s 200 GB free in the tablespace. Why can’t you just shrink it?”

First, the tablespace consists of many data files and there are objects at the end of the data file, preventing the shrink.

There’s probably over a dozen post out there about the subject matter; however, I believe this method is much simpler and will let you be the judge.

Find the data files to shrink, provide the size to shrink to, a list of tables will be provided to be moved.

After the move, rebuild all UNUSABLE indexes. Don’t forget, this is an offline operation.

Find data files for tablespace

SQL> set pages 10000
SQL> select tablespace_name, file_id, bytes/1048576 mb from dba_data_files
where tablespace_name = '&_tbs' order by 1,2 asc
;  2    3
Enter value for _tbs: USERS
old   2: where tablespace_name = '&_tbs' order by 1,2 asc
new   2: where tablespace_name = 'USERS' order by 1,2 asc

TABLESPACE_NAME                   FILE_ID         MB
------------------------------ ---------- ----------
USERS                                   4      23824
USERS                                   7      24576
USERS                                   8      23684
USERS                                   9      20480
USERS                                  10      20480
USERS                                  11      20450
USERS                                  12      20439
USERS                                  14      20353
USERS                                  15      20480
USERS                                  17      20480
USERS                                  19      20480
USERS                                  20      20480
USERS                                  21      20480
USERS                                  31      20453
USERS                                  34      20450
USERS                                  36      18315
USERS                                  39      20480
USERS                                  41      20467
USERS                                  43      20161
USERS                                  44      20353
USERS                                  48      20458
USERS                                  50      10240
USERS                                  51      10941
USERS                                  54      11003
USERS                                  57      10240
USERS                                  61      10193
USERS                                  62      10117
USERS                                  64      10240
USERS                                  66      10240
USERS                                  68      28449
USERS                                  69      10240
USERS                                  70      10178
USERS                                  71      10240
USERS                                  76      25000
USERS                                  83      24556
USERS                                  86      10218
USERS                                  87      13994
USERS                                  88       8721

38 rows selected.

Elapsed: 00:00:00.05

Identify file_id and final size

SQL> SET SERVEROUTPUT ON
SQL> DECLARE
  2       V_FILE_ID NUMBER;
  3       V_BLOCK_SIZE NUMBER;
  4       V_RESIZE_SIZE NUMBER;
  5  BEGIN
  6       V_FILE_ID := &_FILE_ID;
  7       V_RESIZE_SIZE := &_RESIZE_FILE_TO_MB;
  8
  9       SELECT BLOCK_SIZE INTO V_BLOCK_SIZE FROM V$DATAFILE WHERE FILE# = V_FILE_ID;
 10
 11       DBMS_OUTPUT.PUT_LINE('.');
 12       DBMS_OUTPUT.PUT_LINE('.');
 13       DBMS_OUTPUT.PUT_LINE('.');
 14       DBMS_OUTPUT.PUT_LINE('OBJECTS IN FILE '||V_FILE_ID||' THAT MUST MOVE IN ORDER TO RESIZE THE FILE TO '||V_RESIZE_SIZE||' MB');
 15       DBMS_OUTPUT.PUT_LINE('===================================================================');
 16       DBMS_OUTPUT.PUT_LINE('NON-PARTITIONED OBJECTS');
 17       DBMS_OUTPUT.PUT_LINE('===================================================================');
 18
 19       for my_record in (
 20            SELECT DISTINCT(OWNER||'.'||SEGMENT_NAME||' - OBJECT TYPE = '||SEGMENT_TYPE) ONAME
 21            FROM DBA_EXTENTS
 22            WHERE (block_id + blocks-1)*V_BLOCK_SIZE/1048576 > V_RESIZE_SIZE
 23            AND FILE_ID = V_FILE_ID
 24            AND SEGMENT_TYPE NOT LIKE '%PARTITION%'
 25            ORDER BY 1) LOOP
 26                 DBMS_OUTPUT.PUT_LINE(my_record.ONAME);
 27       END LOOP;
 28
 29       DBMS_OUTPUT.PUT_LINE('===================================================================');
 30       DBMS_OUTPUT.PUT_LINE('PARTITIONED OBJECTS');
 31       DBMS_OUTPUT.PUT_LINE('===================================================================');
 32
 33       for my_record in (
 34            SELECT DISTINCT(OWNER||'.'||SEGMENT_NAME||' - PARTITION = '||PARTITION_NAME||' - OBJECT TYPE = '||SEGMENT_TYPE) ONAME
 35            FROM DBA_EXTENTS
 36            WHERE (block_id + blocks-1)*V_BLOCK_SIZE/1048576 > V_RESIZE_SIZE
 37            AND FILE_ID = V_FILE_ID
 38            AND SEGMENT_TYPE LIKE '%PARTITION%'
 39            ORDER BY 1) LOOP
 40                 DBMS_OUTPUT.PUT_LINE(my_record.ONAME);
 41       END LOOP;
 42
 43  END;
 44  /
Enter value for _file_id: 83
old   6:      V_FILE_ID := &_FILE_ID;
new   6:      V_FILE_ID := 83;
Enter value for _resize_file_to_mb: 10240
old   7:      V_RESIZE_SIZE := &_RESIZE_FILE_TO_MB;
new   7:      V_RESIZE_SIZE := 10240;
.
.
.
OBJECTS IN FILE 83 THAT MUST MOVE IN ORDER TO RESIZE THE FILE TO 10240 MB
===================================================================
NON-PARTITIONED OBJECTS
===================================================================
SCHEMA.D_DATA - OBJECT TYPE = TABLE
SCHEMA.LOGIN_LOG - OBJECT TYPE = TABLE
SCHEMA.COMPANY - OBJECT TYPE = TABLE
SCHEMA.ORDER - OBJECT TYPE = TABLE
SCHEMA.FIELD - OBJECT TYPE = TABLE
SCHEMA.REQUEST - OBJECT TYPE = TABLE
SCHEMA.SENDER - OBJECT TYPE = TABLE
SCHEMA.SUMMARY - OBJECT TYPE = TABLE
SCHEMA.TERMINAL - OBJECT TYPE = TABLE
SCHEMA.ORG - OBJECT TYPE = TABLE
SCHEMA.SESSION_LOG - OBJECT TYPE = TABLE
SCHEMA.AGENT - OBJECT TYPE = TABLE
===================================================================
PARTITIONED OBJECTS
===================================================================

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.30
SQL>

When asked about how much space was saved, the answer is 24556-10240=14316 MB

Disclaimer, this has on been run; hence, the actual results is unknown.

SQL script and Reference:

– How to Resize a Datafile (Doc ID 1029252.6)

set pages 10000
select tablespace_name, file_id, bytes/1048576 mb from dba_data_files
where tablespace_name = '&_tbs' order by 1,2 asc
;

SET SERVEROUTPUT ON
DECLARE
V_FILE_ID NUMBER;
V_BLOCK_SIZE NUMBER;
V_RESIZE_SIZE NUMBER;
BEGIN
V_FILE_ID := &_FILE_ID;
V_RESIZE_SIZE := &_RESIZE_FILE_TO_MB;

SELECT BLOCK_SIZE INTO V_BLOCK_SIZE FROM V$DATAFILE WHERE FILE# = V_FILE_ID;

DBMS_OUTPUT.PUT_LINE(‘.’);
DBMS_OUTPUT.PUT_LINE(‘.’);
DBMS_OUTPUT.PUT_LINE(‘.’);
DBMS_OUTPUT.PUT_LINE(‘OBJECTS IN FILE ‘||V_FILE_ID||’ THAT MUST MOVE IN ORDER TO RESIZE THE FILE TO ‘||V_RESIZE_SIZE||’ MB’);
DBMS_OUTPUT.PUT_LINE(‘===================================================================’);
DBMS_OUTPUT.PUT_LINE(‘NON-PARTITIONED OBJECTS’);
DBMS_OUTPUT.PUT_LINE(‘===================================================================’);

for my_record in (
SELECT DISTINCT(OWNER||’.'||SEGMENT_NAME||’ – OBJECT TYPE = ‘||SEGMENT_TYPE) ONAME
FROM DBA_EXTENTS
WHERE (block_id + blocks-1)*V_BLOCK_SIZE/1048576 > V_RESIZE_SIZE
AND FILE_ID = V_FILE_ID
AND SEGMENT_TYPE NOT LIKE ‘%PARTITION%’
ORDER BY 1) LOOP
DBMS_OUTPUT.PUT_LINE(my_record.ONAME);
END LOOP;

DBMS_OUTPUT.PUT_LINE(‘===================================================================’);
DBMS_OUTPUT.PUT_LINE(‘PARTITIONED OBJECTS’);
DBMS_OUTPUT.PUT_LINE(‘===================================================================’);

for my_record in (
SELECT DISTINCT(OWNER||’.'||SEGMENT_NAME||’ – PARTITION = ‘||PARTITION_NAME||’ – OBJECT TYPE = ‘||SEGMENT_TYPE) ONAME
FROM DBA_EXTENTS
WHERE (block_id + blocks-1)*V_BLOCK_SIZE/1048576 > V_RESIZE_SIZE
AND FILE_ID = V_FILE_ID
AND SEGMENT_TYPE LIKE ‘%PARTITION%’
ORDER BY 1) LOOP
DBMS_OUTPUT.PUT_LINE(my_record.ONAME);
END LOOP;

END;
/



Viewing all articles
Browse latest Browse all 666

Trending Articles