Files
oracle/csierra/cs_tbs_resize.sql
2026-03-12 21:23:47 +01:00

536 lines
17 KiB
SQL

----------------------------------------------------------------------------------------
--
-- File name: cs_tbs_resize.sql
--
-- Purpose: Tablespace Resize
--
-- Author: Rodrigo Righetti
--
-- Version: 2020/12/09
--
-- Usage: Execute connected to CDB or PDB.
--
--
-- Example: $ sqlplus / as sysdba
-- SQL> @cs_tbs_resize.sql TBSNAME 10
--
-- This execution would increase the maxsize for Tablespace TBSNAME in 10%.
--
-- Notes: Developed and tested on 12.1.0.2 and 19c.
--
---------------------------------------------------------------------------------------
--
--
DEF permanent = 'Y';
DEF undo = 'Y';
DEF temporary = 'Y';
-- order_by: [{pdb_name, tablespace_name}|max_size_gb DESC|allocated_gb DESC|used_gb DESC|free_gb DESC]
DEF order_by = 'pdb_name, tablespace_name';
DEF rows = '999';
--
@@cs_internal/cs_primary.sql
@@cs_internal/cs_cdb_warn.sql
@@cs_internal/cs_set.sql
@@cs_internal/cs_def.sql
@@cs_internal/cs_file_prefix.sql
--
DEF cs_script_name = 'cs_tbs_resize';
--
COL tablespace_name FOR A30;
SELECT tablespace_name
FROM dba_tablespaces;
PRO
--
PRO 1. Tablespace to resize:
DEF tbs_name = '&1.';
UNDEF 1;
--
SELECT '&&cs_file_prefix._&&cs_script_name.' cs_file_name FROM DUAL;
--
@@cs_internal/cs_spool_head.sql
PRO SQL> @&&cs_script_name..sql "&&tbs_name."
@@cs_internal/cs_spool_id.sql
--
--
CLEAR BREAK COMPUTE;
BREAK ON REPORT;
COMPUTE SUM LABEL 'TOTAL' OF allocated_gb used_gb free_gb max_size_gb ON REPORT;
--
COL pdb_name FOR A30;
COL tablespace_name FOR A30;
COL allocated_gb FOR 999,990.000 HEA 'ALLOCATED|SPACE (GB)';
COL used_gb FOR 999,990.000 HEA 'USED|SPACE (GB)';
COL used_percent FOR 990.0 HEA 'USED|PERC';
COL free_gb FOR 999,990.000 HEA 'FREE|SPACE (GB)';
COL free_percent FOR 990.0 HEA 'FREE|PERC';
COL max_size_gb FOR 999,990.000 HEA 'MAX|SIZE (GB)';
COL met_used_space_GB FOR 999,990.000 HEA 'METRICS|USED|SPACE (GB)';
COL met_used_percent FOR 990.0 HEA 'METRICS|USED|PERC';
--
WITH
t AS (
SELECT /*+ MATERIALIZE NO_MERGE */
con_id,
tablespace_name,
SUM(NVL(bytes, 0)) bytes
FROM cdb_data_files
WHERE con_id=&&cs_con_id.
GROUP BY
con_id,
tablespace_name
UNION ALL
SELECT /*+ MATERIALIZE NO_MERGE */
con_id,
tablespace_name,
SUM(NVL(bytes, 0)) bytes
FROM cdb_temp_files
WHERE con_id=&&cs_con_id.
GROUP BY
con_id,
tablespace_name
),
u AS (
SELECT /*+ MATERIALIZE NO_MERGE */
con_id,
tablespace_name,
SUM(bytes) bytes
FROM cdb_free_space
WHERE con_id=&&cs_con_id.
GROUP BY
con_id,
tablespace_name
UNION ALL
SELECT /*+ MATERIALIZE NO_MERGE */
con_id,
tablespace_name,
NVL(SUM(bytes_used), 0) bytes
FROM gv$temp_extent_pool
WHERE con_id=&&cs_con_id.
GROUP BY
con_id,
tablespace_name
),
un AS (
SELECT /*+ MATERIALIZE NO_MERGE */
ts.con_id,
ts.tablespace_name,
NVL(um.used_space * ts.block_size, 0) bytes
FROM cdb_tablespaces ts,
cdb_tablespace_usage_metrics um
WHERE ts.contents = 'UNDO'
AND um.tablespace_name(+) = ts.tablespace_name
AND um.con_id(+) = ts.con_id
),
oem AS (
SELECT /*+ MATERIALIZE NO_MERGE */
ts.con_id,
pdb.name pdb_name,
ts.tablespace_name,
ts.contents,
ts.bigfile,
ts.block_size,
NVL(t.bytes, 0) allocated_space_bytes,
NVL(
CASE ts.contents
WHEN 'UNDO' THEN un.bytes
WHEN 'PERMANENT' THEN t.bytes - NVL(u.bytes, 0)
WHEN 'TEMPORARY' THEN
CASE ts.extent_management
WHEN 'LOCAL' THEN u.bytes
WHEN 'DICTIONARY' THEN t.bytes - NVL(u.bytes, 0)
END
END
, 0) used_space_bytes
FROM cdb_tablespaces ts,
v$containers pdb,
t,
u,
un
WHERE 1 = 1
AND t.tablespace_name = upper('&&tbs_name.')
AND pdb.con_id = ts.con_id
AND t.tablespace_name(+) = ts.tablespace_name
AND t.con_id(+) = ts.con_id
AND u.tablespace_name(+) = ts.tablespace_name
AND u.con_id(+) = ts.con_id
AND un.tablespace_name(+) = ts.tablespace_name
AND un.con_id(+) = ts.con_id
),
tablespaces AS (
SELECT o.pdb_name,
o.tablespace_name,
o.contents,
o.bigfile,
ROUND(m.maxbytes / POWER(10, 9), 3) AS max_size_gb,
ROUND(o.allocated_space_bytes / POWER(10, 9), 3) AS allocated_gb,
ROUND(o.used_space_bytes / POWER(10, 9), 3) AS used_gb,
ROUND((o.allocated_space_bytes - o.used_space_bytes) / POWER(10, 9), 3) AS free_gb,
ROUND(100 * o.used_space_bytes / o.allocated_space_bytes, 3) AS used_percent, -- as per allocated space
ROUND(100 * (o.allocated_space_bytes - o.used_space_bytes) / o.allocated_space_bytes, 3) AS free_percent -- as per allocated space
FROM oem o,
(SELECT con_id, tablespace_name, sum(maxbytes) maxbytes
FROM cdb_data_files
WHERE con_id = &&cs_con_id.
GROUP BY con_id, tablespace_name
UNION
SELECT con_id, tablespace_name, sum(maxbytes) maxbytes
FROM cdb_temp_files
WHERE con_id = &&cs_con_id.
GROUP BY con_id, tablespace_name
) m
WHERE m.tablespace_name(+) = o.tablespace_name
AND m.con_id(+) = o.con_id
)
SELECT pdb_name,
tablespace_name,
contents,
bigfile,
'|' AS "|",
max_size_gb,
allocated_gb,
used_gb,
free_gb,
used_percent,
free_percent
FROM tablespaces
ORDER BY
&&order_by.
FETCH FIRST &&rows. ROWS ONLY
/
--
--
@@cs_internal/&&cs_set_container_to_cdb_root.
--
COL p_u02 NEW_V p_u02 FOR 99999999;
--
PRO
PRO OS SPACE AVAILABLE - FREE GB U02
-- OS space available
SELECT round(U02_AVAILABLE/power(2,20)) p_u02
FROM C##IOD.dbc_system
WHERE TIMESTAMP= (select max(TIMESTAMP) from C##IOD.dbc_system);
--
PRO
--
@@cs_internal/&&cs_set_container_to_curr_pdb.
--
SET SERVEROUTPUT ON
BEGIN
DBMS_OUTPUT.put_line('-----------------------------------------------------------------------------------------');
DBMS_OUTPUT.put_line('Max permissible increase must be between 1% and 20%, different values will default to 10%');
DBMS_OUTPUT.put_line('-----------------------------------------------------------------------------------------');
DBMS_OUTPUT.put_line('Increments are always rounded up "ceil", small files always added with 1G and maxsize 32G');
DBMS_OUTPUT.put_line('-----------------------------------------------------------------------------------------');
END;
/
PRO
PRO 2. What percentange to increase the TBS maxsize {[10]|1-20}?:
DEF perc_increase = '&2.';
UNDEF 2;
--
COL p_perc_increase NEW_V p_perc_increase NOPRI;
SELECT CASE WHEN &&perc_increase. BETWEEN 1 AND 20 THEN &&perc_increase. ELSE 10 END AS p_perc_increase FROM DUAL
/
--
SET SERVEROUTPUT ON
--
DECLARE
l_u02_avail NUMBER := &&p_u02.;
l_perc_increase NUMBER := (&&p_perc_increase./100)+1;
l_statement CLOB;
l_newmax NUMBER;
l_bytes NUMBER;
l_maxbytes NUMBER;
l_nfiles NUMBER;
l_smmaxfix NUMBER;
l_addfilesc NUMBER;
l_counter NUMBER := 1;
l_temp VARCHAR2(10) := ' DATAFILE ';
BEGIN
IF upper('&&tbs_name.') like 'TEMP%' THEN
SELECT round(sum(bytes)/power(2,30)) bytes_gb , round(sum(maxbytes)/power(2,30)) maxbytes_gb, count(*) numfiles
INTO l_bytes, l_maxbytes, l_nfiles
FROM dba_temp_files
WHERE tablespace_name = upper('&&tbs_name.');
l_temp := ' TEMPFILE ';
ELSE
SELECT round(sum(bytes)/power(2,30)) bytes_gb , round(sum(maxbytes)/power(2,30)) maxbytes_gb, count(*) numfiles
INTO l_bytes, l_maxbytes, l_nfiles
FROM dba_data_files
WHERE tablespace_name = upper('&&tbs_name.');
END IF;
FOR i IN (SELECT tablespace_name, bigfile
FROM dba_tablespaces
WHERE tablespace_name = upper('&&tbs_name.') ) LOOP
IF i.bigfile = 'YES' THEN
FOR j IN (SELECT file_id, autoextensible, (bytes/power(2,30)) bytes_gb, (maxbytes/power(2,30)) maxbytes_gb
FROM dba_data_files
WHERE tablespace_name = upper('&&tbs_name.')
) LOOP
IF j.maxbytes_gb <= j.bytes_gb THEN
l_newmax := ceil(j.bytes_gb * l_perc_increase);
ELSIF j.maxbytes_gb < (j.maxbytes_gb*l_perc_increase) THEN
l_newmax := ceil(j.maxbytes_gb * l_perc_increase);
ELSIF j.maxbytes_gb >= (j.maxbytes_gb*l_perc_increase) THEN
DBMS_OUTPUT.put_line( 'Maxsize already has over '||l_perc_increase||'% increase requested.');
RETURN;
END IF;
IF l_newmax = 0 THEN
l_newmax := 1;
DBMS_OUTPUT.put_line('Tablespace too small, minimal adjustment is 1G:');
END IF;
IF (l_newmax - j.bytes_gb) >= (l_u02_avail*.7) THEN
DBMS_OUTPUT.put_line('Your new Maxsize request is over 70% of the available /u02 free space !!!');
RETURN;
END IF;
DBMS_OUTPUT.put_line('-------------------------------------------------------------------------------------');
l_statement := 'ALTER DATABASE DATAFILE '||j.file_id||' AUTOEXTEND ON NEXT 1G MAXSIZE '||l_newmax||'G';
DBMS_OUTPUT.put_line(l_statement);
execute immediate l_statement;
END LOOP;
ELSE
-- small file support
-- if all datafiles already at max 32 gb, then add datafile, else fix Maxsize and add datafile if needed
-- Small files always increamented in 32gb files maxsize
-- fix max size of current datafiles
IF l_maxbytes > l_bytes THEN
l_newmax := ceil((l_maxbytes*l_perc_increase)-l_maxbytes);
ELSE
l_newmax := ceil((l_bytes*l_perc_increase)-l_bytes);
END IF;
IF (l_newmax - l_bytes) >= (l_u02_avail*.7) THEN
DBMS_OUTPUT.put_line( 'Your new Maxsize request is over 70% of the available /u02 free space !!!');
RETURN;
END IF;
FOR j IN (SELECT file_id, autoextensible, (bytes/power(2,30)) bytes_gb, (maxbytes/power(2,30)) maxbytes_gb, (maxbytes/power(2,30))-(bytes/power(2,30)) free_gb
FROM dba_data_files
WHERE tablespace_name = upper('&&tbs_name.')
AND round(maxbytes/power(2,30)) < 32
UNION
SELECT file_id, autoextensible, (bytes/power(2,30)) bytes_gb, (maxbytes/power(2,30)) maxbytes_gb, (maxbytes/power(2,30))-(bytes/power(2,30)) free_gb
FROM dba_temp_files
WHERE tablespace_name = upper('&&tbs_name.')
AND round(maxbytes/power(2,30)) < 32
ORDER by file_id) LOOP
l_statement := 'ALTER DATABASE '||l_temp||' '||j.file_id||' AUTOEXTEND ON NEXT 1G MAXSIZE UNLIMITED';
DBMS_OUTPUT.put_line(l_statement);
execute immediate l_statement;
END LOOP;
SELECT max(maxbytes_gb)
INTO l_smmaxfix
FROM (
SELECT sum(maxbytes)/power(2,30) maxbytes_gb
FROM dba_data_files
WHERE tablespace_name = upper('&&tbs_name.')
UNION
SELECT sum(maxbytes)/power(2,30) maxbytes_gb
FROM dba_temp_files
WHERE tablespace_name = upper('&&tbs_name.')
)
;
DBMS_OUTPUT.put_line('-------------------------------------------------------------------------------------');
IF l_smmaxfix >= l_maxbytes+l_newmax THEN
DBMS_OUTPUT.PUT_LINE('SmallFile Tablespace maxsize increased to: '||round(l_smmaxfix,2)||'G, no need to add more datafiles');
ELSE
DBMS_OUTPUT.PUT_LINE( 'Smallfile tablespaces are added with 1G autoexted and Maxsize of 32G.');
l_newmax := ceil((l_smmaxfix*l_perc_increase)-l_smmaxfix);
IF (l_newmax - l_bytes) >= (l_u02_avail*.7) THEN
DBMS_OUTPUT.PUT_LINE( 'Your new Maxsize request is over 70% of the available /u02 free space !!!');
RETURN;
END IF;
l_addfilesc := ceil(l_newmax/32);
WHILE l_counter <= l_addfilesc
LOOP
l_statement := 'ALTER TABLESPACE '||i.tablespace_name||' ADD '||l_temp||' SIZE 1G AUTOEXTEND ON NEXT 1G MAXSIZE UNLIMITED';
DBMS_OUTPUT.put_line(l_statement);
execute immediate l_statement;
l_counter := l_counter + 1;
END LOOP;
END IF;
END IF;
END LOOP;
END;
/
PRO -------------------
PRO
PRO New Tablespace Size
PRO -------------------
WITH
t AS (
SELECT /*+ MATERIALIZE NO_MERGE */
con_id,
tablespace_name,
SUM(NVL(bytes, 0)) bytes
FROM cdb_data_files
WHERE con_id=&&cs_con_id.
GROUP BY
con_id,
tablespace_name
UNION ALL
SELECT /*+ MATERIALIZE NO_MERGE */
con_id,
tablespace_name,
SUM(NVL(bytes, 0)) bytes
FROM cdb_temp_files
WHERE con_id=&&cs_con_id.
GROUP BY
con_id,
tablespace_name
),
u AS (
SELECT /*+ MATERIALIZE NO_MERGE */
con_id,
tablespace_name,
SUM(bytes) bytes
FROM cdb_free_space
WHERE con_id=&&cs_con_id.
GROUP BY
con_id,
tablespace_name
UNION ALL
SELECT /*+ MATERIALIZE NO_MERGE */
con_id,
tablespace_name,
NVL(SUM(bytes_used), 0) bytes
FROM gv$temp_extent_pool
WHERE con_id=&&cs_con_id.
GROUP BY
con_id,
tablespace_name
),
un AS (
SELECT /*+ MATERIALIZE NO_MERGE */
ts.con_id,
ts.tablespace_name,
NVL(um.used_space * ts.block_size, 0) bytes
FROM cdb_tablespaces ts,
cdb_tablespace_usage_metrics um
WHERE ts.contents = 'UNDO'
AND um.tablespace_name(+) = ts.tablespace_name
AND um.con_id(+) = ts.con_id
),
oem AS (
SELECT /*+ MATERIALIZE NO_MERGE */
ts.con_id,
pdb.name pdb_name,
ts.tablespace_name,
ts.contents,
ts.bigfile,
ts.block_size,
NVL(t.bytes, 0) allocated_space_bytes,
NVL(
CASE ts.contents
WHEN 'UNDO' THEN un.bytes
WHEN 'PERMANENT' THEN t.bytes - NVL(u.bytes, 0)
WHEN 'TEMPORARY' THEN
CASE ts.extent_management
WHEN 'LOCAL' THEN u.bytes
WHEN 'DICTIONARY' THEN t.bytes - NVL(u.bytes, 0)
END
END
, 0) used_space_bytes
FROM cdb_tablespaces ts,
v$containers pdb,
t,
u,
un
WHERE 1 = 1
AND t.tablespace_name = upper('&&tbs_name.')
AND pdb.con_id = ts.con_id
AND t.tablespace_name(+) = ts.tablespace_name
AND t.con_id(+) = ts.con_id
AND u.tablespace_name(+) = ts.tablespace_name
AND u.con_id(+) = ts.con_id
AND un.tablespace_name(+) = ts.tablespace_name
AND un.con_id(+) = ts.con_id
),
tablespaces AS (
SELECT o.pdb_name,
o.tablespace_name,
o.contents,
o.bigfile,
ROUND(m.maxbytes / POWER(10, 9), 3) AS max_size_gb,
ROUND(o.allocated_space_bytes / POWER(10, 9), 3) AS allocated_gb,
ROUND(o.used_space_bytes / POWER(10, 9), 3) AS used_gb,
ROUND((o.allocated_space_bytes - o.used_space_bytes) / POWER(10, 9), 3) AS free_gb,
ROUND(100 * o.used_space_bytes / o.allocated_space_bytes, 3) AS used_percent, -- as per allocated space
ROUND(100 * (o.allocated_space_bytes - o.used_space_bytes) / o.allocated_space_bytes, 3) AS free_percent -- as per allocated space
FROM oem o,
(SELECT con_id, tablespace_name, sum(maxbytes) maxbytes
FROM cdb_data_files
WHERE con_id = &&cs_con_id.
GROUP BY con_id, tablespace_name
UNION
SELECT con_id, tablespace_name, sum(maxbytes) maxbytes
FROM cdb_temp_files
WHERE con_id = &&cs_con_id.
GROUP BY con_id, tablespace_name
) m
WHERE m.tablespace_name(+) = o.tablespace_name
AND m.con_id(+) = o.con_id
)
SELECT pdb_name,
tablespace_name,
contents,
bigfile,
'|' AS "|",
max_size_gb,
allocated_gb,
used_gb,
free_gb,
used_percent,
free_percent
FROM tablespaces
ORDER BY
&&order_by.
FETCH FIRST &&rows. ROWS ONLY
/
CLEAR BREAK COMPUTE;
--
PRO
PRO SQL> @&&cs_script_name..sql "&&tbs_name." "&&perc_increase."
--
@@cs_internal/cs_spool_tail.sql
@@cs_internal/cs_undef.sql
@@cs_internal/cs_reset.sql
--