Optimizar una consulta SQL: ¿llamar a una función o hacer una combinación?

¿Cuál es el más rápido en una base de datos ORACLE?

Llame a una función dentro de una declaración de selección para recuperar un solo valor para cada fila

SELECT field1, field2, F_GET_LIBELLE_STATUT( field2 ) FROM table1 WHERE ...

con la función sencilla:

create or replace
FUNCTION "F_GET_LIBELLE_STATUT" (v_statut NUMBER) RETURN VARCHAR2 IS
tmpVar VARCHAR2(40);
BEGIN
   select libelle into tmpVar from t_statut_ope where id_statut = v_statut;
   RETURN tmpVar;
   EXCEPTION
     WHEN NO_DATA_FOUND THEN
       RETURN '';
     WHEN OTHERS THEN
       -- Consider logging the error and then re-raise
       RAISE;
END f_get_libelle_statut;

¿O haciendo una combinación en la declaración de selección?

Select a.field1, a.field2, b.libelle
FROM table1 a LEFT JOIN t_statut_ope b ON b.id_statut = a.field2
WHERE ...

¿Y es la misma respuesta si llamo a muchas funciones (diez o más) en la condición select y en la cláusula?

Gracias por tu respuesta.

preguntado el 03 de mayo de 12 a las 07:05

En este escenario específico, la combinación simple superará a la función, pero eso no significa que siempre lo hará. Siempre debe mirar los planes de ejecución de sus soluciones y sacar sus conclusiones de eso. -

@Lieven: estoy de acuerdo con la necesidad de tratar cada caso según sus méritos. Pero una unión siempre será más rápida que una función de búsqueda del tipo publicado aquí. Es axiomático. -

@APC: tiendo a estar de acuerdo, pero desconfío de las declaraciones absolutas como siempre y nunca. -

4 Respuestas

Cualquier cosa que se pueda hacer en SQL debe hacerse en SQL (*).

Una unión siempre será más rápida que llamar a esa función porque las operaciones basadas en conjuntos siempre son más rápidas que fila por fila agonizante. Entonces tiene la sobrecarga de moverse entre SQL y PL/SQL. Además de la sobrecarga de manejar esas excepciones NO_DATA_FOUND, que no son realmente excepciones porque se esperan y toleran brechas. Finalmente, el optimizador elegirá un plan mejor para la opción de SQL puro porque le ha dado toda la información que necesita.


(*) Respondí esta pregunta hace mucho tiempo y la respondí enfocándome en el ejemplo dado, y mantengo esa respuesta. Si podemos obtener los datos que necesitamos usando SQL contra tablas (a través de uniones, vistas, vistas en línea, subconsultas), entonces deberíamos hacerlo. Pero quiero profundizar en la pregunta subyacente: ¿por qué Oracle admite el uso de funciones en las consultas? Porque a veces necesitamos hacer cosas que no podemos hacer en SQL.

Aquí hay casos de uso para llamar a funciones que ejecutan SQL (estoy pensando principalmente en funciones invocadas a través de table() llamadas) en lugar de usar una combinación (u otras construcciones de SQL como vista en línea, cláusula WITH):

  1. La consulta es dinámica. SQL dinámico requiere PL/SQL, por lo que una función es tu única persona aquí.
  2. Generación de filas. Usar PL/SQL para dividir la entrada en varias cadenas (como la tokenización de CSV) o tal vez para generar datos, no de una tabla. Ocasionalmente sigue siendo válido, pero la compatibilidad con expresiones regulares y el ingenioso truco CONECTAR POR NIVEL <= N han clasificado los usos más comunes.
  3. Los datos se encapsulan detrás de una API PL/SQL, por lo que todo lo que podemos llamar es una función.
  4. Por alguna extraña razón, solo podemos obtener el rendimiento que necesitamos usando PL/SQL para implementar un filtro o una búsqueda. Aparentemente. Para ser honesto, nunca recuerdo un caso en el que tuve que hacer esto y funcionó (aunque he tenido algunos casos en los que convertir una función canalizada en una subconsulta o una vista en línea mejoró el rendimiento). Tal vez he llevado una vida protegida. Ciertamente, agradecería las citas comparativas para los contraejemplos.

respondido 09 nov., 21:07

Sin embargo, a veces las subconsultas seleccionadas son más rápidas que las uniones. Simplemente necesita pruebas. - Olafur Tryggvason

@OlafurTryggvason: una subconsulta sigue siendo SQL. - APC

Habría un número muy pequeño de circunstancias en las que el método de función sería óptimo y, de forma predeterminada, no lo usaría. Las uniones son para lo que están diseñadas las bases de datos, por lo que deberían ser su primera opción.

contestado el 03 de mayo de 12 a las 10:05

¿Qué descubriste tú mismo usando esas 2 consultas diferentes?

Según mi experiencia, una combinación es 9 de cada 10 veces más rápida que una función. Al menos cuando accede a otra consulta/tabla/vista en la función. La función debe evaluarse cada ejecución, la unión probablemente genera un conjunto de datos más grande, pero puede funcionar mejor porque solo tiene que unir las tablas (en claves), lo cual es bastante rápido.

contestado el 03 de mayo de 12 a las 07:05

La primera consulta (con la función) se encontró en una aplicación existente en la que estoy trabajando. La segunda consulta es más como lo hago en general, así que antes de volver a escribir todas las consultas con combinaciones, trato de saber cuál es más eficiente. - fluminis

O olvídese de la combinación externa y coloque la declaración de selección que hace la traducción en la lista de selección [esto a veces es más rápido que la combinación externa]:

SELECT field1, field2
, (select libelle from t_statut_ope b where b.id_statut = a.field2) libelle
FROM table1 a
WHERE 1=1
;

contestado el 03 de mayo de 12 a las 15:05

Interesante, ¿sabes cuándo / por qué es en algún momento más rápido? - fluminis

No creo haber visto nunca que la "instrucción de selección en la lista de selección" sea más lenta que la "unión externa". Sospecho que el trabajo adicional requerido por Oracle para "crear" los registros que faltan provoca la ralentización de la unión externa. Este trabajo aumenta para mesas muy grandes a ambos lados. - roger cornejo

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.