Imagina tener una herramienta que pueda detectar automáticamente los problemas de rendimiento de JPA e Hibernate. ¡Hypersistence Optimizer es esa herramienta!
Introducción
En este artículo, vamos a ver cómo funciona el operador EXISTS de SQL y cuándo debes utilizarlo.
Aunque el operador EXISTS ha estado disponible desde SQL:86, la primera edición del Estándar SQL, he encontrado que todavía hay muchos desarrolladores de aplicaciones que no se dan cuenta de lo poderosas que son realmente las expresiones de subconsulta SQL cuando se trata de filtrar una tabla dada en base a una condición evaluada en una tabla diferente.
Modelo de tabla de la base de datos
Supongamos que tenemos las siguientes dos tablas en nuestra base de datos, que forman una relación de tabla uno-a-muchos. La tabla student
es el padre, y la student_grade
es la tabla hija ya que tiene una columna student_id
Foreign Key que hace referencia a la columna id
Primary Key de la tabla student
.
La tabla student
contiene los dos registros siguientes:
| id | first_name | last_name | admission_score ||----|------------|-----------|-----------------|| 1 | Alice | Smith | 8.95 || 2 | Bob | Johnson | 8.75 |
Y, la tabla student_grade
almacena las calificaciones que han recibido los alumnos:
| id | class_name | grade | student_id ||----|------------|-------|------------|| 1 | Math | 10 | 1 || 2 | Math | 9.5 | 1 || 3 | Math | 9.75 | 1 || 4 | Science | 9.5 | 1 || 5 | Science | 9 | 1 || 6 | Science | 9.25 | 1 || 7 | Math | 8.5 | 2 || 8 | Math | 9.5 | 2 || 9 | Math | 9 | 2 || 10 | Science | 10 | 2 || 11 | Science | 9.4 | 2 |
SQL EXISTS
Digamos que queremos obtener todos los alumnos que han recibido una calificación de 10 en la clase de Matemáticas.
Si sólo nos interesa el identificador del alumno, entonces podemos ejecutar una consulta como esta:
SELECT student_grade.student_idFROM student_gradeWHERE student_grade.grade = 10 AND student_grade.class_name = 'Math'ORDER BY student_grade.student_id
Pero, la aplicación está interesada en mostrar el nombre completo de un alumno, no sólo el identificador, por lo que necesitamos información de la tabla student
también.
Para filtrar los registros de la tabla student
que tienen una calificación de 10 en Matemáticas, podemos utilizar el operador SQL EXISTS, así:
SELECT id, first_name, last_nameFROM studentWHERE EXISTS ( SELECT 1 FROM student_grade WHERE student_grade.student_id = student.id AND student_grade.grade = 10 AND student_grade.class_name = 'Math')ORDER BY id
Al ejecutar la consulta anterior, podemos ver que sólo se selecciona la fila Alice:
| id | first_name | last_name ||----|------------|-----------|| 1 | Alice | Smith |
La consulta externa selecciona las columnas de la fila student
que nos interesa devolver al cliente. Sin embargo, la cláusula WHERE está utilizando el operador EXISTS con una subconsulta interna asociada.
El operador EXISTS devuelve true
si la subconsulta devuelve al menos un registro y false
si no se selecciona ninguna fila. El motor de la base de datos no tiene que ejecutar la subconsulta por completo. Si se encuentra un solo registro, el operador EXISTS devuelve true
, y se selecciona la otra fila de la consulta asociada.
La subconsulta interna está correlacionada porque la columna student_id
de la tabla student_grade
coincide con la columna id
de la tabla externa student
.
SQL NOT EXISTS
Consideremos que queremos seleccionar todos los alumnos que no tengan una calificación inferior a 9. Para ello, podemos utilizar NOT EXISTS, que niega la lógica del operador EXISTS.
Por tanto, el operador NOT EXISTS devuelve true
si la subconsulta subyacente no devuelve ningún registro. Sin embargo, si la subconsulta interna coincide con un solo registro, el operador NOT EXISTS devolverá false
, y la ejecución de la subconsulta puede detenerse.
Para hacer coincidir todos los registros student
que no tengan asociado student_grade
con un valor inferior a 9, podemos ejecutar la siguiente consulta SQL:
SELECT id, first_name, last_nameFROM studentWHERE NOT EXISTS ( SELECT 1 FROM student_grade WHERE student_grade.student_id = student.id AND student_grade.grade < 9)ORDER BY id
Al ejecutar la consulta anterior, podemos ver que sólo coincide el registro de Alice:
| id | first_name | last_name ||----|------------|-----------|| 1 | Alice | Smith |
Genial, ¿verdad?
Talleres online
Si te ha gustado este artículo, ¡apuesto a que te va a encantar mi próximo taller online de 4 días!
- Alto-Performance Java Persistence Online Workshop (4 horas x 4 días) entre el 19 y el 22 de abril
Conclusión
La ventaja de utilizar los operadores SQL EXISTS y NOT EXISTS es que la ejecución de la subconsulta interna puede detenerse siempre que se encuentre un registro coincidente.
Si la subconsulta requiere escanear un gran volumen de registros, detener la ejecución de la subconsulta tan pronto como se encuentre un solo registro coincidente puede acelerar en gran medida el tiempo de respuesta global de la consulta.