Pregunta

Estoy trabajando en una consulta para un sitio de noticias, que encontrará contenido destacado para mostrar en la página de inicio principal. El contenido marcado de esta manera se etiqueta como 'Contenido destacado' y se ordena en una tabla destacada por 'página de inicio'. Actualmente tengo el resultado deseado, pero la consulta se ejecuta en más de 3 segundos, lo cual necesito reducir. ¿Cómo se optimiza una consulta como la que sigue?

EDITAR: materializó la vista cada minuto como se sugiere, hasta .4 segundos:

SELECT f.position, s.item_id, s.item_type, s.title, s.caption, s.date
FROM live.search_all s 
INNER JOIN live.tags t 
ON s.item_id = t.item_id AND s.item_type = t.item_type AND t.tag = 'FeaturedContent' 
LEFT OUTER JOIN live.featured f 
ON s.item_id = f.item_id AND s.item_type = f.item_type AND f.feature_type = 'homepage'
ORDER BY position IS NULL, position ASC, date

Esto muestra todas las funciones de la página de inicio en orden, seguidas de otro contenido destacado ordenado por fecha.
La explicación se ve así:

|-id---|-select_type-|-table-|-type---|-possible_keys---------|-key--------|-key_len-|-ref---------------------------------------|-rows--|-Extra-------------------------------------------------------------|
|-1----|-SIMPLE------|-t2----|-ref----|-PRIMARY,tag_index-----|-tag_index--|-303-----|-const-------------------------------------|-2-----|-Using where; Using index; Using temporary; Using filesort;--------|
|-1----|-SIMPLE------|-t-----|-ref----|-PRIMARY---------------|-PRIMARY----|-4-------|-newswires.t2.id---------------------------|-1974--|-Using index-------------------------------------------------------|
|-1----|-SIMPLE------|-s-----|-eq_ref-|-PRIMARY, search_index-|-PRIMARY----|-124-----|-newswires.t.item_id,newswires.t.item_type-|-1-----|-------------------------------------------------------------------|
|-1----|-SIMPLE------|-f-----|-index--|-NULL------------------|-PRIMARY----|-190-----|-NULL--------------------------------------|-13----|-Using index-------------------------------------------------------|

Y el perfil es el siguiente:

|-Status---------------|-Time-----|
|-starting-------------|-0.000091-|
|-Opening tables-------|-0.000756-|
|-System lock----------|-0.000005-|
|-Table lock-----------|-0.000008-|
|-init-----------------|-0.000004-|
|-checking permissions-|-0.000001-|
|-checking permissions-|-0.000001-|
|-checking permissions-|-0.000043-|
|-optimizing-----------|-0.000019-|
|-statistics-----------|-0.000127-|
|-preparing------------|-0.000023-|
|-Creating tmp table---|-0.001802-|
|-executing------------|-0.000001-|
|-Copying to tmp table-|-0.311445-|
|-Sorting result-------|-0.014819-|
|-Sending data---------|-0.000227-|
|-end------------------|-0.000002-|
|-removing tmp table---|-0.002010-|
|-end------------------|-0.000005-|
|-query end------------|-0.000001-|
|-freeing items--------|-0.000296-|
|-logging slow query---|-0.000001-|
|-cleaning up----------|-0.000007-|

Soy nuevo en la lectura de la salida EXPLAIN, por lo que no estoy seguro de tener un pedido mejor disponible o algo bastante simple que se pueda hacer para acelerarlos.

La tabla search_all es la tabla de vista materializada que se actualiza periódicamente, mientras que las etiquetas y las tablas destacadas son vistas. Estas vistas no son opcionales y no se pueden solucionar.

La vista de etiquetas combina etiquetas y una tabla relacional para obtener una lista de etiquetas según item_type y item_id, pero las otras vistas son vistas simples de una tabla.

EDITAR: Con la vista materializada, el mayor cuello de botella parece ser el paso "Copiar a la tabla temporal". Sin ordenar la salida, toma .0025 segundos (¡mucho mejor!) Pero la salida final necesita ser ordenada. ¿Hay alguna forma de mejorar el rendimiento de ese paso o evitarlo?

Lo siento si el formato es difícil de leer, soy nuevo y no estoy seguro de cómo se hace con regularidad.
¡Gracias por tu ayuda! Si necesita algo más, hágamelo saber.

EDITAR: Tamaños de tabla, como referencia:
Relaciones de etiqueta: 197,411
Etiquetas: 16,897
Historias: 51,801
Imágenes: 28,383
Videos: 2,408
Destacados: 13

¿Fue útil?

Solución

Creo que optimizar su consulta por sí solo no será muy útil. Los primeros pensamientos son que unirse a una subconsulta, en sí misma hecha de UNION, es solo un doble cuello de botella para el rendimiento.

Si tiene la opción de cambiar la estructura de su base de datos, entonces sugeriría fusionar las 3 tablas stories, images y videos en una, si son, como parece, muy similares (agregando un type ENUM('story', 'image', 'video')) para diferenciar los récords; esto eliminaría tanto la subconsulta como la unión.

Además, parece que sus vistas sobre stories y videos no utilizan un campo indexado para filtrar contenido. ¿Está consultando una columna indexada?

¡Es un problema bastante complicado sin conocer la estructura completa de su tabla y el reparto de sus datos!

Otra opción, que no implicaría realizar modificaciones a su base de datos existente (especialmente si ya está en producción), sería "almacenar en caché" esta información en otra tabla, que se actualizaría periódicamente mediante un trabajo cron.

El almacenamiento en caché se puede realizar en diferentes niveles, ya sea en la consulta completa o en subpartes de la misma (vistas independientes o las 3 uniones fusionadas en una sola tabla de caché, etc.)

La viabilidad de esta opción depende de si es aceptable mostrar datos ligeramente desactualizados o no. Puede ser aceptable solo para algunas partes de sus datos, lo que puede implicar que almacenará en caché solo un subconjunto de las tablas / vistas involucradas en la consulta.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top