Advanced Index Compression - Oracle Database 12c R1

Olá pessoal,

Um novo tipo de compressão de índice chamado Advanced Index Compression, disponível a partir do Oracle Database 12c Release 1 (12.1.0.2), permite que você melhore as proporções de compactação significativamente enquanto ainda fornece acesso eficiente aos índices.

Especifique COMPRESS ADVANCED LOW no momento da criação de um índice para habilitar a compressão de índice avançada.

A compressão de índice avançada funciona bem em todos os índices suportados, incluindo aqueles índices que não são bons candidatos para a compactação.

Advanced Index Compression é parte da feature Oracle Advanced Compression, que é uma option que pode ser adquirida(comprada) com Oracle Database Enterprise Edition.

https://docs.oracle.com/database/121/DBLIC/options.htm#DBLIC140

Veja a Sintaxe:

CREATE INDEX idxname ON tabname(col1, col2, col3) compress ADVANCED LOW;

Vamos a um exemplo:

Primeiro nos conectamos com o usuário user01, que é um usuário que já tínhamos em nosso banco:

[oracle@serv01 ~]$ sqlplus user01/teste

SQL*Plus: Release 12.1.0.2.0 Production on Thu Feb 22 11:59:29 2018

Copyright (c) 1982, 2014, Oracle.  All rights reserved.

Last Successful login time: Fri Feb 16 2018 11:51:58 -03:00

Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options

Nosso exemplo será baseado na dba_objects, que em meu banco tem 91 mil registros:

SQL> select count(*) from dba_objects;

COUNT(*)
----------
91781

SQL>

Vamos lá!

Índice normal:

Certo, vamos ao cenário com índice padrão btree.
Vamos criar a tabela: tb_teste_index que é baseada na: dba_objects, como demonstrado abaixo.
Em seguida fazemos um loop para inserir nesta mesma tabela os 91 mil registros da dba_objects mais 11 vezes, aumentando assim nossa massa de dados. Veja abaixo:

SQL> create table tb_teste_index as
select o.owner, o.object_name, o.object_type from dba_objects o;

Table created.

SQL> begin

for x in 1..11
loop
insert into tb_teste_index
select o.owner, o.object_name, o.object_type from dba_objects o;
end loop;
commit;
end;
/  

PL/SQL procedure successfully completed.

SQL> select count(*) from tb_teste_index;

COUNT(*)
----------
1101360

Ok, temos aproximadamente 1 milhão de registros. Vamos criar um índice normal agora e coletar as estatísticas do índice:

SQL> create index idx_tb_teste_index on tb_teste_index(object_type);


Index created.

SQL> SQL> exec dbms_stats.gather_index_stats('USER01', 'IDX_TB_TESTE_INDEX');

PL/SQL procedure successfully completed.

Certo, veja quanto este índice está ocupando com a consulta abaixo:

SQL> select bytes from user_segments where segment_name = 'IDX_TB_TESTE_INDEX';

BYTES
----------
26214400

Agora com nossa tabela populada veja o plano de execução de uma consulta simples.
Repare que o índice está sendo utilizado e repare o custo total. Vamos continuar a analisar partindo para outro cenário, vamos comparar com o ADVANCED INDEX COMPRESSION na sequência:

SQL> explain plan for
select count(1)
from tb_teste_index
where object_type = 'TABLE';    

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 3410653443
----------------------------------------------------------------------------------------
| Id  | Operation         | Name               | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                    |     1 |     9 |    69   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE   |                    |     1 |     9 |            |          |
|*  2 |   INDEX RANGE SCAN| IDX_TB_TESTE_INDEX |  1995 | 17955 |    69   (0)| 00:00:01 |
----------------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_TYPE"='TABLE')
14 rows selected.
SQL>

Advanced Index Compression:

Seguindo nossa análise, vamos montar o cenário para o ADVANCED INDEX COMPRESSION. Criamos a tabela: tb_teste_advanced_index baseada na dba_objects como fizemos antes.
Aproveite e popule-a para ficar com 1 milhão de registros aproximadamente:

SQL> create table tb_teste_advanced_index as
select o.owner, o.object_name, o.object_type from dba_objects o; 

Table created.

SQL> begin

for x in 1..11
loop
insert into tb_teste_advanced_index
select o.owner, o.object_name, o.object_type from dba_objects o;
end loop;
commit;
end;
/   

PL/SQL procedure successfully completed.

SQL> select count(*) from tb_teste_advanced_index;

COUNT(*)
----------
1101360

Agora o pulo do gato, crie o index utilizando a funcionalidade de ADVANCED INDEX COMPRESSION, informando: compress advanced low no momento da criação do index:

SQL> create index idx_tb_teste_advanced_index on tb_teste_advanced_index(object_type) compress advanced low;

Index created.

Colete as estatísticas do índice que acabamos de criar e veja o total de bytes que ele está ocupando. Repare que o espaço utilizado por este índice já é bem menor que o índice normal que criamos anteriormente:

SQL> exec dbms_stats.gather_index_stats('USER01', 'IDX_TB_TESTE_ADVANCED_INDEX');

PL/SQL procedure successfully completed.

SQL> select bytes from user_segments where segment_name = 'IDX_TB_TESTE_ADVANCED_INDEX';

BYTES
----------
14680064

Agora, veja o plano de execução da mesma consulta simples, utilizando a nova tabela que criamos mas, que está utilizado o advanced index compression.
Veja que o index está sendo utilizado e que o custo é muito menor se, comparado ao plano da consulta anterior:

SQL> explain plan for
select count(1)
from tb_teste_advanced_index
where object_type = 'TABLE'; 

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2813549140
-------------------------------------------------------------------------------------------------
| Id  | Operation         | Name                        | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                             |     1 |     9 |    39   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE   |                             |     1 |     9 |       |          |
|*  2 |   INDEX RANGE SCAN| IDX_TB_TESTE_ADVANCED_INDEX |  1995 | 17955 |    39   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_TYPE"='TABLE')
14 rows selected.
SQL>

Comparativo de Performance:

Vamos a um teste simples de performance.
Vamos consultar a quantidade de objetos existentes em nossas duas tabelas pelo filtro de tipo de objeto(object_type).
As duas consultas irão utilizar o índice, porém, vamos ver qual será mais rápida, veja:

SQL> set serveroutput on
declare
vStart number;
vQtde pls_integer;
vTot pls_integer;

cursor cur_objetos is
select distinct o.object_type from dba_objects o;
begin

-- Indice normal
vStart := dbms_utility.get_time;
vQtde := 0;
vTot := 0;

for x in cur_objetos
loop

select count(1)
into vTot
from tb_teste_index
where object_type = x.object_type;

vQtde := vQtde + vTot;

end loop;

dbms_output.put_line('Index Normal (' || vQtde || ' rows): ' ||
(dbms_utility.get_time - vStart) || ' hsecs');


-- Advanced index compression
vStart := dbms_utility.get_time;
vQtde := 0;
vTot := 0;

for y in cur_objetos
loop

select count(1)
into vTot
from tb_teste_advanced_index
where object_type = y.object_type;

vQtde := vQtde + vTot;

end loop;

dbms_output.put_line('Advanced index compression (' || vQtde || ' rows): ' ||
(dbms_utility.get_time - vStart) || ' hsecs');
end;
/SQL>

Index Normal (1101360 rows): 59 hsecs
Advanced index compression (1101360 rows): 15 hsecs

PL/SQL procedure successfully completed.

Vimos neste teste simples que a consulta que utilizou o: Advanced Index Compression foi bem mais rápida.

Por hoje é isso pessoal,

Abraço,

Ronaldo.

Nenhum comentário:

Postar um comentário