Por que usar cursores explícitos em vez de loops regulares?

12

Escrevo aplicativos da Web básicos há um ano (para um banco de dados Oracle) e, como as funções são bem simples, a maioria de nós usa loops FOR regulares para obter nossos dados:

for i in (select * from STUDENTS) loop
      htp.prn(i.student_last_name || ', ' || i.student_first_name || ' ' || i.student_dob);
end loop;

Mas, os cursores parecem ser a maneira 'certa' de fazer as coisas. Posso encontrar muitas informações sobre o que são os cursores e maneiras diferentes de fazer um loop entre eles, mas não consigo encontrar uma razão sólida para usá-los em loops FOR regulares. Depende das necessidades do procedimento? Existem vantagens inerentes das quais devo estar ciente?

ini
fonte
Esse tipo de FORé apenas outra maneira de usar cursores. Consulte os documentos: docs.oracle.com/cd/E11882_01/appdev.112/e10472/… Enfim, o que htp.prn () faz?
Dezso
Essa é uma das nossas funções de saída. Então, você tem uma preferência sobre qual método usar?
In16
Para esse tipo de coisa, o FORloop é muito mais legível, eu acho. Eu tendem a usar cursores 'reais' apenas se tiver que dar um passo para trás, não apenas para frente. Fiz essa outra pergunta porque posso imaginar uma função de tabela em vez de htp.prn().
Dez16
Vale ressaltar que ambas as formas de cursor têm desempenho inferior a uma solução SQL pura - particularmente relevante para instruções DML.
David Aldridge

Respostas:

7

Um cursor pode ser explícito ou implícito e qualquer um dos tipos pode ser usado em um loop FOR. Existem realmente dois aspectos em sua pergunta.

  1. Por que usar um loop FOR explícito do cursor sobre um loop FOR implícito do cursor?

    • Use um loop FOR explícito do cursor quando a consulta for reutilizada, caso contrário, um cursor implícito é preferido.
  2. Por que usar um loop com um FETCH em vez de um loop FOR que não possui um FETCH explícito?

    • Use um FETCH dentro de um loop quando precisar coletar em massa ou quando precisar de SQL dinâmico.

Aqui estão algumas informações úteis da documentação.

Exemplo de cursor implícito FOR LOOP

BEGIN
   FOR vItems IN (
      SELECT last_name
      FROM employees
      WHERE manager_id > 120
      ORDER BY last_name
   ) 
   LOOP
      DBMS_OUTPUT.PUT_LINE ('Name = ' || vItems.last_name);
   END LOOP;
END;
/

Exemplo de Cursor Explícito FOR LOOP

DECLARE
   CURSOR c1 IS
      SELECT last_name
      FROM employees
      WHERE manager_id > 120
      ORDER BY last_name;
BEGIN
   FOR vItems IN c1 LOOP
      DBMS_OUTPUT.PUT_LINE ('Name = ' || vItems.last_name);
   END LOOP;
END;
/

Cursor implícito

Um cursor implícito é um cursor de sessão que é construído e gerenciado por PL / SQL. O PL / SQL abre um cursor implícito toda vez que você executa uma instrução SELECT ou DML. Você não pode controlar um cursor implícito, mas pode obter informações de seus atributos.

Um cursor implícito fecha após a execução da instrução associada; no entanto, seus valores de atributo permanecem disponíveis até que outra instrução SELECT ou DML seja executada.

Os atributos implícitos do cursor são: SQL% ISOPEN, SQL% FOUND, SQL% NOTFOUND, SQL% ROWCOUNT, SQL% BULK_ROWCOUNT, SQL% BULK_EXCEPTIONS

Cursor explícito

Um cursor explícito é um cursor de sessão que você constrói e gerencia. Você deve declarar e definir um cursor explícito, atribuindo-lhe um nome e associando-o a uma consulta (normalmente, a consulta retorna várias linhas). Em seguida, você pode processar o conjunto de resultados da consulta de uma das seguintes maneiras:

Abra o cursor explícito (com a instrução OPEN), busque linhas do conjunto de resultados (com a instrução FETCH) e feche o cursor explícito (com a instrução CLOSE).

Use o cursor explícito em uma instrução FOR LOOP do cursor (consulte "Processamento do conjunto de resultados da consulta com instruções FOR LOOP do cursor").

Você não pode atribuir um valor a um cursor explícito, usá-lo em uma expressão ou como um parâmetro formal do subprograma ou variável de host. Você pode fazer essas coisas com uma variável de cursor (consulte "Variáveis ​​do cursor").

Ao contrário de um cursor implícito, você pode fazer referência a um cursor explícito ou variável de cursor por seu nome. Portanto, um cursor explícito ou variável de cursor é chamado de cursor nomeado.

Instruções Cursor FOR LOOP

A instrução FOR LOOP do cursor permite executar uma instrução SELECT e, em seguida, percorrer imediatamente as linhas do conjunto de resultados. Esta declaração pode usar um cursor implícito ou explícito.

Leigh Riffel
fonte
11
Os cursores implícitos buscam 100 linhas por vez a partir de 10g.
David Aldridge
16

O código que você postou está usando um cursor. Está usando um loop implícito do cursor.

Há casos em que o uso de um loop explícito do cursor (por exemplo, declarar uma variável CURSOR na seção de declaração) produz código mais limpo ou melhor desempenho

  1. Se você tiver consultas mais complexas e não puder refatorar em visualizações, ele poderá facilitar a leitura do código se o loop repetir student_cursorem vez de incluir uma instrução SQL de 30 linhas que incorpora um monte de lógica. Por exemplo, se você estava imprimindo todos os alunos que foram liberados para se formar e que envolviam ingressar em tabelas que tinham seus registros acadêmicos, os requisitos do programa de graduação, tabelas com informações sobre retenções acadêmicas, tabelas com informações sobre livros vencidos da biblioteca, tabelas com informações sobre taxas não pagas, substituições administrativas, etc. provavelmente faria sentido refatorar o código para que essa consulta não ficasse no meio do código que se preocupa em apresentar a lista a um usuário. Isso pode envolver a criação de uma visão que encapsularia toda essa lógica. Ou pode envolver a criação de um cursor explícito que foi declarado como parte do bloco PL / SQL atual ou em algum bloco PL / SQL de nível superior (por exemplo, um cursor declarado em um pacote) para que seja reutilizável. Ou pode envolver fazer outra coisa para encapsulamento e reutilização (por exemplo, criando uma função de tabela em pipeline).
  2. Se você deseja fazer uso de operações em massa no PL / SQL, geralmente deseja usar cursores explícitos. Aqui está um encadeamento StackOverflow que discute as diferenças de desempenho entre cursores explícitos e implícitos . Se tudo o que você está fazendo é ligar htp.prn, fazer um BULK COLLECTprovavelmente não comprará nada. Em outros casos, no entanto, pode resultar em melhorias substanciais no desempenho.
Justin Cave
fonte
2

Vejo que muitos desenvolvedores estão usando cursores explícitos em vez de cursores implícitos, fora do antigo hábito. Isso porque no Oracle versão 7, esse sempre foi o caminho mais eficiente. Hoje em dia geralmente existe o contrário. Especialmente com o otimizador que, se necessário, pode reescrever o cursor implícito para loops em uma coleta em massa.

Peter Åkerlund
fonte
0

Recentemente, tive que reescrever um monte de consultas de um loop FOR implícito em cursores explícitos. O motivo foi que as consultas buscaram dados de um banco de dados externo via link e esse banco de dados tinha uma codificação diferente do nosso banco de dados local. Ao transferir dados do cursor implícito para um tipo de registro definido localmente, ocorreram erros intermitentes misteriosos (apenas em determinadas linhas específicas). Nosso DBA explicou isso para nós, não teríamos sido capazes de chegar ao fundo disso sozinhos. Parece que esse erro foi relatado no Oracle.

Fomos aconselhados a reescrever tudo usando cursores explícitos e o erro desapareceu.

Não é o principal motivo pelo qual você pode usar explícito ou implícito, mas vale a pena notar.

Edição: Oracle 12c.

Robotron
fonte
Você poderia adicionar o bug e / ou o número da nota para que aqueles que estão lendo isso possam saber mais sobre os sintomas e se / quando isso for resolvido?
Leigh Riffel
Desculpe, o relatório de erros foi feito por um dos nossos DBAs, não tenho acesso a essas informações.
Robotron 24/05