Sei sulla pagina 1di 8

Abuso del distinct o group by.

EJERCICIO 1: Listado de clientes.


Dada la siguiente consulta de clientes: select distinct nif, apellidos, nombre, cn_sexo, cn_ec from clientes c, sexos s, estadosciviles e where c.sex_id_sexo = s.id_sexo and c.ec_id_ec = e.id_ec group by nif, nombre, apellidos, cn_sexo, cn_ec

Obtenemos los siguientes resultados: 1 ordenacin en memria 2 ordenacin en disco estimacin = 271 Coste Mediante el siguiente plan de ejecucin:
Execution Plan ---------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE (Cost=271 Card=9999 Bytes=649935) 1 0 SORT (GROUP BY) (Cost=271 Card=9999 Bytes=649935) 2 1 HASH JOIN (Cost=18 Card=9999 Bytes=649935) 3 2 MERGE JOIN (CARTESIAN) (Cost=6 Card=10 Bytes=170) 4 3 TABLE ACCESS (FULL) OF 'SEXOS' (Cost=2 Card=2 Bytes=14) 5 3 BUFFER (SORT) (Cost=4 Card=1 Bytes=10) 6 5 TABLE ACCESS (FULL) OF 'ESTADOSCIVILES' (Cost=2 Card=1 Bytes=10) 7 2 TABLE ACCESS (FULL) OF 'CLIENTES' (Cost=11 Card=9999 Bytes=479952)

Primer paso: Estudio del modelo de datos.

En este caso, dado el modelo, no existen NIF duplicados. Es, por tanto, innecesario realizar una ordenacin adicional para seleccionar los distintos. Tampoco existen clculos sobre subconjuntos (en este caso, cada registro sera un subconjunto) y la clusula GROUP BY tambin se est utilizando de forma inadecuada afectando en el coste de la ejecucin. Omitir una de las dos clusulas no ofrece ninguna mejora en la ejecucin. Incluso Oracle, en algunas ejecuciones, puede resolver planes idnticos. La solucin, por tanto, reside en eliminar GROUP BY y DISTINCT.
Execution Plan ---------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE (Cost=145 Card=9999 Bytes=649935) 1 0 SORT (UNIQUE) (Cost=145 Card=9999 Bytes=649935) 2 1 HASH JOIN (Cost=18 Card=9999 Bytes=649935) 3 2 MERGE JOIN (CARTESIAN) (Cost=6 Card=10 Bytes=170) 4 3 TABLE ACCESS (FULL) OF 'SEXOS' (Cost=2 Card=2 Bytes=14) 5 3 BUFFER (SORT) (Cost=4 Card=1 Bytes=10) 6 5 TABLE ACCESS (FULL) OF 'ESTADOSCIVILES' (Cost=2 Card=1 Bytes=10) 7 2 TABLE ACCESS (FULL) OF 'CLIENTES' (Cost=11 Card=9999 Bytes=479952)

El resultado de omitir estas clusulas innecesarias sera el siguiente: select nif, apellidos, nombre, cn_sexo, cn_ec from clientes c, sexos s, estadosciviles e where c.sex_id_sexo = s.id_sexo and c.ec_id_ec = e.id_ec

Con el siguiente plan de ejecucin:


Execution Plan ---------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE (Cost=18 Card=9999 Bytes=649935) 1 0 HASH JOIN (Cost=18 Card=9999 Bytes=649935) 2 1 MERGE JOIN (CARTESIAN) (Cost=6 Card=10 Bytes=170) 3 2 TABLE ACCESS (FULL) OF 'SEXOS' (Cost=2 Card=2 Bytes=14) 4 2 BUFFER (SORT) (Cost=4 Card=1 Bytes=10) 5 4 TABLE ACCESS (FULL) OF 'ESTADOSCIVILES' (Cost=2 Card=1 Bytes=10) 6 1 TABLE ACCESS (FULL) OF 'CLIENTES' (Cost=11 Card=9999 Bytes=479952)

1 ordenacin en memria 0 ordenacines en disco estimacin = 18 Coste

Abuso del distinct o group by.

EJERCICIO 2: Vuelos de una compaa con reservas.


Dada la siguiente consulta: select distinct c.CN_COMP compania, v.AER_ID_AERO origen, v.AER_ID_AERO_DESTINO destino from vuelos v, plazas p, reservas r, companias c where v.ID_VUELO=p.vue_id_vuelo and p.vue_id_vuelo=r.vue_id_vuelo and p.pla_id=r.pla_id_plaza and c.id_comp=v.comp_id_comp and c.cn_comp='Alitalia' O esta otra, con resultados idnticos: select c.CN_COMP compania, v.AER_ID_AERO origen, v.AER_ID_AERO_DESTINO destino from vuelos v, companias c, reservas r where id_vuelo in (select vue_id_vuelo from reservas where importe in (select max (importe) from reservas)) and v.comp_id_comp=c.id_comp and v.id_vuelo=r.vue_id_vuelo group by c.CN_COMP,v.AER_ID_AERO,v.AER_ID_AERO_DESTINO

Obtenemos los siguientes resultados: 43 segundos de ejecucin en devolver 1120 filas 17326 lecturas fsicas 1 ordenacin en memria 1 ordenacin en disco estimacin = 3495 Coste

Primer paso: Estudio del modelo de datos.

Cada PLAZA contiene la identificacin del VUELO. Por lo tanto, no es necesario recuperar los datos de las plazas para asociarlos a las reservas. Es preciso tener en cuenta que no se est visualizando informacin sobre las plazas, por lo que ese acceso podra omitirse. El resultado de este cambio produce la siguiente sentencia:
select distinct c.CN_COMP compania, v.AER_ID_AERO origen, v.AER_ID_AERO_DESTINO destino from vuelos v, reservas r, companias c where v.ID_VUELO=r.vue_id_vuelo and c.id_comp=v.comp_id_comp and c.cn_comp='Alitalia'

Obtenemos los siguientes resultados: 4 segundos de ejecucin en devolver 1120 filas 1302 lecturas fsicas 1 ordenacin en memria 0 ordenaciones en disco estimacin = 349 Coste

Segundo paso: Mejorar ordenaciones o evitar innecesarias.


La mejora en tiempos ha sido sustancial: de 47 segundos a 4 segundos. No obstante, estos tiempos pueden no resultar aceptables, por ejemplo, en entornos web o si se trata de un proceso a realizar en bucle. La clusula DISTINCT es imprescindible, ya que una compaa puede tener varios vuelos con el mismo trayecto y reservas en ambos. Para evitar ordenaciones, o mejorarlas en medida de lo posible, hay que prestar atencin a los ndices o a aquellas estructuras fsicas que puedan retornar los datos ordenados. Este es el plan de ejecucin de la sentencia anterior:
Execution Plan ---------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE (Cost=349 Card=578 Bytes=19074) 1 0 SORT (UNIQUE) (Cost=349 Card=578 Bytes=19074) 2 1 HASH JOIN (Cost=254 Card=21389 Bytes=705837) 3 2 HASH JOIN (Cost=48 Card=7214 Bytes=209206) 4 3 TABLE ACCESS (FULL) OF 'COMPANIAS' (Cost=2 Card=1 Bytes=14) 5 3 TABLE ACCESS (FULL) OF 'VUELOS' (Cost=43 Card=57711 Bytes=865665) 6 2 INDEX (FAST FULL SCAN) OF 'RES_PK' (UNIQUE) (Cost=82 Card=171113 Bytes=684452)

En este plan de ejecucin, la ordenacin de la clusula DISTINCT se realiza sobre una cardinalidad de 578 y, por este motivo, el coste estimado se incrementa en 100. Podemos tambin advertir que el ndice RES_PK con el cdigo del vuelo y el de la plaza, pueden ayudar a que el subconjunto de registros se procese de forma ordenada por vuelos. De esta forma, la consulta transmite al optimizador que recupere los vuelos mediante el ndice nico, de modo que la cardinalidad queda reducida a 1.
select distinct c.CN_COMP compania, v.AER_ID_AERO origen, v.AER_ID_AERO_DESTINO destino from vuelos v, companias c where v.id_vuelo in (select r.vue_id_vuelo from reservas r where r.vue_id_vuelo=v.id_vuelo) and c.id_comp=v.comp_id_comp and c.cn_comp='Alitalia'

Execution Plan ---------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE (Cost=256 Card=1 Bytes=33) 1 0 SORT (UNIQUE) (Cost=256 Card=1 Bytes=33) 2 1 HASH JOIN (Cost=254 Card=1 Bytes=33) 3 2 HASH JOIN (Cost=48 Card=7214 Bytes=209206) 4 3 TABLE ACCESS (FULL) OF 'COMPANIAS' (Cost=2 Card=1 Bytes=14) 5 3 TABLE ACCESS (FULL) OF 'VUELOS' (Cost=43 Card=57711 Bytes=865665) 6 2 INDEX (FAST FULL SCAN) OF 'RES_PK' (UNIQUE) (Cost=82 Card=171113 Bytes=684452)

Posiblemente la mejora no aparente un gran resultado, pero en volmenes muy grandes de filas, mejorar la cardinalidad en las ordenaciones puede evitar un impacto en los costes. Este es el resultado: 3 segundos de ejecucin en devolver 1120 filas 1302 lecturas fsicas 1 ordenacin en memria 0 ordenaciones en disco estimacin = 256 Coste

SQL> select distinct c.CN_COMP compania, 2 v.AER_ID_AERO origen, 3 v.AER_ID_AERO_DESTINO destino 4 from vuelos v, companias c 5 where v.id_vuelo in (select r.vue_id_vuelo 6 from reservas r 7 where r.vue_id_vuelo=v.id_vuelo) 8 and c.id_comp=v.comp_id_comp 9 and c.cn_comp='Alitalia' 10 ; COMPANIA -----------------------------Alitalia Alitalia Alitalia Alitalia Alitalia Alitalia Alitalia Alitalia Alitalia Alitalia Alitalia ... 1120 filas seleccionadas. Transcurrido: 00:00:03.08 ORI --BCN BCN BCN BCN BCN BCN BCN BCN BCN BCN BCN DES --BLB BLC BON BOS BRL CHI DNV ESX FLO HEA LAN

Resumen de la prctica.

Es preciso prestar atencin al uso del DISTINCT y GROUP BY. Estas clusulas implican ordenaciones y el conjunto de registros debe reducirse al mnimo. El uso de GROUP BY debera reducirse, nicamente, y para evitar confusiones, cuando sea necesario agrupar resultados para aplicar una funcin de grupo. La informacin debe consultarse en la fuente apropiada. La consulta de ciudades distintas en clientes no mostrar todas las ciudades del modelo, sino nicamente las que tienen clientes. Es comn su uso en reduccin de resultados duplicados a causa de una mala combinacin de las tablas. Si dos tablas no estn combinadas, Oracle resuelve un producto cartesiano y, sin embargo, el uso de DISTINCT o GROUP BY ocultar el error en el filtro de resultados.

SQL> r 1 select distinct c.CN_COMP compania, 2 v.AER_ID_AERO origen, 3 v.AER_ID_AERO_DESTINO destino 4 from vuelos v, companias c, reservas r 5 where v.id_vuelo in (select r.vue_id_vuelo 6 from reservas r 7 where r.vue_id_vuelo=v.id_vuelo) 8 and c.id_comp=v.comp_id_comp 9* and c.cn_comp='Alitalia'

Esta consulta, que contiene un producto cartesiano por error a causa de omitirse una join, ha tardado 1 hora y :13 minutos en resolver las mismas 1120 filas anteriores. Para reducir los costes de ordenacin, puede resultar til reducir la cardinalidad mediante el uso de estructuras que procesen los registros de forma ordenada tales como ndices, clusters o tablas IOT.

Potrebbero piacerti anche