Muchas veces nos topamos con la tarea de saber cuales valores de cierta columna(s) son distintos de un conjunto de registros.
Normalmente lo hacemos con la clausula distinct, pues nos ahorra un par de palabras a la hora de escribir el query. Algo como:
select distinct(firstname) from test
Pero el mismo resultado obtenemos si lo hacemos de la siguiente forma:
select firstname from test group by firstname
Entonces, ¿cuál es la diferencia? La diferencia es que con una cantidad considerable de registros, podríamos reducir hasta 1 segundo en el query. Veámoslo con un ejemplo:
Tenemos la tabla test con los siguientes datos (Mostraré solo una parte de la tabla, para ver todos los datos vean el script):
Nombre | codigo1 | codigo2 | codigo3 |
Juan | 2565368308 | 35763 | |
Juan | 87728636342562659891 | 2565188276 | 35801 |
Mohamad | 25653346402565334648 | 2565334647 | 35801 |
Joel | 2059330320 | 2059336400 | 35205 |
William | 2058700123 | 2058700227 | 35209 |
William | 2059789339 | 2058700227 | 35594 |
William | 2058700123 | 2058700227 | 35202 |
Elia | 2516079797 | 2058700227 | 36608 |
Elia | 2516079797 | 2516390940 | 36532 |
Elia | 2516079797 | 2516390940 | 36608 |
Elia | 2516079797 | 2516390940 | 36545 |
Esta tabla tiene 100 registros y cuando hacemos un DISTINCT sobre la columna firstname el query tarda 110ms en promedio
mientras si lo hacemos con GROUP BY 93 ms. ¿17 ms se preguntarán? Pero si eso sucede con 100 registros y sin nadie más usando la BD, imagínense lo significativo que es el cambio con 2 millones de registros y varias personas haciendo el mismo query al mismo tiempo.
¿A que se debe la diferencia?
Si vemos el plan de ejecución podríamos observar lo siguientes:
-- query con DISTINCT
'Unique (cost=37.41..39.91 rows=200 width=32) (actual time=0.380..0.462 rows=49 loops=1)'
' -> Sort (cost=37.41..38.66 rows=500 width=32) (actual time=0.379..0.409 rows=100 loops=1)'
' Sort Key: firstname'
' -> Seq Scan on test (cost=0.00..15.00 rows=500 width=32) (actual time=0.015..0.093 rows=100 loops=1)'
'Total runtime: 0.495 ms'
Aquí el costo de hacer un recorrido secuencial y luego sort, unique es el que aumenta en total el tiempo de ejecución, mientras
-- Haciendo un query con GROUP BY
'HashAggregate (cost=16.25..18.25 rows=200 width=32) (actual time=0.145..0.165 rows=49 loops=1)'
' -> Seq Scan on test (cost=0.00..15.00 rows=500 width=32) (actual time=0.013..0.052 rows=100 loops=1)'
'Total runtime: 0.201 ms'
Se realiza un recorrido secuencial pero se utiliza una función Hash que es más rápida que el sort y el unique.
Así que aunque nos lleve un poco más de tiempo escribir un query con GROUP BY, vamos a recuperarlo cada vez que se ejecute dicho query.
Bueno, pues, una vez más, espero que les sirva y hasta la próxima.
Por cierto, esperen una oleada de artículos entre hoy y mañana pues vamos tratar de subir el nivel del Blog.