Acabo de configurar un sistema de registro que consta de varias tablas con el mismo diseño.
Hay una tabla para cada fuente de datos.
Para el visor de registros, quiero
- UNION todas las tablas de registro ,
- filtrarlos por cuenta ,
- agregue una pseudo columna para la identificación de la fuente,
- ordenarlos por tiempo ,
- y limitarlos a la paginación .
Todas las tablas contienen un campo llamado zeitpunkt
que es una columna de fecha / hora indexada.
Mi primer intento fue:
(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt AS zeit,
'hp' AS source FROM is_log AS l WHERE l.account_id = 730)
UNION
(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt,
'ig' AS source FROM ig_is_log AS l WHERE l.account_id = 730)
ORDER BY zeit DESC LIMIT 10;
El optimizador no puede usar los índices aquí porque todas las filas de ambas tablas son devueltas por las subconsultas y ordenadas después de UNION
.
Mi solución fue la siguiente:
(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt AS zeit,
'hp' AS source FROM is_log AS l WHERE l.account_id = 730
ORDER BY l.zeitpunkt DESC LIMIT 10)
UNION
(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt,
'ig' AS source FROM ig_is_log AS l WHERE l.account_id = 730
ORDER BY l.zeitpunkt DESC LIMIT 10)
ORDER BY zeit DESC LIMIT 10;
Esperaba que el motor de consultas usara los índices aquí ya que ambas subconsultas deberían estar ordenadas y limitadas antes de la UNION
, que luego combina y ordena las filas.
Realmente pensé que sería así, pero ejecutar EXPLAIN
la consulta me dice que las subconsultas aún buscan en ambas tablas.
EXPLAINing
las subconsultas mismas me muestran la optimización deseada pero UNIONing
juntas no lo hacen.
¿Me he perdido algo?
Sé que las ORDER BY
cláusulas dentro de las UNION
subconsultas se ignoran sin a LIMIT
, pero hay un límite.
Editar: en
realidad, probablemente también habrá consultas sin laaccount_id
condición.
Las tablas ya existen y están llenas de datos. Puede haber cambios en el diseño dependiendo de la fuente, por lo que quiero mantenerlos divididos. Además, los clientes de registro utilizan diferentes credenciales por una razón.
Tengo que mantener una especie de capa entre los lectores de registro y las tablas reales.
Aquí están los planes de ejecución para toda la consulta y la primera subconsulta, así como el diseño de la tabla en detalle:
(account_id, zeitpunkt)
. ¿Tienes ese índice? El segundo mejor sería (creo) el sencillo(zeitpunkt)
, pero la eficiencia si se usa depende de la frecuencia con la queaccount_id=730
aparecen las filas .UNION DISTINCT
? No es necesario forzar una ordenación distinta, ya que los resultados serán diferentes entre las subconsultas, debido a la columna de identificación adicional. UsoUNION ALL
.source
columna? De esta manera, podría evitarUNION
sy usar índices en todos sus datos.UNION ALL
produce un plan de ejecución diferente.Respuestas:
Solo por curiosidad, ¿puedes probar esta versión? Puede engañar al optimizador para que use los mismos índices que las subconsultas usarían por separado:
Sigo pensando que el mejor índice que podrías tener es el compuesto
(account_id, zeitpunkt)
. Produciría las 10 filas rápidamente, y no se necesitarían trucos.fuente
log entries / user
escala el número de usuarios y la cantidad de usuarios .account_id=?
, conserve ambas.SELECT * FROM
engaña a MySQL para que use los índices?(SELECT ...) AS a
, intenta evaluar y optimizar la tabla derivada por separado de las otras tablas derivadas y luego toda la consulta.force index
le dará una mejor solución.