un conteo para cada combinación – optimización

RESULTADOS: He usado tres métodos:

  1. Tres consultas secundarias, 1 unirse en cada una (mina)
  2. Tres sub consultas, sin unión, filtrando con where (SlimsGhost)
  3. Triple unión (Solarflare)

He hecho algunas estadísticas con “explicar” y “perfilar”, lo que explica el trabajo que cada consulta debe hacer y los siguientes resultados no fueron sorprendentes: estadísticas

Resultados relativos:

  1. 100%
  2. 79%
  3. 1715%

    tres sub consultas con simple join tres sub consultas con where cláusula una consulta con triple unión

POSTE ORIGINAL

La idea es unir 4 tablas, utilizando el mismo PK cada vez y luego contar cuántas filas se otorgarán por separado.

La respuesta obvia es hacer cada unión … por separado con subconsultas.

¿Pero es posible hacerlo con una consulta? ¿Sería más eficiente?

select "LES CIGARES DU PHARAON" as "Titre", (select count( payalb.idPays) from album alb left join pays_album payalb using ( idAlb ) where alb.titreAlb = "LES CIGARES DU PHARAON") as "Pays", (select count( peralb.idPers) from album alb left join pers_album peralb using ( idAlb ) where alb.titreAlb = "LES CIGARES DU PHARAON") as "Personnages", (select count( juralb.idJur) from album alb left join juron_album juralb using ( idAlb ) where alb.titreAlb = "LES CIGARES DU PHARAON") as "Jurons" ; +------------------------+------+-------------+--------+ | Titre | Pays | Personnages | Jurons | +------------------------+------+-------------+--------+ | LES CIGARES DU PHARAON | 3 | 13 | 50 | +------------------------+------+-------------+--------+ 

filas de álbumes de mesa: 22

tabla pays_album rows: 45

tabla personnage_album filas: 100

mesa filas de juron_album: 1704

Esto es lo que intenté:

 select alb.titreAlb as "Titre", sum(case when alb.idAlb=payalb.idAlb then 1 else 0 end) "Pays", sum(case when alb.idAlb=peralb.idAlb then 1 else 0 end) "Personnages", sum(case when alb.idAlb=juralb.idAlb then 1 else 0 end) "Jurons" from album alb left join pays_album payalb using ( idAlb ) left join pers_album peralb using ( idAlb ) left join juron_album juralb using ( idAlb ) where alb.titreAlb = "LES CIGARES DU PHARAON" group by alb.titreAlb ; +------------------------+------+-------------+--------+ | Titre | Pays | Personnages | Jurons | +------------------------+------+-------------+--------+ | LES CIGARES DU PHARAON | 1950 | 1950 | 1950 | +------------------------+------+-------------+--------+ 

pero cuenta el número total de filas de la tabla completa, … (1950 = 3 * 13 * 50)

esquema: https://github.com/LittleNooby/gbd2015-2016/blob/master/tintin_schema.png

contenido de tablas: https://github.com/LittleNooby/gbd2015-2016/blob/master/tintin_description

Si quieres jugar para jugar con él:

db_init: https://github.com/LittleNooby/gbd2015-2016/blob/master/tintin_ok.mysql

Para fines de optimización, una buena regla general es unir menos, no más. De hecho, debe intentar unir las pocas filas que pueda con el menor número de filas que pueda. Con cualquier combinación adicional, multiplicará el costo en lugar de agregar el costo. Porque mysql básicamente generará una gran matriz multiplicada. Sin embargo, mucho de eso se optimiza mediante índices y otras cosas.

Pero para responder a su pregunta: en realidad es posible contar con una sola unión grande, suponiendo que las tablas tienen claves únicas y idalb es una clave única para el álbum. Entonces, y solo entonces, puedes hacerlo de manera similar a tu código:

 select alb.titreAlb as "Titre", count(distinct payalb.idAlb, payalb.PrimaryKeyFields) "Pays", count(distinct peralb.idAlb, peralb.PrimaryKeyFields) "Personnages", count(distinct juralb.idAlb, juralb.PrimaryKeyFields) "Jurons" from album alb left join pays_album payalb using ( idAlb ) left join pers_album peralb using ( idAlb ) left join juron_album juralb using ( idAlb ) where alb.titreAlb = "LES CIGARES DU PHARAON" group by alb.titreAlb 

donde PrimaryKeyFields representa los campos clave principales de las tablas unidas (debe buscarlas).

Distinct eliminará el efecto que las otras uniones tienen en el recuento. Pero desafortunadamente, en general, distinct no eliminará el efecto que las uniones tienen en el costo.

Aunque, si tiene índices que cubren todos los campos (idAlb + PrimaryKeyFields) de sus tablas, eso podría ser incluso tan rápido como la solución original (porque puede optimizar lo distinct para no hacer una clasificación) y se acercará a lo que usted estábamos pensando en (simplemente caminando a través de cada mesa / índice una vez). Pero en un szenario normal o peor, debería funcionar peor que una solución razonable (como la de SlimGhost), porque es dudoso que encuentre la estrategia óptima. Pero juega con eso y revisa las explicaciones (y publica los hallazgos), tal vez mysql haga algo loco.

En cuanto al “trabajo mínimo para la base de datos”, creo que lo siguiente sería una E / S correcta y menos lógica para su esquema. Sin embargo, entienda que NO PUEDE saber con certeza a menos que mire los planes de explicación (esperados y reales).

Aún así, recomiendo probar esto: solo accede a la tabla “alb” una vez, mientras que su consulta original necesitaría acceder a ella cuatro veces (una para buscar el registro del álbum “base” y luego tres más para las tres subconsultas).

 select alb.titreAlb as "Titre", (select count(*) from pays_album t2 where t2.idAlb = alb.idAlb) "Pays", (select count(*) from pers_album t2 where t2.idAlb = alb.idAlb) "Personnages", (select count(*) from juron_album t2 where t2.idAlb = alb.idAlb) "Jurons" from album alb where alb.titreAlb = "LES CIGARES DU PHARAON"