Introdução
Será abordada a criação de uma tabela junto de operações dml nela, a fim de analisar o comportamento do segmento gerado e identificar algumas das estruturas físicas e lógicas de armazenamento. As observações acerca do segmento da tabela foram realizadas por meio da criação de recursos (tablespace e user) e objetos (tabela e procedure). As análises utilizaram recursos do banco de dados por meio de consultas em dynamic performance views v$, do comando “alter system dump datafile …” e das packages dbms_space.space_usage, dbms_rowid.rowid_relative_fno e dbms_rowid.rowid_block_number. As demonstrações serão realizadas em um banco de dados Oracle 19c.
Configurações iniciais – setup
As configurações iniciais consistem na criação de tablespace, de usuário e de objetos tabela e procedure, onde o usuário terá cota ilimitada na tablespace e será o owner desses objetos. A procedure será utilizada para inserir dados aleatórios na tabela, e a tablespace e a tabela serão analisadas ao longo de suas criações e das inserções de dados.
Observação: Se for de interesse realizar as configurações, configurá-las em um ambiente propício a testes, a fim de mitigar erros em ambientes críticos.
SQL> create tablespace tbs_user_test datafile size 1000m autoextend on next 100m;
Tablespace created.
SQL> create user user_test identified by verystrongpasswordhere default tablespace tbs_user_test quota unlimited on tbs_user_test;
User created.
SQL> grant create procedure to user_test;
Grant succeeded.
SQL> create table user_test.table01 (
id number generated by default as identity primary key,
value number(10, 2)
) tablespace tbs_user_test; 2 3 4
Table created.
SQL> create procedure user_test.proc_insert_rows_on_tablenn (
p_schema_name in varchar2,
p_table_name in varchar2,
p_quanity in number
)
as
v_sql varchar2(200);
begin
for i in 1..p_quanity loop
v_sql := 'insert into ' || p_schema_name || '.' || p_table_name || ' (value) ' || 'values (round(dbms_random.value(1, 10000), 2))';
execute immediate v_sql;
if mod(i, 10000) = 0 then
commit;
end if;
end loop;
commit;
end;
/ 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Procedure created.Alguns dos comandos utilizados nas próximas sessões envolvem a utilização de scripts, os quais podem ser encontrados na página de scripts desse site. Tanto as configurações que foram realizadas, quanto as consultas/scripts, requerem alguns privilégios no ambiente de banco de dados.
Analisando o objeto e seu segmento
A tablespace foi inicializada em um ambiente que possui OMF e devido a isso, o nome e o caminho do seu arquivo datafile foram definidos automaticamente. Ela foi inicializada com um espaço alocado de 1000 MB, sendo que o espaço livre para utilização no datafile é de 999 MB, desse modo ficando 1 MB restrito a informações de uso interno. Os extents que serão criados nela terão blocos de dados de tamanho 8192 bytes, assumindo o tamanho correspondente ao bloco padrão do banco de dados, pois esse valor não foi definido durante a criação da tablespace.
SQL> ora_datafile_free_info.sql tbs_user_test
TABLESPACE_NAME FILE_ID RELATIVE_FNO FILE_NAME FREE_BYTES FREE_MB BLOCKS_QTY BLOCK_SIZE
------------------------------ ---------- ------------ ------------------------------------------------------------------------------------------------------------------------ ---------- ---------- ---------- ----------
TBS_USER_TEST 22 22 /u01/app/oracle/oradata/ORCL02/218863F8DE9306C0E065A3F680D6920C/datafile/o1_mf_tbs_user_n4roo5b0_.dbf 1047527424 999 127872 8192A tabela TABLE01 do owner USER_TEST encontra-se alocada na tablespace TBS_USER_TEST conforme especificado no seu comando de criação. Essa tabela não possui segmento associado visto que não houve a especificação das opções da cláusula de storage e que nenhum registro foi inserido nela, sendo essa a característica resultante de deferred segment creation (parametro deferred_segment_creation). Uma vez que a tabela não possui segmento, não há blocos de dados associados a ela e a sua utilização ainda não pode ser mensurada.
SQL> ora_segments_info.sql user_test table01
no rows selected
SQL> ora_extents_info.sql user_test table01
no rows selected
SQL> ora_table_info.sql user_test table01
OWNER TABLE_NAME TABLESPACE_NAME SEGMENT_CREATED LAST_ANALYZED INITIAL_EXTENT NEXT_EXTENT MIN_EXTENTS MAX_EXTENTS NUM_ROWS BLOCKS EMPTY_BLOCKS NUM_FREELIST_BLOCKS AVG_SPACE PCT_FREE TOTAL_BLOCKS_SIZE_MB TOTAL_ROWS_SIZE_MB AVG_FREE_SPACE_MB AVG_FREE_SPACE_PCT
-------------------- -------------------- --------------- --------------- ------------- -------------- ----------- ----------- ----------- ---------- ---------- ------------ ------------------- ---------- ---------- -------------------- ------------------ ----------------- ------------------
USER_TEST TABLE01 TBS_USER_TEST NO 10
SQL>
SQL> ora_table_space_usage.sql user_test table01 table
Number of blocks that are unformatted: 0
Number of blocks having at least 0 to 25% free space: 0
Number of blocks having at least 25 to 50% free space: 0
Number of blocks having at least 50 to 75% free space: 0
Number of blocks having at least 75 to 100% free space: 0
Number of full blocks: 0
Total number of bytes full in the segment: 0
PL/SQL procedure successfully completed.Comportamento do segmento ao inserir registro – parte 01 (blocks – extents – segments, space)
A procedure será utilizada para inserir 1 registro na tabela USER_TEST.TABLE01 e desse modo inicializar/criar o segmento dela. Após inserir o registro, a tabela ficou com o tamanho de 0,0625 MB em um extent composto por 8 data blocks (1*8*8192/1024/1024 = 0,0625 MB).
SQL> execute user_test.proc_insert_rows_on_tablenn('USER_TEST', 'TABLE01', 1);
PL/SQL procedure successfully completed.
SQL>
SQL> ora_segments_info.sql user_test table01
OWNER SEGMENT_NAME SEGMENT_TYPE SEGMENT_SUBTYPE TABLESPACE_NAME SIZE_MB BLOCKS EXTENTS HEADER_FILE HEADER_BLOCK RELATIVE_FNO
-------------------- -------------------------------- ------------------ --------------- --------------- ---------- ---------- ---------- ----------- ------------ ------------
USER_TEST TABLE01 TABLE ASSM TBS_USER_TEST .0625 8 1 22 130 22
SQL>
SQL> ora_extents_info.sql user_test table01
OWNER SEGMENT_NAME PARTITION_NAME SEGMENT_TYPE TABLESPACE_NAME EXTENT_ID FILE_ID BLOCK_ID BYTES BLOCKS RELATIVE_FNO
--------------- -------------------------------- -------------------- ------------------ -------------------------------- ---------- ---------- ---------- ---------- ---------- ------------
USER_TEST TABLE01 TABLE TBS_USER_TEST 0 22 128 65536 8 22
SQL>
SQL> ora_table_info.sql user_test table01
OWNER TABLE_NAME TABLESPACE_NAME SEGMENT_CREATED LAST_ANALYZED INITIAL_EXTENT NEXT_EXTENT MIN_EXTENTS MAX_EXTENTS NUM_ROWS BLOCKS EMPTY_BLOCKS NUM_FREELIST_BLOCKS AVG_SPACE PCT_FREE TOTAL_BLOCKS_SIZE_MB TOTAL_ROWS_SIZE_MB AVG_FREE_SPACE_MB AVG_FREE_SPACE_PCT
-------------------- -------------------- --------------- --------------- ------------- -------------- ----------- ----------- ----------- ---------- ---------- ------------ ------------------- ---------- ---------- -------------------- ------------------ ----------------- ------------------
USER_TEST TABLE01 TBS_USER_TEST NO 10Alguns dados podem ser atualizados na consulta executada acima (ora_table_info.sql) ao coletar as estatísticas da tabela. Inicialmente ao coletar as estatísticas da tabela com a procedure dbms_stats.gather_table_stats, observa-se que a coluna empty_blocks fica com valor igual a 0 e a coluna blocks com valor igual a 5, e a soma desses valores é diferente de 8, o que não é igual ao número de blocos (8) do extent da tabela. Uma maneira de atualizar esse campo é a execução do comando “analyze table xxx.yyy compute statistics”, entretanto ele pode gerar valores diferentes da procedure dbms_stats.gather_table_stats para os demais campos, então após executar o analyze, rodei novamente a procedure.
OBS: Coletar as estatísticas de uma tabela, preferencialmente, e se possível somente, com o comando dbms_stats.gather_table_stats, não empregando o "analyze table xxx.yyy compute statistics", lembrando de coletar em casos que realmente necessitem.
SQL> exec dbms_stats.gather_table_stats('USER_TEST','TABLE01',cascade=>true);
PL/SQL procedure successfully completed.
SQL>
SQL> ora_table_info.sql user_test table01
OWNER TABLE_NAME TABLESPACE_NAME SEGMENT_CREATED LAST_ANALYZED INITIAL_EXTENT NEXT_EXTENT MIN_EXTENTS MAX_EXTENTS NUM_ROWS BLOCKS EMPTY_BLOCKS NUM_FREELIST_BLOCKS AVG_SPACE PCT_FREE TOTAL_BLOCKS_SIZE_MB TOTAL_ROWS_SIZE_MB AVG_FREE_SPACE_MB AVG_FREE_SPACE_PCT
-------------------- -------------------- --------------- --------------- ------------- -------------- ----------- ----------- ----------- ---------- ---------- ------------ ------------------- ---------- ---------- -------------------- ------------------ ----------------- ------------------
USER_TEST TABLE01 TBS_USER_TEST YES 13-JUN-25 65536 1048576 1 2147483645 1 5 0 0 0 10 .04 0 .04 100
SQL>
SQL> analyze table user_test.table01 compute statistics;
Table analyzed.
SQL>
SQL> ora_table_info.sql user_test table01
OWNER TABLE_NAME TABLESPACE_NAME SEGMENT_CREATED LAST_ANALYZED INITIAL_EXTENT NEXT_EXTENT MIN_EXTENTS MAX_EXTENTS NUM_ROWS BLOCKS EMPTY_BLOCKS NUM_FREELIST_BLOCKS AVG_SPACE PCT_FREE TOTAL_BLOCKS_SIZE_MB TOTAL_ROWS_SIZE_MB AVG_FREE_SPACE_MB AVG_FREE_SPACE_PCT
-------------------- -------------------- --------------- --------------- ------------- -------------- ----------- ----------- ----------- ---------- ---------- ------------ ------------------- ---------- ---------- -------------------- ------------------ ----------------- ------------------
USER_TEST TABLE01 TBS_USER_TEST YES 13-JUN-25 65536 1048576 1 2147483645 1 5 3 0 8071 10 .04 0 .04 100
SQL> exec dbms_stats.gather_table_stats('USER_TEST','TABLE01',cascade=>true);
PL/SQL procedure successfully completed.Após atualizar as estatísticas da tabela, o resultado do comando “ora_table_info.sql” terá os seus valores atualizados uma vez que a view dba_tables que ele consulta também teve alguns valores atualizados. Na tabela, os blocks continuam igual a 5 e os empty blocks igual a 3, totalizando 8 blocos associados ao extent da tabela.
SQL> ora_table_info.sql user_test table01
OWNER TABLE_NAME TABLESPACE_NAME SEGMENT_CREATED LAST_ANALYZED INITIAL_EXTENT NEXT_EXTENT MIN_EXTENTS MAX_EXTENTS NUM_ROWS BLOCKS EMPTY_BLOCKS NUM_FREELIST_BLOCKS AVG_SPACE PCT_FREE TOTAL_BLOCKS_SIZE_MB TOTAL_ROWS_SIZE_MB AVG_FREE_SPACE_MB AVG_FREE_SPACE_PCT
-------------------- -------------------- --------------- --------------- ------------- -------------- ----------- ----------- ----------- ---------- ---------- ------------ ------------------- ---------- ---------- -------------------- ------------------ ----------------- ------------------
USER_TEST TABLE01 TBS_USER_TEST YES 13-JUN-25 65536 1048576 1 2147483645 1 5 3 0 8071 10 .04 0 .04 100A tabela possui 1 registro e o comando “ora_table_space_usage.sql” teve um resultado diferente daquele obtido na sua execução prévia, ao indicar que 5 blocos possuem espaço livre entre 75% e 100%.
SQL> ora_table_space_usage.sql user_test table01 table
Number of blocks that are unformatted: 0
Number of blocks having at least 0 to 25% free space: 0
Number of blocks having at least 25 to 50% free space: 0
Number of blocks having at least 50 to 75% free space: 0
Number of blocks having at least 75 to 100% free space: 5
Number of full blocks: 0
Total number of bytes full in the segment: 0
PL/SQL procedure successfully completed.Identificando algumas das estruturas físicas e lógicas
No banco de dados Oracle há estruturas físicas e lógicas para armazenar e acessar os seus dados, as quais podem ser visualizadas na imagem abaixo retirada da documentação da Oracle. Fazendo uma associação da imagem com a tabela criada, tem-se:

Para o caso da tabela USER_TEST.TABLE01 na tablespace TBS_USER_TST, tem-se:
-Data file da tablespace: Teve o seu nome e caminho definidos pelo OMF e está armazenado diretamente no filesystem, sem a utilização de Oracle ASM. Nesse caso ele é o arquivo “/u01/app/oracle/oradata/ORCL02/218863F8DE9306C0E065A3F680D6920C/datafile/o1_mf_tbs_user_n4roo5b0_.dbf”.
-Tablespace associada a tabela: Ela é a TBS_USER_TEST e foi declarada no comando de criação da tabela, e caso não tivesse sido especificada, teria assumido o valor da tablespace default do usuário owner do objeto.
-Segmento da tabela: Possui o mesmo nome da tabela e nesse caso foi iniciado por meio de deferred segment creation ao inserir 1 registro na tabela.
-Extent do segmento da tabela: Foi iniciado em decorrencia do deferred segment creation ao inserir 1 registro na tabela.
-Oracle data block: Para a tablespace associada a tabela USER_TEST.TABLE01 ele assume o valor de 8192 bytes, correspondente ao valor padrão do data block desse banco de dados. Os extents atuais e futuros dessa tabela serão compostos por múltiplos data blocks desse tamanho.
SQL> ora_datafile_free_info.sql tbs_user_test
TABLESPACE_NAME FILE_ID RELATIVE_FNO FILE_NAME FREE_BYTES FREE_MB BLOCKS_QTY BLOCK_SIZE
------------------------------ ---------- ------------ ------------------------------------------------------------------------------------------------------------------------ ---------- ---------- ---------- ----------
TBS_USER_TEST 22 22 /u01/app/oracle/oradata/ORCL02/218863F8DE9306C0E065A3F680D6920C/datafile/o1_mf_tbs_user_n4roo5b0_.dbf 1047527424 999 127872 8192
SQL>
SQL> !ls -l /u01/app/oracle/oradata/ORCL02/218863F8DE9306C0E065A3F680D6920C/datafile/o1_mf_tbs_user_n4roo5b0_.dbf
-rw-r-----. 1 oracle oinstall 1048584192 Jun 13 18:49 /u01/app/oracle/oradata/ORCL02/218863F8DE9306C0E065A3F680D6920C/datafile/o1_mf_tbs_user_n4roo5b0_.dbf
SQL>
SQL> ora_segments_info.sql user_test table01
OWNER SEGMENT_NAME SEGMENT_TYPE SEGMENT_SUBTYPE TABLESPACE_NAME SIZE_MB BLOCKS EXTENTS HEADER_FILE HEADER_BLOCK RELATIVE_FNO
-------------------- -------------------------------- ------------------ --------------- --------------- ---------- ---------- ---------- ----------- ------------ ------------
USER_TEST TABLE01 TABLE ASSM TBS_USER_TEST .0625 8 1 22 130 22
SQL>
SQL> ora_extents_info.sql user_test table01
OWNER SEGMENT_NAME PARTITION_NAME SEGMENT_TYPE TABLESPACE_NAME EXTENT_ID FILE_ID BLOCK_ID BYTES BLOCKS RELATIVE_FNO
--------------- -------------------------------- -------------------- ------------------ -------------------------------- ---------- ---------- ---------- ---------- ---------- ------------
USER_TEST TABLE01 TABLE TBS_USER_TEST 0 22 128 65536 8 22Avaliando o segmento a partir de um dump de datafile blocks
É possível gerar um dump de blocos de um datafile. Para a tabela TABLE01, como há apenas 8 blocos associados a tabela, todos eles serão avaliados, mesmo que resumidamente. O bloco inicial utilizado foi o 128, obtido através do comando “ora_extents_info.sql”, e o bloco final utilizado foi o 135, visto que há 8 blocos no extent dessa tabela. Por padrão, o dump gerado ficará salvo no arquivo padrão de trace, o qual será consultado um pouco mais adiante.
SQL> ora_segments_info.sql user_test table01
OWNER SEGMENT_NAME SEGMENT_TYPE SEGMENT_SUBTYPE TABLESPACE_NAME SIZE_MB BLOCKS EXTENTS HEADER_FILE HEADER_BLOCK RELATIVE_FNO
-------------------- -------------------------------- ------------------ --------------- ------------------------------ ---------- ---------- ---------- ----------- ------------ ------------
USER_TEST TABLE01 TABLE ASSM TBS_USER_TEST .0625 8 1 22 130 22
SQL>
SQL> ora_extents_info.sql user_test table01
OWNER SEGMENT_NAME PARTITION_NAME SEGMENT_TYPE TABLESPACE_NAME EXTENT_ID FILE_ID BLOCK_ID BYTES BLOCKS RELATIVE_FNO
--------------- -------------------------------- -------------------- ------------------ -------------------------------- ---------- ---------- ---------- ---------- ---------- ------------
USER_TEST TABLE01 TABLE TBS_USER_TEST 0 22 128 65536 8 22
SQL>
SQL> alter system dump datafile 22 block min 128 block max 135;
System altered.
SQL>
SQL> select value from v$diag_info vdi where name='Default Trace File';
VALUE
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/u01/app/oracle/diag/rdbms/orcl02/orcl02/trace/orcl02_ora_6142.trcAntes de efetivamente analisar o dump dos blocos do datafile, há um modo de identificar onde estão contidos os registros da tabela. Por meio da package dbms_rowid e de alguns de seus sub programas, é possível verificar em qual datafile e bloco de dados o registro se encontra. Para a tabela em questão, o seu único registro encontra-se no bloco 133 do datafile 22.
SQL> select dbms_rowid.rowid_relative_fno(rowid) as "relative_fno"
,dbms_rowid.rowid_block_number(rowid) as "block_number"
,count(*) as "rows_qty"
from user_test.table01
group by dbms_rowid.rowid_relative_fno(rowid)
,dbms_rowid.rowid_block_number(rowid)
order by dbms_rowid.rowid_relative_fno(rowid)
,dbms_rowid.rowid_block_number(rowid); 2 3 4 5 6 7 8
relative_fno block_number rows_qty
------------ ------------ ----------
22 133 1No comando “ora_segments_info.sql” o bloco do segment header é o 130, e sabe-se que o bloco inicial é o 128 e que o registro da tabela está no bloco 133, e para melhorar entender essa estrutura, será avaliado o dump gerado. Aplicando um filtro textual no dump dos blocos do datafile, pode ser visto o padrão (22/1[0-9][0-9]) que aponta para determinado bloco, por exemplo, o bloco 128 do datafile 22 está represtando como (22/128) e possui class 8. Além da identificação do número do bloco, há a característica de sua classe, e para esse caso temos blocos com as classes 1,4,8 e 9. Não consigo encontrar uma definição clara para esses blocos, mas ao consultar a view v$waitstat e criar uma “presudo coluna” de id, é possível correlacionar a classe ao número, o que parece ser reazoável com a estrutura dos blocos em segmentos de gerenciamento ASSM (automatic segment space management).
SQL> !cat /u01/app/oracle/diag/rdbms/orcl02/orcl02/trace/orcl02_ora_6142.trc | grep ^BH
BH (0x10bf9f378) file#: 22 rdba: 0x05800080 (22/128) class: 8 ba: 0x10b73a000
BH (0x10bf74538) file#: 22 rdba: 0x05800081 (22/129) class: 9 ba: 0x10b36a000
BH (0x10bff8130) file#: 22 rdba: 0x05800082 (22/130) class: 4 ba: 0x10bf20000
BH (0x10bfc47b8) file#: 22 rdba: 0x05800083 (22/131) class: 1 ba: 0x10ba8a000
BH (0x10bfeeef0) file#: 22 rdba: 0x05800084 (22/132) class: 1 ba: 0x10be50000
BH (0x10bf6b190) file#: 22 rdba: 0x05800085 (22/133) class: 1 ba: 0x10b298000
BH (0x10bf96138) file#: 22 rdba: 0x05800086 (22/134) class: 1 ba: 0x10b66a000
BH (0x10bfc4650) file#: 22 rdba: 0x05800087 (22/135) class: 1 ba: 0x10ba88000
SQL> select rownum as "PSEUDO_ID", vw.class from v$waitstat vw;
PSEUDO_ID CLASS
---------- ------------------
1 data block
2 sort block
3 save undo block
4 segment header
5 save undo header
6 free list
7 extent map
8 1st level bmb
9 2nd level bmb
10 3rd level bmb
11 bitmap block
12 bitmap index block
13 file header block
14 unused
15 system undo header
16 system undo block
17 undo header
18 undo block
18 rows selected.O segmento da tabela possui segment_subtype assm, ou seja, o seu gerenciamento é do tipo automatico (automatic segment space management) que é o padrão definido para as tablespaces locally_managed. Esse gerenciamento é realizado por meio de bitmap blocks e espera-se encontrá-los, além da presença do segment header e dos data blocks.
Juntando as informações da tabela USER_TEST.TABLE01, tem-se que o extent associado a ela possui 8 data blocks, dos quais os dois primeiros (22/128 class 8 e 22/129 class 9) são, respectivamente, o “1st level bmb” e o “2nd lvl bmb” (bitmap blocks), o terceiro (22/130 class 4) é o segment header e do quarto ao oitavo blocos (22/130 ao 22/135 – todos class 1) estão presentes os data blocks.
Comportamento do segmento ao inserir registros – parte 02 (blocks – extents – segments, space)
Será feita uma inserção de 100000 registros na tabela para avaliar o comportamento do seu segmento. Após a inserção e a coleta de estatísitcas, cabe destacar que:
- O espaço disponível no datafile reduziu de 999 MB para 995 MB, visto que a tabela e seu índice (primary key) cresceram;
- O segmentou da tabela aumentou de 1 extent para 17 extents;
- O tamanho da tabela aumentou de 0,0625 MB para 2 MB, sendo que o seu segmento passou de 8 blocos para 256 blocos, e os blocos vazios, que antes eram 3, agora são 12, ou seja, 244 blocos estão em uso (256-12);
- Foram preenchidos mais blocos. O primeiro bloco com dados é o 131, sendo que antes era o 133, e o bloco mais distante com dados é o 511;
- Estima-se que 204 blocos estejam totalmente cheios, que 1 bloco tenha espaço livre de 0% a 25% e que 39 blocos tenham espaço livre de 75% a 100%.
SQL> execute user_test.proc_insert_rows_on_tablenn('USER_TEST', 'TABLE01', 100000);
PL/SQL procedure successfully completed.
SQL>
SQL> analyze table user_test.table01 compute statistics;
Table analyzed.
SQL>
SQL> exec dbms_stats.gather_table_stats('USER_TEST','TABLE01',cascade=>true);
PL/SQL procedure successfully completed.
SQL>
SQL> ora_datafile_free_info.sql tbs_user_test
TABLESPACE_NAME FILE_ID RELATIVE_FNO FILE_NAME FREE_BYTES FREE_MB BLOCKS_QTY BLOCK_SIZE
-------------------------------- ---------- ------------ ------------------------------------------------------------------------------------------------------------------------ ---------- ---------- ---------- ----------
TBS_USER_TEST 22 22 /u01/app/oracle/oradata/ORCL02/218863F8DE9306C0E065A3F680D6920C/datafile/o1_mf_tbs_user_n4roo5b0_.dbf 1043333120 995 127360 8192
SQL>
SQL> ora_segments_info.sql user_test table01
OWNER SEGMENT_NAME SEGMENT_TYPE SEGMENT_SUBTYPE TABLESPACE_NAME SIZE_MB BLOCKS EXTENTS HEADER_FILE HEADER_BLOCK RELATIVE_FNO
-------------------- -------------------------------- ------------------ --------------- -------------------------------- ---------- ---------- ---------- ----------- ------------ ------------
USER_TEST TABLE01 TABLE ASSM TBS_USER_TEST 2 256 17 22 130 22
SQL>
SQL> ora_extents_info.sql user_test table01
OWNER SEGMENT_NAME PARTITION_NAME SEGMENT_TYPE TABLESPACE_NAME EXTENT_ID FILE_ID BLOCK_ID BYTES BLOCKS RELATIVE_FNO
--------------- -------------------------------- -------------------- ------------------ -------------------------------- ---------- ---------- ---------- ---------- ---------- ------------
USER_TEST TABLE01 TABLE TBS_USER_TEST 0 22 128 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 1 22 152 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 2 22 168 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 3 22 184 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 4 22 200 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 5 22 216 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 6 22 232 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 7 22 248 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 8 22 264 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 9 22 280 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 10 22 296 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 11 22 312 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 12 22 328 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 13 22 344 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 14 22 352 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 15 22 368 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 16 22 384 1048576 128 22
17 rows selected.
SQL>
SQL> ora_table_info.sql user_test table01
OWNER TABLE_NAME TABLESPACE_NAME SEGMENT_CREATED LAST_ANALYZED INITIAL_EXTENT NEXT_EXTENT MIN_EXTENTS MAX_EXTENTS NUM_ROWS BLOCKS EMPTY_BLOCKS NUM_FREELIST_BLOCKS AVG_SPACE PCT_FREE TOTAL_BLOCKS_SIZE_MB TOTAL_ROWS_SIZE_MB AVG_FREE_SPACE_MB AVG_FREE_SPACE_PCT
-------------------- -------------------- --------------- --------------- ------------- -------------- ----------- ----------- ----------- ---------- ---------- ------------ ------------------- ---------- ---------- -------------------- ------------------ ----------------- ------------------
USER_TEST TABLE01 TBS_USER_TEST YES 13-JUN-25 65536 1048576 1 2147483645 100001 244 12 0 1977 10 1.91 .95 .95 49.7382199
SQL>
SQL> ora_table_space_usage.sql user_test table01 table
Number of blocks that are unformatted: 0
Number of blocks having at least 0 to 25% free space: 1
Number of blocks having at least 25 to 50% free space: 0
Number of blocks having at least 50 to 75% free space: 0
Number of blocks having at least 75 to 100% free space: 39
Number of full blocks: 204
Total number of bytes full in the segment: 1671168
PL/SQL procedure successfully completed.
SQL>
SQL> select dbms_rowid.rowid_relative_fno(rowid) as "relative_fno"
,dbms_rowid.rowid_block_number(rowid) as "block_number"
,count(*) as "rows_qty"
from user_test.table01
group by dbms_rowid.rowid_relative_fno(rowid)
,dbms_rowid.rowid_block_number(rowid)
order by dbms_rowid.rowid_relative_fno(rowid)
,dbms_rowid.rowid_block_number(rowid); 2 3 4 5 6 7 8
relative_fno block_number rows_qty
------------ ------------ ----------
22 131 519
22 132 520
22 133 526
22 134 520
22 135 520
...
22 507 485
22 508 485
22 509 485
22 510 485
22 511 485
205 rows selected.Removendo registros da tabela e observando o seu segmento
Será feita a exclusão de registros da tabela para avaliar a estrutura do segmento dela após isso. Nesse caso foram deletados os registros de id par, reduzindo a tabela de 100001 para 50000 registros. A remoção poderia ter sido realizada de outra forma, em lotes com quantias menores de registros, visando realizar commits menores, mas como o ambiente é controlado, optou-se por remover os registros e realizar o commit em uma única vez. Após remover os registros observa-se que:
- O datafile continuou com 995 MB de espaço livre, pois o espaço ocupado pelos registros deletados segue disponível para uso, não sendo considerado como espaço vazio. Operações futuras na tabela poderão utilizar esses blocos alocados e não vazios;
- O segmento continua com 17 extents e 256 blocos, dos quais continuam 244 blocos em uso e 12 blocos vazios;
- A grande diferença está na utilização dos blocos, onde 204 blocos possuem de 25% a 50% de espaço livre, 1 bloco com espaço livre de 50% a 75% e 39 blocos com espaço livre de 75% a 100%.
SQL> delete from user_test.table01 where mod(id, 2) = 1;
50001 rows deleted.
SQL>
SQL> commit;
Commit complete.
SQL>
SQL> analyze table user_test.table01 compute statistics;
Table analyzed.
SQL>
SQL> exec dbms_stats.gather_table_stats('USER_TEST','TABLE01',cascade=>true);
PL/SQL procedure successfully completed.
SQL>
SQL> ora_datafile_free_info.sql tbs_user_test
TABLESPACE_NAME FILE_ID RELATIVE_FNO FILE_NAME FREE_BYTES FREE_MB BLOCKS_QTY BLOCK_SIZE
--------------- ---------- ------------ ------------------------------------------------------------------------------------------------------------------------ ---------- ---------- ---------- ----------
TBS_USER_TEST 22 22 /u01/app/oracle/oradata/ORCL02/218863F8DE9306C0E065A3F680D6920C/datafile/o1_mf_tbs_user_n4roo5b0_.dbf 1043333120 995 127360 8192
SQL>
SQL> ora_segments_info.sql user_test table01
OWNER SEGMENT_NAME SEGMENT_TYPE SEGMENT_SUBTYPE TABLESPACE_NAME SIZE_MB BLOCKS EXTENTS HEADER_FILE HEADER_BLOCK RELATIVE_FNO
-------------------- -------------------------------- ------------------ --------------- --------------- ---------- ---------- ---------- ----------- ------------ ------------
USER_TEST TABLE01 TABLE ASSM TBS_USER_TEST 2 256 17 22 130 22
SQL>
SQL> ora_extents_info.sql user_test table01
OWNER SEGMENT_NAME PARTITION_NAME SEGMENT_TYPE TABLESPACE_NAME EXTENT_ID FILE_ID BLOCK_ID BYTES BLOCKS RELATIVE_FNO
--------------- -------------------------------- -------------------- ------------------ -------------------------------- ---------- ---------- ---------- ---------- ---------- ------------
USER_TEST TABLE01 TABLE TBS_USER_TEST 0 22 128 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 1 22 152 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 2 22 168 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 3 22 184 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 4 22 200 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 5 22 216 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 6 22 232 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 7 22 248 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 8 22 264 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 9 22 280 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 10 22 296 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 11 22 312 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 12 22 328 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 13 22 344 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 14 22 352 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 15 22 368 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 16 22 384 1048576 128 22
17 rows selected.
SQL>
SQL> ora_table_info.sql user_test table01
OWNER TABLE_NAME TABLESPACE_NAME SEGMENT_CREATED LAST_ANALYZED INITIAL_EXTENT NEXT_EXTENT MIN_EXTENTS MAX_EXTENTS NUM_ROWS BLOCKS EMPTY_BLOCKS NUM_FREELIST_BLOCKS AVG_SPACE PCT_FREE TOTAL_BLOCKS_SIZE_MB TOTAL_ROWS_SIZE_MB AVG_FREE_SPACE_MB AVG_FREE_SPACE_PCT
-------------------- -------------------- --------------- --------------- ------------- -------------- ----------- ----------- ----------- ---------- ---------- ------------ ------------------- ---------- ---------- -------------------- ------------------ ----------------- ------------------
USER_TEST TABLE01 TBS_USER_TEST YES 13-JUN-25 65536 1048576 1 2147483645 50000 244 12 0 4616 10 1.91 .48 1.43 74.8691099
SQL>
SQL> ora_table_space_usage.sql user_test table01 table
Number of blocks that are unformatted: 0
Number of blocks having at least 0 to 25% free space: 0
Number of blocks having at least 25 to 50% free space: 204
Number of blocks having at least 50 to 75% free space: 1
Number of blocks having at least 75 to 100% free space: 39
Number of full blocks: 0
Total number of bytes full in the segment: 0
PL/SQL procedure successfully completed.Liberando espaço na tabela
Há alguns modos de liberar espaço na tabela, e nesse caso optou-se por exemplificar 1 deles e avaliar o resultado, lembrando que os métodos devem ser avaliados com relação aos impactos e requisitos.
Será realizado o move da tabela, o que irá resultar na realocação dos seus dados em um novo segmento. Esse comando pode ser realizado de modo online caso essa feature esteja disponível no banco de dados, e caso não esteja disponível, a operação irá gerar locks no objeto (indisponibilizando-o temporariamente), além de ter que realizar uma etapa adicional para rebuildar índices da tabela caso existam e se a opção online não estiver disponível/não for utilizada.
Após realizar o move da tabela observa-se o seguinte:
- O espaço livre no datafile aumento de 995 MB para 997.1875 MB, pois foi gerado um novo segmento para a tabela, o qual ocupa o espaço necessário para os dados existentes, não trazendo os blocos alocados e disponíveis para operações futuras que existiam após o delete;
- Percebe-se que o segment header do novo segmento da tabela encontra-se no bloco 658, sendo que antes ele ocupava o bloco 130;
- O segmento da tabela reduziu de 256 blocos para 112 blocos e nenhum deles encontra-se vazio. Os blocos estão contidos em 14 extents e antes estavam distribuídos em 17 extents;
- A estimativa de tamanho dos blocos da tabela reduziu de 1,91 MB para 0,88 MB.
SQL> ora_table_index_status_info.sql user_test table01
OWNER INDEX_NAME STATUS TABLE_OWNER TABLE_NAME
-------------------- -------------------------------- -------- -------------------- --------------------------------
USER_TEST SYS_C007849 VALID USER_TEST TABLE01
SQL>
SQL> alter table user_test.table01 move online;
Table altered.
SQL>
SQL> ora_table_index_status_info.sql user_test table01
OWNER INDEX_NAME STATUS TABLE_OWNER TABLE_NAME
-------------------- -------------------------------- -------- -------------------- --------------------------------
USER_TEST SYS_C007849 VALID USER_TEST TABLE01
SQL>
SQL> analyze table user_test.table01 compute statistics;
Table analyzed.
SQL>
SQL> exec dbms_stats.gather_table_stats('USER_TEST','TABLE01',cascade=>true);
PL/SQL procedure successfully completed.
SQL>
SQL> ora_datafile_free_info.sql tbs_user_test
TABLESPACE_NAME FILE_ID RELATIVE_FNO FILE_NAME FREE_BYTES FREE_MB BLOCKS_QTY BLOCK_SIZE
------------------------------ ---------- ------------ ------------------------------------------------------------------------------------------------------------------------ ---------- ---------- ---------- ----------
TBS_USER_TEST 22 22 /u01/app/oracle/oradata/ORCL02/218863F8DE9306C0E065A3F680D6920C/datafile/o1_mf_tbs_user_n4roo5b0_.dbf 1045626880 997.1875 127640 8192
SQL>
SQL> ora_segments_info.sql user_test table01
OWNER SEGMENT_NAME SEGMENT_TYPE SEGMENT_SUBTYPE TABLESPACE_NAME SIZE_MB BLOCKS EXTENTS HEADER_FILE HEADER_BLOCK RELATIVE_FNO
-------------------- -------------------------------- ------------------ --------------- ------------------------------ ---------- ---------- ---------- ----------- ------------ ------------
USER_TEST TABLE01 TABLE ASSM TBS_USER_TEST .875 112 14 22 658 22
SQL>
SQL> ora_extents_info.sql user_test table01
OWNER SEGMENT_NAME PARTITION_NAME SEGMENT_TYPE TABLESPACE_NAME EXTENT_ID FILE_ID BLOCK_ID BYTES BLOCKS RELATIVE_FNO
--------------- -------------------------------- -------------------- ------------------ -------------------------------- ---------- ---------- ---------- ---------- ---------- ------------
USER_TEST TABLE01 TABLE TBS_USER_TEST 0 22 656 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 1 22 672 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 2 22 696 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 3 22 720 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 4 22 744 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 5 22 760 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 6 22 784 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 7 22 808 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 8 22 832 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 9 22 848 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 10 22 856 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 11 22 864 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 12 22 872 65536 8 22
USER_TEST TABLE01 TABLE TBS_USER_TEST 13 22 880 65536 8 22
14 rows selected.
SQL>
SQL> ora_table_info.sql user_test table01
OWNER TABLE_NAME TABLESPACE_NAME SEGMENT_CREATED LAST_ANALYZED INITIAL_EXTENT NEXT_EXTENT MIN_EXTENTS MAX_EXTENTS NUM_ROWS BLOCKS EMPTY_BLOCKS NUM_FREELIST_BLOCKS AVG_SPACE PCT_FREE TOTAL_BLOCKS_SIZE_MB TOTAL_ROWS_SIZE_MB AVG_FREE_SPACE_MB AVG_FREE_SPACE_PCT
-------------------- -------------------- --------------- --------------- ------------- -------------- ----------- ----------- ----------- ---------- ---------- ------------ ------------------- ---------- ---------- -------------------- ------------------ ----------------- ------------------
USER_TEST TABLE01 TBS_USER_TEST YES 13-JUN-25 65536 1048576 1 2147483645 50000 112 0 0 833 10 .88 .48 .4 45.4545455
SQL>
SQL> ora_table_space_usage.sql user_test table01 table
Number of blocks that are unformatted: 0
Number of blocks having at least 0 to 25% free space: 0
Number of blocks having at least 25 to 50% free space: 0
Number of blocks having at least 50 to 75% free space: 0
Number of blocks having at least 75 to 100% free space: 0
Number of full blocks: 103
Total number of bytes full in the segment: 843776
PL/SQL procedure successfully completed.
SQL>
SQL> select dbms_rowid.rowid_relative_fno(rowid) as "relative_fno"
,dbms_rowid.rowid_block_number(rowid) as "block_number"
,count(*) as "rows_qty"
from user_test.table01
group by dbms_rowid.rowid_relative_fno(rowid)
,dbms_rowid.rowid_block_number(rowid)
order by dbms_rowid.rowid_relative_fno(rowid)
,dbms_rowid.rowid_block_number(rowid); 2 3 4 5 6 7 8
relative_fno block_number rows_qty
------------ ------------ ----------
22 659 518
22 660 521
22 661 517
22 662 518
22 663 518
22 672 518
22 673 517
22 674 504
22 675 517
22 676 518
22 677 485
22 678 483
22 679 483
22 697 483
22 698 483
22 699 483
...
22 877 483
22 878 483
22 879 483
22 880 483
22 881 483
22 882 483
22 883 483
22 884 483
22 885 483
22 886 483
22 887 393
103 rows selected.Realizando truncate na tabela e observando sua estrutura
O truncate da tabela seguiu o padrão de drop storage, o qual mantém o tamanho de min_extents da tabela, nesse caso 1 extent que resulta em 0,0625 MB (1*8192/1024/1024), e desaloca o espaço que estava ocupado pelos registros removidos.
SQL> truncate table user_test.table01;
Table truncated.
SQL>
SQL> analyze table user_test.table01 compute statistics;
Table analyzed.
SQL>
SQL> exec dbms_stats.gather_table_stats('USER_TEST','TABLE01',cascade=>true);
PL/SQL procedure successfully completed.
SQL>
SQL> ora_datafile_free_info.sql tbs_user_test
TABLESPACE_NAME FILE_ID RELATIVE_FNO FILE_NAME FREE_BYTES FREE_MB BLOCKS_QTY BLOCK_SIZE
--------------- ---------- ------------ ------------------------------------------------------------------------------------------------------------------------ ---------- ---------- ---------- ----------
TBS_USER_TEST 22 22 /u01/app/oracle/oradata/ORCL02/218863F8DE9306C0E065A3F680D6920C/datafile/o1_mf_tbs_user_n4roo5b0_.dbf 1047396352 998.875 127856 8192
SQL>
SQL> ora_segments_info.sql user_test table01
OWNER SEGMENT_NAME SEGMENT_TYPE SEGMENT_SUBTYPE TABLESPACE_NAME SIZE_MB BLOCKS EXTENTS HEADER_FILE HEADER_BLOCK RELATIVE_FNO
-------------------- -------------------------------- ------------------ --------------- --------------- ---------- ---------- ---------- ----------- ------------ ------------
USER_TEST TABLE01 TABLE ASSM TBS_USER_TEST .0625 8 1 22 658 22
SQL>
SQL> ora_extents_info.sql user_test table01
OWNER SEGMENT_NAME PARTITION_NAME SEGMENT_TYPE TABLESPACE_NAME EXTENT_ID FILE_ID BLOCK_ID BYTES BLOCKS RELATIVE_FNO
--------------- -------------------------------- -------------------- ------------------ -------------------------------- ---------- ---------- ---------- ---------- ---------- ------------
USER_TEST TABLE01 TABLE TBS_USER_TEST 0 22 656 65536 8 22
SQL>
SQL> ora_table_info.sql user_test table01
OWNER TABLE_NAME TABLESPACE_NAME SEGMENT_CREATED LAST_ANALYZED INITIAL_EXTENT NEXT_EXTENT MIN_EXTENTS MAX_EXTENTS NUM_ROWS BLOCKS EMPTY_BLOCKS NUM_FREELIST_BLOCKS AVG_SPACE PCT_FREE TOTAL_BLOCKS_SIZE_MB TOTAL_ROWS_SIZE_MB AVG_FREE_SPACE_MB AVG_FREE_SPACE_PCT
-------------------- -------------------- --------------- --------------- ------------- -------------- ----------- ----------- ----------- ---------- ---------- ------------ ------------------- ---------- ---------- -------------------- ------------------ ----------------- ------------------
USER_TEST TABLE01 TBS_USER_TEST YES 13-JUN-25 65536 1048576 1 2147483645 0 0 8 0 0 10 0 0 0
SQL>
SQL> ora_table_space_usage.sql user_test table01 table
Number of blocks that are unformatted: 0
Number of blocks having at least 0 to 25% free space: 0
Number of blocks having at least 25 to 50% free space: 0
Number of blocks having at least 50 to 75% free space: 0
Number of blocks having at least 75 to 100% free space: 0
Number of full blocks: 0
Total number of bytes full in the segment: 0
PL/SQL procedure successfully completed.Removendo os objetos e recursos criados
Por fim, os objetos e recursos criados foram removidos para deixar o ambiente organizado. Destaca-se que ao realizar o drop com purge da tabela, o datafile voltou a ter o espaço disponível de 999 MB, e posteriormente a tablespace, o usuário e os objetos dele foram removidos.
SQL> drop table user_test.table01 purge;
Table dropped.
SQL>
SQL> ora_datafile_free_info.sql tbs_user_test
TABLESPACE_NAME FILE_ID RELATIVE_FNO FILE_NAME FREE_BYTES FREE_MB BLOCKS_QTY BLOCK_SIZE
--------------- ---------- ------------ ------------------------------------------------------------------------------------------------------------------------ ---------- ---------- ---------- ----------
TBS_USER_TEST 22 22 /u01/app/oracle/oradata/ORCL02/218863F8DE9306C0E065A3F680D6920C/datafile/o1_mf_tbs_user_n4roo5b0_.dbf 1047527424 999 127872 8192
SQL>
SQL> drop tablespace TBS_USER_TEST;
Tablespace dropped.
SQL>
SQL> drop user user_test cascade;
User dropped.
SQL>Considerações
Foi observado um caso generalista de uma tabela simples para avaliar o comportamento do seu segmento conforme as operações forem ocorrendo. É importante levar em consideração que há muitas variáveis que podem influenciar em diferentes resultados a exemplo do tipo e da estrutura da tabela (quantidade de colunas e tipos de data types delas), do tamanho ocupado pelo registro em decorrência da estrutura da tabela e dos dados armazenados, do tipo de gerenciamento da tablespace e do segmento, dentre outras. Lembrando que em casos de teste, fazer em ambientes controlados para não ter impactos negativos em ambientes relevantes.