Otimizando Consultas com o Hint INDEX_JOIN no Oracle Database

Introdução ao INDEX_JOIN

O hint INDEX_JOIN é utilizado no Oracle Database para forçar o otimizador a realizar uma junção de índices, evitando acesso à tabela base. Isso pode melhorar o desempenho em consultas que envolvem múltiplas colunas indexadas. Veja exemplos de uso e análise de performance.

Exemplo Básico de Configuração e Uso

Criando tabelas e índices de teste:

CREATE TABLE tbl_origem AS SELECT * FROM dba_objects;
CREATE TABLE tbl_destino AS SELECT * FROM dba_objects WHERE 1=2;
CREATE INDEX idx_obj_id ON tbl_origem(object_id);
CREATE INDEX idx_data_cria ON tbl_origem(created);

Executando uma consulta com o hint INDEX_JOIN:

SET AUTOTRACE TRACEONLY;
INSERT INTO tbl_destino
SELECT /*+ INDEX_JOIN(tbl_origem idx_obj_id idx_data_cria) */ 
       FLOOR((ROWNUM-1)/5) AS grupo, object_id 
FROM tbl_origem 
WHERE created = SYSDATE-1000 AND object_id IS NOT NULL;

Este comando insere dados na tabela destino, usando uma junção de índices para filtrar registros com base em object_id e created, sem acessar a tabela tbl_origem diretamente.

Documentação de Referência

Para mais detalhes sobre hints de otimização, consulte o Oracle Database SQL Tuning Guide.

Cenário Avançado com Monitoramento de Performance

Preparando dados de teste adicionais:

CREATE TABLE tabela_exemplo (
    campo1 VARCHAR2(100),
    campo2 VARCHAR2(100),
    campo3 VARCHAR2(100),
    campo4 VARCHAR2(100),
    campo5 VARCHAR2(100),
    campo6 VARCHAR2(100),
    campo7 VARCHAR2(100),
    data_campo8 DATE
);

INSERT INTO tabela_exemplo 
SELECT 
    TRUNC(DBMS_RANDOM.VALUE(1000,9000)),
    RPAD(TRUNC(DBMS_RANDOM.VALUE(1000,9000)),60,'B2'),
    RPAD(TRUNC(DBMS_RANDOM.VALUE(1000,9000)),60,'B3'),
    RPAD(TRUNC(DBMS_RANDOM.VALUE(1000,9000)),60,'B4'),
    RPAD(TRUNC(DBMS_RANDOM.VALUE(1000,9000)),60,'B5'),
    RPAD(TRUNC(DBMS_RANDOM.VALUE(1000,9000)),60,'B6'),
    RPAD(TRUNC(DBMS_RANDOM.VALUE(1000,9000)),60,'B7'),
    SYSDATE - TRUNC(DBMS_RANDOM.VALUE(1,9000))
FROM DUAL
CONNECT BY LEVEL < 100000;

CREATE INDEX idx_data8 ON tabela_exemplo(data_campo8);
CREATE INDEX idx_campo4 ON tabela_exemplo(campo4);

Criando uma tabela destino para inserção:

CREATE TABLE resultado_insert (
    grupo NUMBER,
    campo4 VARCHAR2(100)
);

Executando a consulta com INDEX_JOIN e monitorando:

INSERT INTO resultado_insert 
SELECT /*+ MONITOR INDEX_JOIN(tabela_exemplo idx_data8 idx_campo4) */ 
       FLOOR((ROWNUM-1)/5) AS grupo, campo4 
FROM tabela_exemplo 
WHERE data_campo8 <= SYSDATE AND campo4 IS NOT NULL;

Análise do Relatório de Monitoramento SQL

Após execução, o relatório SQL Monitor mostra detalhes de performance:

  • Tempo decorrido: 2 segundos
  • Atividades de IO: 61 MB lidos, 30 MB escritos
  • Plano de execução: Utiliza HASH JOIN entre dois índices (idx_data8 e idx_campo4) sem acessar a tabela base.

No plano, a operação VIEW (index$_join$_002) combina dois INDEX FAST FULL SCAN, reduzindo o custo de leitura de dados.

Verificação de Tamanho e Incremento de Dados

Para medir o tamanho dos segmentos:

SELECT bytes/1024/1024, segment_name 
FROM dba_segments 
WHERE segment_name IN ('TABELA_EXEMPLO','IDX_DATA8','IDX_CAMPO4','RESULTADO_INSERT');

Calcule o tamanho dos dados inseridos usando funções de comprimento:

SELECT SUM(LENGTH(campo4))/1024/1024 FROM resultado_insert;
SELECT SUM(LENGTH(campo4))/1024/1024 FROM tabela_exemplo;

Para obter o incremento de dados com base no tempo, use SCN e timestamps. Exemplo para filtrar linhas inseridas em um período específico:

SELECT a.*, 
       TO_CHAR(SCN_TO_TIMESTAMP(DBMS_ROWID.ROWID_BLOCK_NUMBER(a.ROWID)), 'yyyy-mm-dd hh24:mi:ss') AS insercao_tm 
FROM resultado_insert a 
WHERE SCN_TO_TIMESTAMP(DBMS_ROWID.ROWID_BLOCK_NUMBER(a.ROWID)) > TO_DATE('2024-01','YYYY-MM')
  AND ROWNUM < 10;

Este método permite rastrear o volume de dados adicionados por intervalo de tempo, útil para monitoramento de crescimento.

Tags: Oracle Database SQL Performance INDEX_JOIN Hint Database Indexing Query Optimization

Publicado em 6-22 20:53