La unión interna de MySQL es demasiado larga.
Mi esquema es el siguiente:
Tabla A
id
fieldA1
fieldA2
fieldA3
fieldA4
Tabla B
id
fieldB1
fieldB2
fieldB3
fieldB4
La particularidad es que la tabla A tiene alrededor de 100,000 entradas y la tabla B tiene alrededor de 5,000,000 de entradas. Ambas tablas tienen el mismo número de ID distintos (100,000). Hay 5,000,000 combinaciones distintas para (ID, fieldB2) en la tabla B.
Quiero hacer una consulta que seleccione campos de ambas tablas y devuelva un máximo de 100,000 resultados (uno por ID, o menos dependiendo del filtro, que puede ser cualquier campo de la tabla A o B excepto fieldB2).
Como hay varias filas para cada ID de la tabla B, no me importa qué valor se devuelva, pero debe ser rápido (es decir, por ejemplo, para fieldB3 quiero cualquier valor para field3 asociado a un dispositivo). La única excepción es para el fieldB1, para el cual quiero la lista de todos los valores existentes para cada ID en el resultado. Si el rendimiento es malo para obtener la lista, puedo hacer una segunda solicitud más tarde solo para este punto, por lo que en mi investigación aún no he intentado obtener esta lista.
Lo que he intentado es:
select distinct id, fieldB1, fieldB2, fieldB3, fieldB4
from B
where id IN (SELECT id from A where fieldA1 > 0);
Y esto:
select distinct B.id, fieldB1, fieldB2, fieldB3, fieldB4, fieldA2, fieldA3, fieldA4 from B
INNER JOIN (SELECT id from A where fieldA1 > 0) ON A.id = B.id;
La consulta tarda más de 5 segundos (ambas). Sin el distinct, la consulta es solo ~ 10% más rápida.
Tengo 3 índices:
– uno en ID (tabla A)
– uno en ID (tabla B)
– uno en fieldA1 (tabla A)
¿Hay alguna forma de hacer esta consulta más rápido? (¿sin la lista de agregación para fieldB1 al menos?)
davy.ai
Hay algunas optimizaciones potenciales que se pueden realizar en las consultas proporcionadas. Un enfoque es utilizar una subconsulta para obtener los valores distintos de
id
deA
antes de unirse conB
, como sigue:Esta consulta primero selecciona los valores distintos de
id
deA
que cumplen los criterios de filtro deseados. Luego une estos valores deid
conB
en función de la columnaid
, y selecciona las columnas deseadas de ambas tablas. Para asegurarse de que se devuelva solo una fila porid
, el conjunto de resultados se agrupa por la columnaid
(lo que se puede optimizar creando un índice en esta columna).Otro enfoque es utilizar una subconsulta correlacionada para seleccionar solo una fila de
B
para cada valor deid
. La siguiente consulta demuestra este enfoque:Esta consulta utiliza una unión izquierda en lugar de una unión interna para asegurarse de que todos los valores de
id
deA
estén incluidos en el conjunto de resultados, incluso si no hay filas coincidentes enB
. Para obtener la lista de valores distintos defieldB_1
para cadaid
, la consulta utiliza la funciónGROUP_CONCAT
dentro de una subconsulta, agrupando por la columnaid
. Para las columnas restantes, la consulta selecciona el valor máximo para cada una, que puede ser arbitrario ya que los valores para cadaid
no están especificados. El conjunto de resultados se agrupa por la columnaid
para asegurarse de que se devuelva solo una fila porid
.En general, el segundo enfoque puede ser más rápido ya que evita la necesidad de una operación distinta y puede aprovechar la unión izquierda para incluir todos los valores de
id
deA
. Dependiendo de la distribución de datos específica y del plan de ejecución de la consulta, puede ser útil crear índices adicionales en las columnasfieldB_2
,fieldB_3
yfieldB_4
enB
para mejorar el rendimiento.