¡Optimizar una PEAZO Query SQL! :(

bLaKnI

Buenas a todos!
Tengo un monstruito de query (MySQL) que se usa basicamente para un motor de búsqueda web, es decir, el tipico "input" en el que el usuario escribe una palabra, y se buscan todos los resultados posibles buscando dicha palabra en varios campos de diversas tamblas.

La query es algo como lo que sigue (lo pongo con letras y nombres sin importancia, pues es meramente ejemplificativa):

SELECT *
FROM aaa l
LEFT JOIN bbb ls ON(l.x = ls.x)
LEFT JOIN ccc s ON(ls.y = s.y)
LEFT JOIN ddd a ON(s.z = a.z)
LEFT JOIN eee ep ON(l.w = ep.ww OR l.w = ep.www)
LEFT JOIN fff p ON(ep.k = p.k)
WHERE l.a LIKE '%temp%' OR l.b LIKE '%temp%' OR l.c LIKE '%temp%' OR l.d LIKE '%temp%' OR l.e LIKE '%temp%' OR l.f LIKE '%temp%' OR l.g LIKE '%temp%' OR l.h LIKE '%temp%'
OR s.i LIKE '%temp%'
OR a.j LIKE '%temp%'
OR p.k LIKE '%temp%';

Necesito optimizar esto, porque directamente, ni acaba. No se ni cuanto dura, porque he tenido que pararlo.
Ya se evidentemente que eso dura la muerte, pues no hay indices, ni views ni nada. Así que este es el monstruo virgen, y hay que caparlo.

El primer paso que haré, es el de seleccionar específicamente los campos por contra de SELECT *.

Lo siguiente, seria crear un indice para cada uno de los campos que aparecen en el Where?
Y finalmente, crear una view de dicha query?
Los like, son una putada, pero no puedo prescindir de ellos. A no se que use algo tipo indices FULLTEXT y use luego MATCH...

Eso es lo que iba ha hacer... ¿que hariais vosotros? Que se os ocurre?

Muchas gracias,

Saludos! :)

Gentoozo

Sin ver las tablas no te puedo ayudar mucho, pero intenta hacer subconsultas que muchas veces te acortan las consultas.

También recuerda que los indices fulltext son tus amigos (salvo que uses innodb en cuyo caso, no existen XD)

bLaKnI

Mierdas...
Las tablas son innodb!! :_(

En cuanto a las tablas, habria que intentar ordenar de menor a mayor cantidad de contenido... Eso tambien lo probaré.

Otra cosa, se me ocurre meter en la Join, las partes del WHERE respectivas mediante un AND. Es una buena metodologia? A veces salen resultados diferentes poniendo la parte en el JOIN mediante un AND que abajo en el WHERE... :S

SELECT *
FROM aaa l
LEFT JOIN bbb ls ON(l.x = ls.x)
LEFT JOIN ccc s ON(ls.y = s.y AND s.i LIKE '%temp%' )
LEFT JOIN ddd a ON(s.z = a.z AND a.j LIKE '%temp%' )
LEFT JOIN eee ep ON(l.w = ep.ww OR l.w = ep.www)
LEFT JOIN fff p ON(ep.k = p.k AND p.ll LIKE '%temp%' )
WHERE l.a LIKE '%temp%' OR l.b LIKE '%temp%' OR l.c LIKE '%temp%' OR l.d LIKE '%temp%' OR l.e LIKE '%temp%' OR l.f LIKE '%temp%' OR l.g LIKE '%temp%' OR l.h LIKE '%temp%';

Y en caso de subqueries, seria en las JOIN, no?
Es decir, hacer JOIN con rows sacadas de una subquery:

SELECT *
FROM ( SELECT * FROM aaa l WHERE l.a LIKE '%temp%' OR l.b LIKE '%temp%' OR l.c LIKE '%temp%' OR l.d LIKE '%temp%' OR l.e LIKE '%temp%' OR l.f LIKE '%temp%' OR l.g LIKE '%temp%' OR l.h LIKE '%temp%' ) as aaa
LEFT JOIN bbb ls ON(l.x = ls.x)
LEFT JOIN (SELECT * FROM ccc s WHERE s.i LIKE '%temp%' ) as ccc ON(ls.y = ccc.y)
LEFT JOIN (SELECT * FROM ddd a WHERE a.j LIKE '%temp%' ) as ddd ON(s.z = ddd.z)
LEFT JOIN eee ep ON(aaa.w = ep.ww OR aaa.w = ep.www)
LEFT JOIN (SELECT * FROM fff p WHERE p.k LIKE '%temp%' ) as fff p ON(ep.k = fff.k);

Seria así el tema "subquery"?

Merci!

Beavis

Un recurso bastante común es crear una tabla MyISAM con un campo de texto con fulltext index en la que introduces todos los posibles campos de búsqueda asociados a algo y es la que usas en las búsquedas. Requiere un extra de mantenimiento (actualizarla cada vez que edites los datos asociados) pero te ahorra consultas infumables como esa.

Gentoozo

Muy buena la idea de Beavis.

Sobre lo de las subconsultas, yo siempre las meto en el WHERE.

bLaKnI

Pero si poner las subqueries en el WHERE, es que usas un EXISTS o un IN/NOT IN...
Y el tema problematico aqui son las JOINS y los LIKE... Entonces no me sirve realmente para acortar... Como lo harias en el where así por encima, Gentoozo?

Y Beavis, lo tuyo me parece muy muy sexy, xD
Pero no entiendo muy bien la estructura de la tabla.

Seria una tabla MyISAM de 1 sola columna? Y cuantas filas? Tantas como resultados daria la query inicial de #1 en el caso de terminar? Y cada fila de 1 sola columna que contendria? Cada campo concatenado digamos?

Tabla MYISAM:

VALORES_CONCAT
nombre,titulo,apellido1,ISBN,palabras_clave
nombre,titulo,apellido1,ISBN,palabras_clave
nombre,titulo,apellido1,ISBN,palabras_clave
nombre,titulo,apellido1,ISBN,palabras_clave
nombre,titulo,apellido1,ISBN,palabras_clave
...
nombre,titulo,apellido1,ISBN,palabras_clave

hasta N?

Una sola columna VALORES_CONCAT en donde cada fila contiene una concatenacion de cada campo a buscar, y con tantas filas como daria la consulta en #1? Es eso?

Pero entonces, almenos una vez habria que lanzar la query de #1 para generar los contenidos de la tabla, no? Y no se ni cuanto tarda...

Puedes mas o menos explicarme como harias lo que has comentado porfavor?
Merci! ^^

Gentoozo

Yo la tabla de Beavis la veo así:

tabla_sexy

  • id
  • foreign_table (nombre de la tabla en la que está lo que buscamos)
  • foreign_key (clave de la fila en la que está lo que buscamos)
  • foreign_field (campo en la tabla externa en la que está lo que buscamos)
  • text (texto en el que buscar)

Lo de las subconsultas luego edito a ver si me sale XD

SiCk

Pero supongo que Beavis se refiere a que en "text" lo busques usando match.
http://dev.mysql.com/doc/refman/5.1/en/fulltext-search.html
http://devzone.zend.com/article/1304

Beavis

Yo me refería a una estructura bastante más simple, si estás buscando libros por ejemplo tendrías dos campos, uno con el identificador del libro y otro de texto (indexado con fulltext) donde meterías todo lo que sea susceptible a búsquedas relacionado con ese libro (nombre, descripción, ISBN, autor etc)
Esto es útil cuando tienes un único input de búsqueda que luego vas a buscar en varios sitios distintos y todos ellos están relacionados con la misma entidad (como en el ejemplo que tu has planteado) ya que con una consulta muy simple tendrías todos los resultados posibles y puedes usar búsquedas booleanas complejas.

El extra de mantenimiento supone que cada vez que edites la información relacionada con un determinado libro deberías actualizar su fila en la tabla de búsquedas, esto se podría hacer con triggers o hardcoded en la zona de administración de la aplicación, no creo que sea una buena idea generar esta tabla por completo a partir de búsquedas cuando tienes control total de cuando se modifica la información y puedes modificar la tabla acorde.

Es una solución relativamente simple para este caso concreto, está claro que algo así no va a resultar útil en muchos escenarios.

Usuarios habituales

  • Beavis
  • SiCk
  • Gentoozo
  • bLaKnI