Pergunta

Eu tenho um par de cenários:

  1. precisa ler o valor de uma coluna de três tabelas diferentes em uma ordem predefinida e apenas 1 mesa terá os dados

  2. Ler dados da tabela 1 se os registros estão presentes para critérios dados pessoa ler dados de Table2 para critérios dados

No Oracle Stored Procedures

A forma como estes estão sendo tratados agora é a primeira a obter a contagem para uma determinada consulta em uma variável, e se a contagem> 0, então vamos executar a mesma consulta para ler os dados reais como em:

select count(*) from table1 into v_count
if v_count > 0
then
    select data into v_data from table1
end if;

Return v_data

Isso está sendo feito para evitar a exceção NO_DATA_FOUND, caso contrário, eu precisaria três blocos manipulador de exceção para capturar a exceção NO_DATA_FOUND para cada acesso à tabela.

Atualmente estou reimplementação isso com cursores para que eu tenha algo como isto:

cursor C1 is
    select data from table1;
Open C1
Fetch C1 into v_data
if C1%FOUND
then
    Close C1
    Return v_data
End If

Eu queria descobrir qual é o melhor do ponto de vista do desempenho - aquele com os cursores, ou aquele que faz um Select em uma variável e tem três blocos de exceção NO_DATA_FOUND. Eu não quero usar o processo de consulta em duas fases que temos atualmente.

Foi útil?

Solução

Eu não sei por que você está tão interessado em evitar a exceção? O que está errado com:

begin
    begin
        select data into v_data from table1;
    exception
        when no_data_found then
        begin
            select data into v_data from table2;
        exception
            when no_data_found then
            begin
               select data into v_data from table3;
            exception
                when no_data_found then
                    v_data := null;
            end;
        end;
    end;
    return v_data;
end;

Eu acredito que este terá um desempenho melhor do que a outra solução, porque ele faz o trabalho mínimo possível alcançar o resultado desejado.

Quão ruim é ignorando exceção do Oracle DUP_VAL_ON_INDEX? onde eu demonstram que o uso de exceções desempenho melhor do que a contagem para ver se há quaisquer dados.

Outras dicas

select count(*) from table1 into v_count
if v_count > 0 then
    select data into v_data from table1;
else
    v_data := null;
end if;
return v_data;

não é equivalente a

begin
    select data into v_data from table1;
    return v_data;
exception
    when no_data_found then
        return null;
end;

em um ambiente multi-usuário. No primeiro caso, alguém poderia atualizar a tabela entre os pontos onde você verificar se há existência e quando você ler os dados.

Em termos de performance, não tenho idéia de qual é o melhor, mas eu sei que a primeira opção faz duas mudanças de contexto para o motor sql eo segundo só faz interruptor de um contexto.

A maneira como você está lidando com o cenário 1 agora não é bom. Não só você está fazendo duas consultas quando um será suficiente, mas como Erik apontou, abre-se a possibilidade de alteração de dados entre as duas consultas (a menos que você use uma transação somente leitura ou serializável).

Uma vez que você diz que, neste caso, os dados estarão em exatamente um dos três mesas, e quanto a isso?

SELECT data
  INTO v_data FROM
  (SELECT data FROM table1
   UNION ALL
   SELECT data FROM table2
   UNION ALL
   SELECT data FROM table3
  )

Outro "truque" você pode usar para evitar escrever vários manipuladores não-encontrada por dados seria:

SELECT MIN(data) INTO v_data FROM table1;
IF v_data IS NOT NULL THEN
   return v_data;
END IF;

SELECT MIN(data) INTO v_data FROM table2;
...etc...

mas eu realmente não vejo qualquer razão que é melhor do que ter três manipuladores de exceção.

Para o seu segundo cenário, eu acho que você quer dizer é que pode haver dados em ambas as tabelas e você quiser usar os dados da tabela 1 se presente, caso contrário, utilizar os dados da tabela 2. Novamente você poderia fazer isso em um único consulta:

SELECT data
  INTO v_data FROM
  (SELECT data FROM
    (SELECT 1 sort_key, data FROM table1
     UNION ALL
     SELECT 2 sort_key, data FROM table2
    )
   ORDER BY sort_key ASC
  )
  WHERE ROWNUM = 1

Uma versão de "Dave Costa" 's opção MIN ...

reforçada
SELECT COUNT(1), MIN(data) INTO v_rowcount, v_data FROM table2;

Agora v_rowcount podem ser verificados para valores 0,> 1 (maior que 1), onde consulta seleção normal, vai jogar NO_DATA_FOUND ou exceção TOO_MANY_ROWS. Valor "1" indica que existe uma linha da exata e vai servir o nosso propósito.

DECLARE
    A VARCHAR(35);
    B VARCHAR(35);
BEGIN
    WITH t AS
    (SELECT OM_MARCA, MAGAZIA FROM ifsapp.AKER_EFECTE_STOC WHERE (BARCODE = 1000000491009))
    SELECT
    (SELECT OM_MARCA FROM t) OM_MARCA,
    (SELECT MAGAZIA FROM t) MAGAZIA
    INTO A, B
    FROM DUAL;
    IF A IS NULL THEN
       dbms_output.put_line('A este null');
    END IF;
    dbms_output.put_line(A);
    dbms_output.put_line(B);
END;
/

Utilize o formulário "para linha no cursor" de um loop eo loop irá simplesmente não processar se não houver dados:

declare cursor
t1Cur is
 select ... from table1;
t2Cur is
 select ... from table2;
t3Cur is
 select ... from table3;
t1Flag boolean FALSE;
t2Flag boolean FALSE;
t3Flag boolean FALSE;
begin
for t1Row in t1Cur loop
  ... processing, set t1Flag = TRUE
end loop;
for t2Row in t2Cur loop
  ... processing, set t2Flag = TRUE
end loop;
for t3Row in t3Cur loop
  ... processing, set t3Flag = TRUE
end loop;
... conditional processing based on flags
end;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top