sql >> Base de Datos >  >> RDS >> Mysql

¿Cómo implementar un sistema de etiquetado similar a SO en php/mysql?

Antes de entrar en optimización prematura modo, puede ser útil mirar en la siguiente plantilla de consulta. Por lo menos, esto podría usarse como una línea de base contra la cual se puede medir la efectividad de las posibles optimizaciones.

SELECT T.Tagid, TagInfo.TagName,  COUNT(*)
FROM Items I
JOIN Tags TagInfo ON TagInfo.TagId = T.TagId
JOIN ItemTagMap T  ON I.ItemId = T.ItemId 
--JOIN ItemTagMap T1 ON I.ItemId = T1.ItemId
WHERE I.ItemId IN
  (
      SELECT ItemId 
      FROM Items
      WHERE   -- Some typical initial search criteria
         Title LIKE 'Bug Report%'   -- Or some fulltext filter instead...
         AND  ItemDate > '02/22/2008'
         AND  Status = 'C'
  )
--AND T1.TagId = 'MySql'
GROUP BY T.TagId, TagInfo.TagName
ORDER BY COUNT(*) DESC

La subconsulta es la "consulta de conducción", es decir, la correspondiente a los criterios iniciales del usuario final. (Consulte a continuación para obtener detalles sobre cómo esta consulta, requerida varias veces, puede encajar en un flujo optimizado general) Se comenta JOIN en T1 (y posiblemente T2, T3, cuando se seleccionan varias etiquetas) y, con la cláusula WHERE, el asociado criterios. Estos son necesarios cuando el usuario selecciona una etiqueta en particular, ya sea como parte de la búsqueda inicial o por refinamiento. (Puede ser más eficiente colocar estas uniones y cláusulas where dentro de la subconsulta; más sobre esto a continuación)

Discusión... La "consulta de conducción", o una variación de la misma, se necesita para dos propósitos distintos:

  • 1 para proporcionar el completo lista de ItemId que se necesita para enumerar todas las etiquetas asociadas.

  • 2 para proporcionar los primeros N valores de ItemId (N es el tamaño de la página de visualización), con el fin de buscar información detallada del artículo en la tabla de artículos.

Tenga en cuenta que no es necesario ordenar la lista completa (o puede ser útil ordenarla en un orden diferente), por lo que la segunda lista debe ordenarse en función de la elección del usuario (por ejemplo, por fecha, de forma descendente o por título, en orden alfabético ascendente). ). También tenga en cuenta que si se requiere algún orden de clasificación, el costo de la consulta implicará tratar con la lista completa (por debajo de la optimización extraña por parte de SQL mismo y/o alguna desnormalización, SQL necesita "ver" los últimos registros en esa lista , en caso de que pertenezcan a la parte superior, por orden).

Este último hecho, está a favor de tener la misma consulta para ambos propósitos, la lista correspondiente puede almacenarse en una tabla temporal. El flujo general sería buscar rápidamente los N registros de elementos principales con sus detalles y devolverlos a la aplicación de inmediato. Luego, la aplicación puede obtener ajax-fashion la lista de etiquetas para refinamientos. Esta lista se produciría con una consulta similar a la anterior, donde la subconsulta se reemplaza por "select * from temporaryTable". Hay buenas probabilidades de que el optimizador de SQL decida ordenar esta lista (en algunos casos), dejemos que lo haga, en lugar de adivinarlo y ordenarlo explícitamente.

Otro punto a considerar es tal vez traer las uniones en la tabla ItemTagMap dentro de la "consulta de conducción" en lugar de como se muestra arriba. Probablemente sea mejor hacerlo, tanto por el rendimiento como porque producirá la lista correcta para el propósito #2 (mostrar una página de elementos).

La consulta/flujo descrito anteriormente probablemente escalará bastante bien, incluso en hardware relativamente modesto; tentativamente en más de 1/2 millón de elementos, con búsquedas de usuarios sostenidas tal vez hasta 10 por segundo. Uno de los factores clave sería la selectividad de los criterios de búsqueda iniciales.

Ideas de optimización

  • [Dependiendo de los casos de búsqueda típicos y de las estadísticas de datos] puede tener sentido desnormalizar trayendo (de hecho duplicando) algunos de los campos de los elementos a la tabla ItemTagMap. Los campos cortos en particular pueden ser 'bienvenidos' allí.
  • A medida que los datos crecen en más de un millón de elementos, podríamos explotar la fuerte correlación típica de algunas etiquetas (por ejemplo, en SO, PHP a menudo viene con MySql, por cierto, a menudo sin una buena razón...), con varios trucos. Por ejemplo, la introducción de TagIds de "etiquetas múltiples" podría hacer que la lógica de entrada sea un poco más complicada, pero también podría reducir significativamente el tamaño del mapa.


-- '¡Basta ya! --
Se debe seleccionar la arquitectura y las optimizaciones apropiadas a la luz de los requisitos reales y del perfil estadístico de datos efectivo...