PHP - Reducir tiempo al buscar coincidencias en grandes consultas

 
Vista:
sin imagen de perfil

Reducir tiempo al buscar coincidencias en grandes consultas

Publicado por Julio (3 intervenciones) el 10/09/2014 20:26:33
Hola,
tengo un problema de rendimiento al buscar coincidencias.
Me explico.
Tengo unos proyectos y unos usuarios que pertenecen a los diferentes proyectos.
Los proyectos y usuarios comparten unas 30 categorías.

Entonces cuando creo un nuevo proyecto quiero buscar gente compatible con ese proyecto y busco de entre todos los usuarios las categorías compatibles y lo ordeno de mayor a menor número de categorías compatibles.

El problema viene que si ya tengo cerca de 2500 usuarios y buscar esas 30 categorías una a una a cada usuario pues son muuuchas consultas, cuando no había tantos usuarios no era un problema de tiempo de ejecución.

De momento lo he hago de la siguiente forma
Listo las categorías del proyecto y voy buscando coincidencias en cada uno de los usuarios y lo guardo en otra tabla.
Claro si tengo 20 categorías para buscar en 2500 usuarios son 50000 búsquedas, y si lo acaba haciendo puede tardar 15 o 30 minutos, cuando directamente no se queda colgado.

¿Habría una forma mas eficiente de hacerlo, sin usar tanto procesador?

Muchas gracias
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder
sin imagen de perfil
Val: 729
Bronce
Ha aumentado 1 puesto en PHP (en relación al último mes)
Gráfica de PHP

Buscar coincidencias

Publicado por Gonzalo (615 intervenciones) el 10/09/2014 20:43:16
hola
me imagino que por cada usuario haces una consulta categoria por categoria, si este es el caso entonces sobrecargas de consultas el servidor de sql.

yo tenia el mismo problema cuando trataba de localizar pagos no autorizados o que se habian capturado directo sin pasar por el sistema.

lo que hice fue cargar 2 listas, una con todos los pagos del mes y otra con todos los pagos autorizados por sistema ordenados por empleado y numero de cuenta (las 2 listas), en tehoria las 2 listas deben coincidir, asi que el primero de una lista debe coincidir con el primero de la segunda lista, si coincide doy movenext a los 2 punteros, sino entonces el menor en cualquiera de las 2 listas estaba mal y lo apartaba y solo en esa lista daba movenext, igual con los numeros de empleados, el numero menor se reportaba como registro no autorizado.

se redujo el tiempo de busqueda de 45 minutos a dos minutos solamente usando solo 2 consultas al servidor, debes tener cuidado ya que si ordenas la lista entonces entre mas columnas ordenes el servidor tarda mas tiempo en responder.

tal vez este metodo te pudiera ayudar, solo debes buscar cuales registros coinciden.

suerte.salu2.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil

Buscar coincidencias

Publicado por Julio (3 intervenciones) el 10/09/2014 23:30:06
Resumo lo que hago, a ver si se entiende.
1.- extraigo las categorias del proyecto
2.- con un for las recorro
3.- busco los usuarios que cumplen con cada categoria
4.- actualizo la tabla paralela de usuario que he creado previamente con el contador de categorias

[PHP]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// CATEGORIAS  *********************************
$categoria = $row_proyecto['categoriasproyecto']; // listado de categorias en un campo, del tipo: id1,id2,id14,id23
$categoriaoferta = explode(",",$categoria);        // separo las categorias
for ($j=0;$j<count($categoriaoferta);$j++)         // bucle para recorrer cada categorias sobre los usuarios
{
    mysql_select_db($database_basedatos, $basedatos);
    // busco todos los usuarios que cumplen con la categoria a buscar
    $query_usuarios = "SELECT * FROM usuarios WHERE categoriasusuario LIKE '%$categoriaoferta[$j]%'";
    $usuarios = mysql_query($query_usuarios, $basedatos) or die(mysql_error());
    $row_usuarios = mysql_fetch_assoc($usuarios);
 
    do {
        // previamente he metido a todos los usuarios en la tabla tabla_usuarios_categorias
        // y ahora actualizo los usuario que cumplen tienen esa categoria, sumo +1 al contador numerocategorias e introduzco el id de la categoria en idcategorias.
        $updateSQL = "UPDATE tabla_usuarios_categorias SET numerocategorias=numerocategorias+1, idcategorias=CONCAT(idcategorias, '$categoriaoferta[$j],') WHERE idusuario=$usuarios[idusurio]";
        mysql_select_db($database_basedatos, $basedatos);
        $Result1 = mysql_query($updateSQL, $basedatos) or die(mysql_error());
        } while ($row_usuarios = mysql_fetch_assoc($usuarios));
 
}    // fin de for ($j=0;$j<count($categoriaoferta);$j++)
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 729
Bronce
Ha aumentado 1 puesto en PHP (en relación al último mes)
Gráfica de PHP

Buscar coincidencias

Publicado por Gonzalo (615 intervenciones) el 11/09/2014 02:19:38
ok, olvidate del for, vamos a ver si esto funciona

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$categoria = $row_proyecto['categoriasproyecto']; // listado de categorias en un campo, del tipo: id1,id2,id14,id23
$categoriaoferta = split(",",$categoria); // separo las categorias, entiendo mejor como funciona split pero splode esta bien.
 
$query_usuarios = "SELECT * FROM usuarios "; // aqui inicia el problema, como pedir todos en una sola query
 
$clausulawhere=""; //inicio el clausulawhere como cadena vacia.
 
foreach($categoriaoferta as $i=>$v)
{
if($clausulawhere=="")
{
$clausulawhere= " WHERE (categoriasusuario LIKE '%$v%') "; // la primer condicion debe ser con where
}else
{
$clausulawhere= " or (categoriasusuario LIKE '%$v%') "; // las demas deben ser con Or
}
}
 
$query_usuarios.=$clausulawhere
 
// termina como "select * from x where (1) or (2) or (3) etc etc." puedes agregar un order by si lo consideras necesario
 
// agrega un echo($query_usuarios) para que veas como quedo.
 
$usuarios = mysql_query($query_usuarios, $basedatos) or die(mysql_error()); // listo, los pido todos en una sola orden
 
agregas un while(fetch assoc)  // para recorrer todo el resultado
{
y agregas el update
}

esta muy prolijo pero basicamente es la idea

espero sea de ayuda, suerte, salu2.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil

Buscar coincidencias

Publicado por Julio (3 intervenciones) el 11/09/2014 14:11:35
Muchas gracias Gonzalo,
lo reviso y te comento
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar