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

¿Cómo implementar la búsqueda de 2 datos de tabla diferentes?

Aquí hay algunas "reglas del juego" que debe tener en cuenta para resolver este problema. Probablemente ya los conozca, pero indicarlos claramente puede ayudar a confirmarlos para otros lectores.

  • Todos los índices en MySQL pueden hacer referencia solo a columnas en una sola tabla base. No puede crear un índice de texto completo que indexe varias tablas.
  • No puede definir índices para vistas, solo tablas base.
  • Un MATCH() la consulta en un índice de texto completo debe coincidir con todas las columnas del índice de texto completo, en el orden declarado en el índice.

Crearía una tercera tabla para almacenar el contenido que desea indexar. No es necesario almacenar este contenido de forma redundante:guárdelo únicamente en la tercera tabla. Esto toma prestado un concepto de una "superclase común" del diseño orientado a objetos (en la medida en que podamos aplicarlo al diseño RDBMS).

CREATE TABLE Searchable (
  `id` SERIAL PRIMARY KEY,
  `title` varchar(100) default NULL,
  `description` text,
  `keywords` text,
  `url` varchar(255) default '',
  FULLTEXT KEY `TitleDescFullText` (`keywords`,`title`,`description`,`url`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE `shopitems` (
  `id` INT UNSIGNED NOT NULL,
  `ShopID` INT UNSIGNED NOT NULL,
  `ImageID` INT UNSIGNED NOT NULL,
  `pricing` varchar(45) NOT NULL,
  `datetime_created` datetime NOT NULL,
  PRIMARY KEY (`id`),
  FOREIGN KEY (`id`) REFERENCES Searchable (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE `shops` (
  `id` INT UNSIGNED NOT NULL,
  `owner_id` varchar(255) default NULL,
  `datetime_created` datetime default NULL,
  `created_by` varchar(255) default NULL,
  `datetime_modified` datetime default NULL,
  `modified_by` varchar(255) default NULL,
  `overall_rating_avg` decimal(4,2) default '0.00',
  PRIMARY KEY (`id`),
  FOREIGN KEY (`id`) REFERENCES Searchable (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Observe que la única tabla con una clave de incremento automático ahora es Searchable . Las mesas shops y shopitems utilice una clave con un tipo de datos compatible, pero sin incremento automático. Por lo tanto, debe crear una fila en Searchable para generar el id valor, antes de poder crear la fila correspondiente en cualquiera de las shops o shopitems .

He añadido FOREIGN KEY declaraciones con fines ilustrativos, aunque MyISAM ignorará silenciosamente estas restricciones (y ya sabe que debe usar MyISAM para tener soporte para la indexación de texto completo).

Ahora puedes buscar el contenido textual de ambas shops y shopitems en una sola consulta, usando un solo índice de texto completo:

SELECT S.*, sh.*, si.*,
  MATCH(keywords, title, description, url) AGAINST('dummy') As score
FROM Searchable S
LEFT OUTER JOIN shops sh ON (S.id = sh.id)
LEFT OUTER JOIN shopitems si ON (S.id = si.id)
WHERE MATCH(keywords, title, description, url) AGAINST('dummy')
ORDER BY score DESC;

Por supuesto, para una fila dada en Searchable solo debe coincidir una tabla, ya sea tiendas o artículos de tienda, y estas tablas tienen columnas diferentes. Así que sh.* o si.* será NULL en el resultado. Depende de usted formatear la salida en su aplicación.

Un par de otras respuestas han sugerido usar Sphinx Search . Esta es otra tecnología que complementa a MySQL y agrega una capacidad de búsqueda de texto completo más sofisticada. Tiene un gran rendimiento para las consultas, por lo que algunas personas se han quedado encantadas con él.

Pero crear índices y, en especial, agregar a un índice de manera incremental es costoso. De hecho, actualizar un índice de Sphinx Search es tan costoso que la solución recomendada es crear un índice para datos archivados más antiguos y otro índice más pequeño para datos recientes que es más probable que se actualicen. Luego, cada búsqueda debe ejecutar dos consultas, en los dos índices separados. Y si sus datos no se prestan naturalmente al patrón de datos más antiguos que no cambian, es posible que no pueda aprovechar este truco de todos modos.

En cuanto a su comentario:aquí hay un extracto de la documentación de Sphinx Search sobre actualizaciones en vivo a un índice:

La idea es que, dado que es costoso actualizar un índice de Sphinx Search, su solución es hacer que el índice que actualice sea lo más pequeño posible. De modo que solo las publicaciones del foro más recientes (en su ejemplo), mientras que el historial más grande de publicaciones del foro archivadas nunca cambia, por lo que crea un segundo índice más grande para esa colección una vez. Por supuesto, si desea realizar una búsqueda, debe consultar ambos índices.

Periódicamente, digamos una vez a la semana, los mensajes "recientes" del foro se considerarían "archivados" y tendría que fusionar el índice actual de publicaciones recientes con el índice archivado y comenzar de nuevo con el índice más pequeño. Señalan que fusionar dos índices de Sphinx Search es más eficiente que volver a indexar después de una actualización de los datos.

Pero mi punto es que no todos los conjuntos de datos caen naturalmente en el patrón de tener un conjunto de datos archivados que nunca cambia, frente a datos recientes que se actualizan con frecuencia.

Tome su base de datos, por ejemplo:tiene tiendas y artículos de compras. ¿Cómo puede separarlos en filas que nunca cambian, en lugar de filas nuevas? Se debe permitir que cualquier tienda o producto en el catálogo actualice su descripción. Pero dado que eso requeriría reconstruir todo el índice de Sphinx Search cada vez que realiza un cambio, se convierte en una operación muy costosa. Tal vez ponga en cola los cambios y los aplique en un lote, reconstruyendo el índice una vez por semana. Pero intente explicar a los vendedores de la tienda por qué un cambio menor en la descripción de su tienda no entrará en vigencia hasta el domingo por la noche.