2009-07-06 8 views
10

Estoy usando Oracle, y tengo una tabla muy grande. Necesito verificar si existe alguna fila que cumpla con algunos criterios simples. ¿Cuál es la mejor manera de hacerlo usando SQL simple?¿La consulta más rápida para verificar la existencia de una fila en Oracle?

Aquí es mi mejor conjetura, y si bien puede llegar a ser lo suficientemente rápido para mis propósitos, me gustaría aprender una forma canónica que ver básicamente servidor de SQL "existe" en Oracle:

select count(x_id) from x where x.col_a = value_a and x.col_b = value_b; 

El conteo() se devolverá como un booleano en otro nivel. El punto principal es que quiero que Oracle haga el mínimo indispensable para esta consulta: solo necesito saber si hay filas que coincidan con los criterios.

Y sí, esas columnas definitivamente serán indexadas.

Respuesta

16

El uso de COUNT (*) está bien si también usa rownum = 1:

declare 
    l_cnt integer; 
begin 
    select count(*) 
    into l_cnt 
    from x 
    where x.col_a = value_a 
    and x.col_b = value_b 
    and rownum = 1; 
end; 

Esto siempre devolverá una fila, así que no hay necesidad de manejar cualquier excepción NO_DATA_FOUND. El valor de l_cnt será 0 (sin filas) o 1 (al menos 1 fila existe).

+1

@Tony. ¿Haría un recuento (*) en lugar de EXISTS? Para mí, un EXISTE parece más natural, incluso si necesita lidiar con la excepción. –

+0

¿Quiere decir "seleccionar 1 de dual donde existe (...)"? No lo haría, pero puedo entender por qué algunos lo harían. Lo que realmente se quiere que sea totalmente natural es una construcción PL/SQL como "SI existe (seleccione ...) ENTONCES ..."! –

+0

Estoy siendo flojo aquí al no probarlo yo mismo, pero no contaría (x_id) sería más rápido que count (*), o es el intérprete sql lo suficientemente inteligente como para ver que realmente no necesita expandir "*" ? –

5
SELECT NULL 
FROM x 
WHERE x.col_a = value_a 
     AND x.col_b = value_b 
     AND rownum = 1 

COUNT(*) ciertamente no es la mejor manera, ya que tendrá que contar todas las filas, mientras que ROWNUM = 1 vuelve tan pronto como se encuentra la primera fila coincidente.

Aquí está el código PL/SQL:

DECLARE 
     ex INT; 
BEGIN 
     BEGIN 
       SELECT NULL 
       INTO ex 
       FROM dual 
       WHERE 1 = 1 
         AND rownum = 1; 
       DBMS_OUTPUT.put_line('found'); 
     EXCEPTION 
     WHEN no_data_found THEN 
       DBMS_OUTPUT.put_line('not found'); 
     END; 
END; 
+0

¿Quizás incluso una sugerencia de FIRST_ROWS? El optimizador debería hacer esto implícitamente cuando vea el rownum = 1, creo. SELECT/* + FIRST_ROWS (n) */NULL –

+0

@Robert: por supuesto, no hará daño agregar uno, pero realmente funciona solo en combinaciones (hace que el optimizador prefiera NESTED LOOP sobre HASH JOIN) – Quassnoi

+1

@ Quassnoi: Pensé que también optimizaba el "índice feliz" del optimizador. –

1
begin 
select 'row DOES exist' 
    into ls_result 
from dual 
where exists (select null from x where x.col_a = value_a and x.col_b = value_b); 
exception 
when no_data_found then 
    ls_result := ' row does NOT exist'; 
end; 
7

Creo que usar EXISTS da una respuesta más natural a la pregunta que tratar de optimizar una consulta COUNT usando ROWNUM.

Deje que Oracle haga la optimización ROWNUM para usted.

create or replace function is_exists (
     p_value_a varchar2, 
     p_value_b varchar2) 
     return boolean 
is 

    v_exists varchar2(1 char); 

begin 

    begin 
     select 'Y' into v_exists from dual 
     where exists 
      (select 1 from x where x.col_a = p_value_a and x.col_b = p_value_a); 

    exception 

     when no_data_found then 

      v_exists := null; 

    end; 

    return v_exists is not null; 

end is_exists; 
Cuestiones relacionadas