Oracle PL/SQL BULK COLLECT: Exemplo FORALL

⚡ Resumo Inteligente

COLETA EM GRANDE QUANTIDADE em Oracle PL/SQL busca várias linhas de uma só vez em uma coleção, enquanto FORALL envia operações DML em massa de volta para o banco de dados. Ambos reduzem as trocas de contexto entre os mecanismos SQL e PL/SQL, aumentando o desempenho.

  • 📦 COLETA EM GRANDE QUANTIDADE: Busca várias linhas em uma única passagem para uma variável de coleção, substituindo a busca lenta linha por linha.
  • 🔁 PARA TODOS: Executa uma única operação INSERT, UPDATE ou DELETE em toda a coleção com uma única troca de contexto.
  • 📏 Cláusula LIMIT: Limita a quantidade de linhas que cada comando BULK COLLECT carrega, protegendo a memória da sessão em tabelas grandes.
  • 📊 Atributos de COLETA EM MASSA: O atributo %BULK_ROWCOUNT(n) informa quantas linhas a n-ésima instrução DML FORALL afetou.
  • ⚙️ Coleções necessárias: A cláusula INTO deve ter como alvo um tipo de coleção, como uma tabela aninhada ou uma matriz associativa.
  • 🤖 Assistência de IA: Assistentes de IA como o GitHub Copilot elaboram blocos BULK COLLECT e FORALL e sinalizam a ausência de uma cláusula LIMIT.

Oracle Visão geral das funções PL/SQL BULK COLLECT e FORALL com cláusula LIMIT

O que é COLETA EM GRANEL?

A COLETA EM MASSA reduz as trocas de contexto entre os SQL e o mecanismo PL/SQL, permitindo que o mecanismo SQL busque os registros de uma só vez.

Oracle PL/SQL Oferece a funcionalidade de buscar registros em lote, em vez de buscá-los um por um. Este comando BULK COLLECT pode ser usado em uma instrução SELECT para preencher os registros em lote ou para buscar um conjunto de registros. cursor Em lote. Como o BULK COLLECT busca os registros em lote, a cláusula INTO deve sempre conter uma variável de tipo de coleção. A principal vantagem de usar o BULK COLLECT é o aumento de desempenho, que reduz a interação entre o banco de dados e o mecanismo PL/SQL.

Sintaxe:

SELECT <column1> BULK COLLECT INTO bulk_variable FROM <table name>;
FETCH <cursor_name> BULK COLLECT INTO <bulk_variable>;

Na sintaxe acima, BULK COLLECT é usado para coletar os dados das instruções SELECT e FETCH.

Cláusula FORALL

A instrução FORALL executa Operações DML em dados em massa. Assemelha-se a uma instrução de laço FOR, exceto que em um laço FOR as ações ocorrem no nível do registro, enquanto em FORALL não existe o conceito de laço. Em vez disso, todos os dados presentes no intervalo especificado são processados ​​simultaneamente.

Sintaxe:

FORALL <loop_variable> in <lower range> .. <higher range>

<DML operations>;

Na sintaxe acima, a operação DML fornecida será executada para todos os dados presentes entre os limites inferior e superior.

Cláusula LIMIT

O conceito de coleta em massa carrega todos os dados na variável de coleção de destino de uma só vez, ou seja, todos os dados serão inseridos na variável de coleção de uma só vez. No entanto, isso não é recomendável quando o número total de registros a serem carregados é muito grande, pois, ao tentar carregar todos os dados, o PL/SQL consome mais memória da sessão. Portanto, é sempre bom limitar o tamanho dessa operação de coleta em massa.

Esse limite de tamanho pode ser facilmente alcançado introduzindo a condição ROWNUM na instrução SELECT, enquanto que no caso de um cursor isso não é possível.

Para superar isso, Oracle forneceu a cláusula LIMIT que define o número de registros que precisam ser incluídos no lote.

Sintaxe:

FETCH <cursor_name> BULK COLLECT INTO <bulk_variable> LIMIT <size>;

Na sintaxe acima, a instrução de busca do cursor usa a instrução BULK COLLECT juntamente com a cláusula LIMIT.

BULK COLLECT Atributos

Semelhante aos atributos de cursor, o comando BULK COLLECT possui a função %BULK_ROWCOUNT(n), que retorna o número de linhas afetadas na n-ésima instrução DML do comando FORALL, ou seja, fornece a contagem de registros afetados na instrução FORALL para cada valor da variável de coleção. O termo 'n' indica a sequência do valor na coleção para a qual a contagem de linhas é necessária.

1 exemplo: Neste exemplo, vamos projetar todos os nomes dos funcionários da tabela `emp` usando BULK COLLECT e também vamos aumentar o salário de todos os funcionários em 5000 usando FORALL.

A captura de tela abaixo mostra este exemplo de BULK COLLECT e FORALL juntamente com sua saída em Oracle.

Exemplo de COLETA EM MASSA com LIMIT e FORALL atualizando o salário do funcionário em Oracle PL/SQL

DECLARE
CURSOR guru99_det IS SELECT emp_name FROM emp;
TYPE lv_emp_name_tbl IS TABLE OF VARCHAR2(50);
lv_emp_name lv_emp_name_tbl;
BEGIN
OPEN guru99_det;
FETCH guru99_det BULK COLLECT INTO lv_emp_name LIMIT 5000;
FOR c_emp_name IN lv_emp_name.FIRST .. lv_emp_name.LAST
LOOP
Dbms_output.put_line('Employee Fetched:'||c_emp_name);
END LOOP;
FORALL i IN lv_emp_name.FIRST .. lv_emp_name.LAST
UPDATE emp SET salary=salary+5000 WHERE emp_name=lv_emp_name(i);
COMMIT;
Dbms_output.put_line('Salary Updated');
CLOSE guru99_det;
END;
/

saída

Employee Fetched:BBB
Employee Fetched:XXX
Employee Fetched:YYY
Salary Updated

Code Explicação:

  • Code linha 2: Declarando o cursor guru99_det para a instrução 'SELECT emp_name FROM emp'.
  • Code linha 3: Declarando lv_emp_name_tbl como um tipo de tabela VARCHAR2(50).
  • Code linha 4: Declarando lv_emp_name como o tipo lv_emp_name_tbl.
  • Code linha 6: Abrindo o cursor.
  • Code linha 7: Obtendo o cursor usando BULK COLLECT com o tamanho LIMIT definido como 5000 e armazenando-o na variável lv_emp_name.
  • Code linhas 8-11: Configure um loop FOR para imprimir todos os registros da coleção lv_emp_name.
  • Code linha 12: Utilizando a função FORALL para atualizar o salário de todos os funcionários em 5000.
  • Code linha 14: Comprometer-se com o transação.

Perguntas Frequentes

Não. Um comando BULK COLLECT SELECT nunca gera NO_DATA_FOUND; em vez disso, retorna uma coleção vazia. Sempre teste a coleção com o método .COUNT antes de usar o comando loo.pingCaso contrário, você poderá processar zero linhas silenciosamente.

SAVE EXCEPTIONS permite que FORALL continue sendo executado mesmo quando linhas individuais falham. As linhas com falha são armazenadas em SQL%BULK_EXCEPTIONS, então Oracle gera o erro ORA-24381, que você captura em um exceção manipulador para inspecionar cada erro.

Use BULK COLLECT sempre que um loop ler muitas linhas. cursor O loop FOR busca uma linha por vez, portanto, a busca em lote combinada com FORALL pode ser executada muitas vezes mais rápido em grandes conjuntos de resultados.

BULK COLLECT retorna várias linhas de uma só vez, portanto, precisa de um contêiner com várias linhas. O destino INTO deve ser um coleção como uma tabela aninhada, VARRAY ou matriz associativa, e não uma única variável escalar.

Não. Um cabeçalho FORALL executa exatamente uma instrução INSERT, UPDATE, DELETE ou MERGE. Somente os valores em suas cláusulas VALUES e WHERE podem mudar a cada iteração. Para várias instruções, use instruções FORALL separadas.

O processamento em lote pode ser de várias a mais de cem vezes mais rápido do que o código linha por linha, porque BULK COLLECT e FORALL condensam milhares de trocas de contexto do mecanismo em poucas, reduzindo drasticamente a sobrecarga em grandes volumes de dados.

Sim. Travas deslizantes portáteis Copiloto do GitHub O script descreve rascunhos de coletas BULK COLLECT, loops DML FORALL e cláusulas LIMIT a partir de um comentário, e sugere declarações de tipo de coleção, embora você deva revisar os tamanhos dos lotes e o tratamento de erros por conta própria.

Assistentes de IA analisam loops que buscam ou alteram uma linha por vez e recomendam reescrevê-los com BULK COLLECT, LIMIT e FORALL. Essa análise por aprendizado de máquina detecta limitações LIMIT ausentes e gargalos de desempenho antes da produção.

Resuma esta postagem com: