domingo, 19 de abril de 2009

PL/SQL: Performance: Verificar existencia de un registro

Para verificar la existencia de un registro es mucho mejor usar una función ad-hoc existe, que verifique la existencia en vez de contar la cantidad de registros con un select count y preguntar si la cantidad de registros es mayor que cero. Esto es más dramático cuando usamos un where por un campo con valor no único o una clausula like. Por ejemplo, si deseamos saber si existe un registro con tipo de objeto = 'SYNONYM' , una alternativa (generalmente usada) es hacer:
SELECT COUNT (*)
FROM   objetos
WHERE  object_type = 'SYNONYM';
Una mejor alternativa es hacer una función:

FUNCTION existe (
   p_object_type   IN   objetos.object_type%TYPE
)
   RETURN BOOLEAN IS
   CURSOR c_existe IS
      SELECT 'x'
      FROM   objetos
      WHERE  object_type = p_object_type;

   v_dummy    VARCHAR2 (1);
   v_existe   BOOLEAN;
BEGIN
   OPEN c_existe;

   FETCH c_existe
   INTO  v_dummy;

   v_existe := c_existe%FOUND;

   CLOSE c_existe;

   RETURN v_existe;
END existe;
El primer caso recorre todos los registros, en el segundo caso, solo llega al primer registro y retorna la existencia. Si creamos un bloque anónimo con llamadas iterativas a estas dos instrucciones, tenemos que el tiempo de ejecución es mucho menor para el código ad-hoc eEvalua_Count_vs_Existencia.sql
  • La salida de este script es:
  • 
    Select vía Count:Tiempo en segundos:TF-TI:147 segundos.
    Función existe:Tiempo en segundos:TF-TI:2 segundos.
    
    Por lo tanto, el tiempo de respuesta y el uso de recursos son mucho mejores en el segundo caso. Además, la función de existencia es fácil de implementar programáticamente usando el diccionario de la base de datos.

    5 comentarios:

    1. Una alternativa es usar un stop key en el select count(*), con esto, los resultados entre el count y existe se aproximan:

      SELECT COUNT (*)
      into v_count
      FROM objetos
      WHERE object_type = p_object_type
      and rownum < 2;

      ResponderEliminar
    2. hago un select simple y capturo la excepcion :)

      ResponderEliminar
    3. Es otra alternativa, pero es más código y mas puntos de salida, en general, mientras más simple, mejor. Además de que esto solo sirve si estas pensando en PL/SQL, pero no puedes usarlo como parte de una subquery a no ser que sea una función como la mostrada al principio.

      Observación: Para este efecto, el stop key funciona bien en oracle 10g o superior, en 9i está implementado, pero el costo es el mismo, asi que en ese caso recomiendo usar la función ad-hoc.

      ResponderEliminar
    4. Te escribo desde el trabajo.
      Estaba buscando una manera óptima para comprobar igualdades entre dos tablas.

      Me viene ni que pintado.

      Gracias!

      ResponderEliminar
    5. Una alternativa es utilizar las operaciones de conjunto MINUS o INTERSECT:

      (SELECT 1 id, 'R1' texto
      FROM DUAL
      UNION ALL
      SELECT 2 id, 'R2' texto
      FROM DUAL)
      MINUS
      SELECT 1 id, 'R1' texto
      FROM DUAL;

      (SELECT 1 id, 'R1' texto
      FROM DUAL
      UNION ALL
      SELECT 2 id, 'R2' texto
      FROM DUAL)
      INTERSECT
      SELECT 1 id, 'R1' texto
      FROM DUAL;

      ResponderEliminar