Foros del Web » Programación para mayores de 30 ;) » Bases de Datos General » Mysql »

Optimizar busqueda

Estas en el tema de Optimizar busqueda en el foro de Mysql en Foros del Web. Buenas! Tengo una tabla con la estructura siguiente: tabla Juegos-Campos: id-nombre-pjuego1-pjuego2-pjuego3-pjuego4 Y asi hasta 25 juegos. Lo que pretendo es saber según la puntuación de ...
  #1 (permalink)  
Antiguo 01/04/2013, 10:28
 
Fecha de Ingreso: mayo-2009
Mensajes: 232
Antigüedad: 14 años, 11 meses
Puntos: 3
Optimizar busqueda

Buenas!

Tengo una tabla con la estructura siguiente:

tabla Juegos-Campos: id-nombre-pjuego1-pjuego2-pjuego3-pjuego4

Y asi hasta 25 juegos.

Lo que pretendo es saber según la puntuación de cada juego en que posición se encuentra, el usuario en cuenstion.

Lo sabria hacer cargando toda la tabla con un select * from tabla, y entonces ir ordenando el array por cada uno de los juegos con un for.

Esa es mi duda, creo que asi sobrecargo innecesariamente la aplicacion, ademas deberia recoger como digo todos los usuarios para manejarlos en un array, y si hay miles...

La otra forma que pense seria haciendo un select juego1 where pjuego1 > puntuacionusuario, y contando el array resultante ya tendria la posicion.


Pero para ello deberia hacer un select para cada campo(juego).
  #2 (permalink)  
Antiguo 01/04/2013, 13:17
Colaborador
 
Fecha de Ingreso: enero-2007
Ubicación: México
Mensajes: 2.097
Antigüedad: 17 años, 3 meses
Puntos: 447
Respuesta: Optimizar busqueda

Hola phyronx:

No sé si entendí correctamente qué es lo que quieres hacer, pero bueno, si entendí bien creo que podrías hacer las cosas más simples haciendo algo como esto:

Código MySQL:
Ver original
  1. mysql> SELECT * FROM tabla;
  2. +------+--------+---------+---------+---------+---------+
  3. | id   | nombre | pjuego1 | pjuego2 | pjuego3 | pjuego4 |
  4. +------+--------+---------+---------+---------+---------+
  5. |    1 | uno    |       1 |       2 |       1 |       1 |
  6. |    2 | dos    |       2 |       3 |       0 |       4 |
  7. |    3 | tres   |       3 |       4 |       1 |       5 |
  8. |    4 | cuatro |       4 |       1 |       2 |       1 |
  9. |    5 | cinco  |       5 |       5 |       1 |       5 |
  10. +------+--------+---------+---------+---------+---------+
  11. 5 rows in set (0.00 sec)
  12.  
  13. mysql> SELECT
  14.     -> id, nombre, pjuego1, pjuego2, pjuego3, pjuego4,
  15.     -> pjuego1 + pjuego2 + pjuego3 + pjuego4 total_puntos
  16.     -> FROM tabla
  17.     -> ORDER BY total_puntos DESC;
  18. +------+--------+---------+---------+---------+---------+--------------+
  19. | id   | nombre | pjuego1 | pjuego2 | pjuego3 | pjuego4 | total_puntos |
  20. +------+--------+---------+---------+---------+---------+--------------+
  21. |    5 | cinco  |       5 |       5 |       1 |       5 |           16 |
  22. |    3 | tres   |       3 |       4 |       1 |       5 |           13 |
  23. |    2 | dos    |       2 |       3 |       0 |       4 |            9 |
  24. |    4 | cuatro |       4 |       1 |       2 |       1 |            8 |
  25. |    1 | uno    |       1 |       2 |       1 |       1 |            5 |
  26. +------+--------+---------+---------+---------+---------+--------------+
  27. 5 rows in set (0.00 sec)

Si esto no es lo que quieres obtener postea algunos datos de ejemplo y dinos qué salida es la que esperas.

Saludos
Leo.
  #3 (permalink)  
Antiguo 01/04/2013, 13:33
 
Fecha de Ingreso: mayo-2009
Mensajes: 232
Antigüedad: 14 años, 11 meses
Puntos: 3
Respuesta: Optimizar busqueda

Gracias leo por responder, pero no es esto exactamente.

Cogiendo de ejemplo la primera tabla que creaste, donde nombre seria el nombre del usuario, y tendria su puntuacion en cada juego, como pusiste.

Ahora, cogiendo el pjuego1, si quisiera saber en que posicion estoy respecto a las otras puntuaciones, haria un select pjuego1 from tabla, para luego gurdarlo en un array y recorrerlo hasta encontrar mi usuario, y esa seria la posicion que ocupo en el ranking. (Habiendo ordenado de mayor a menos ,claro).

Pues si necesito ver una lista con mi posicion en el ranking en todos los juegos, deberia hacer esto mismo con cada columna, osea una consulta por cada juego, o bien, cargar toda la tabla en un array y ir ordenandolo por cada campo y sacando posiciones.


El problema es ese, que si hay 4000 usuarios por ejemplo, recoger toda la tabla me parece exagerado, y por ello creo k es mejor realizar diferentes consultas, aunque aun asi acabas cargando toda la tabla..
  #4 (permalink)  
Antiguo 01/04/2013, 14:02
Colaborador
 
Fecha de Ingreso: enero-2007
Ubicación: México
Mensajes: 2.097
Antigüedad: 17 años, 3 meses
Puntos: 447
Respuesta: Optimizar busqueda

Hola de nuevo:

En mi post te pedía que si esto no es lo que esperabas como salida nos dijeras a partir de algunos datos de ejemplo qué es lo que esperabas como salida, ojo con eso. En ocasiones resulta más fácil entender lo que se quiere obtener con un ejemplo visual más que con una larga explicación.

Veamos si entendí correctamente. Más que los puntos lo que te interesa saber entonces es la posición en que te encuentras para cada juego correcto??? es decir, algo como esto:

Código MySQL:
Ver original
  1. mysql> SELECT id, nombre,
  2.     -> pjuego1,
  3.     -> ( SELECT COUNT(id) FROM tabla T2
  4.     ->   WHERE T2.pjuego1 >= T1.pjuego1) rank1
  5.     -> FROM tabla T1;
  6. +------+--------+---------+-------+
  7. | id   | nombre | pjuego1 | rank1 |
  8. +------+--------+---------+-------+
  9. |    1 | uno    |       1 |     5 |
  10. |    2 | dos    |       2 |     4 |
  11. |    3 | tres   |       3 |     3 |
  12. |    4 | cuatro |       4 |     2 |
  13. |    5 | cinco  |       5 |     1 |
  14. +------+--------+---------+-------+
  15. 5 rows in set (0.00 sec)

Es decir, por un lado presento los puntos que obtuve por cada juego y con una subconsulta obtengo cuántos jugadores existen con más puntos que yo, eso me da la posición.

Sin embargo, esta consulta puede tener problemas dependiendo de cómo tienes organizada tu información, observa lo que pasa con los datos que pongo para el juego 3:

Código MySQL:
Ver original
  1. mysql> SELECT id, nombre,
  2.     -> pjuego3,
  3.     -> ( SELECT COUNT(id) FROM tabla T2
  4.     ->   WHERE T2.pjuego3 >= T1.pjuego3) rank3
  5.     -> FROM tabla T1;
  6. +------+--------+---------+-------+
  7. | id   | nombre | pjuego3 | rank3 |
  8. +------+--------+---------+-------+
  9. |    1 | uno    |       1 |     4 |
  10. |    2 | dos    |       0 |     5 |
  11. |    3 | tres   |       1 |     4 |
  12. |    4 | cuatro |       2 |     1 |
  13. |    5 | cinco  |       1 |     4 |
  14. +------+--------+---------+-------+
  15. 5 rows in set (0.00 sec)

Observa que aquí estoy asignando puntos iguales para más de un jugador, esto se ve reflejado en el ranking, estrictamente hablando es correcto que el jugador 4 aparezca en primer lugar, pero los jugadores con 1 punto deberían aparecer en segundo, no en 4 como aparece... como te repito no sé como tienes almacenada tu información ni cómo haces la asignación de puntos. Si tienes algo parecido a lo que te pongo tendrías que hacer una consulta distinta, aunque no sería nada sencilla... si es así creo que hacerlo mediante programación sería más sencillo que obtener una consulta.

Saludos
Leo.
  #5 (permalink)  
Antiguo 01/04/2013, 14:23
 
Fecha de Ingreso: mayo-2009
Mensajes: 232
Antigüedad: 14 años, 11 meses
Puntos: 3
Respuesta: Optimizar busqueda

Perdon por no hacerme entender bien.

Lo pondre claro.

Tengo la siguiente tabla, pero con unos 40 juegos y miles de usuarios:

Código MySQL:
Ver original
  1. +------+--------+---------+-------+
  2. | id   | nombre | pcanicas | pcartas|
  3. +------+--------+---------+-------+
  4. |    1 | juan    |       154 |     521 |
  5. |    2 | marcos  |       378 |     378 |
  6. |    4 | silvia |       487 |     554 |
  7. |    5 | anna |       55 |     14 |
  8. +------+--------+---------+-------+

Cada jugador tiene una puntuacion en cada juego.

Yo soy Juan, y entro en la pagina de rankings. Allí se ordena cada juego por puntuacion.
Aqui se me listan la posicion que entoy en el rankin en cada juego por separado:

-----------------
Juan:

canicas, tu posicion es 3º
cartas, tu posicion es 1º
.
.
.

y asi sucesivamente.

Para calcular la posicion de todos los juegos por separado, la posicion individual dentro de cada juego, hay varias maneras, lo que necesito saber cual es la mejor de ellas.

- O hago un select para cada juego ordenando el resultado de mayor a menor, y buscando la posicion de juan.

- O cargo con una sola consulta toda la tabla, y por cada juego hago lo del ejemplo anterior, ordenar, buscar a juan..
  #6 (permalink)  
Antiguo 01/04/2013, 15:37
Colaborador
 
Fecha de Ingreso: enero-2007
Ubicación: México
Mensajes: 2.097
Antigüedad: 17 años, 3 meses
Puntos: 447
Respuesta: Optimizar busqueda

Hola de nuevo:

En realidad eso de ordenar y buscar al jugador es irrelevante, lo que tienes que hacer como te dije es contar el número de jugadores que tienen más puntos que el jugador en cuestión... Si observas el segundo ejemplo que pongo es justo lo que necesitas, presentando la información en forma de columnas:

Código MySQL:
Ver original
  1. mysql> SELECT * FROM juegos;
  2. +------+--------+----------+---------+
  3. | id   | nombre | pcanicas | pcartas |
  4. +------+--------+----------+---------+
  5. |    1 | juan   |      154 |     521 |
  6. |    2 | marcos |      378 |     378 |
  7. |    4 | silvia |      487 |     554 |
  8. |    5 | anna   |       55 |      14 |
  9. +------+--------+----------+---------+
  10. 4 rows in set (0.00 sec)
  11.  
  12. mysql> SELECT id, nombre,
  13.     -> ( SELECT COUNT(DISTINCT id) FROM juegos T2
  14.     ->   WHERE T2.pcanicas >= T1.pcanicas) rank_canicas,
  15.     -> ( SELECT COUNT(DISTINCT id) FROM juegos T2
  16.     ->   WHERE T2.pcartas >= T1.pcartas) rank_cartas
  17.     ->   FROM juegos T1
  18.     -> WHERE T1.nombre = 'juan';
  19. +------+--------+--------------+--------------+
  20. | id   | nombre | rank_canicas | rank_cartas   |
  21. +------+--------+--------------+--------------+
  22. |    1 | juan   |            3 |            2 |
  23. +------+--------+--------------+--------------+
  24. 1 row in set (0.00 sec)

Mucho ojo, en tu post pones en el rank de cartas como primero, sin embargo silvia tiene más puntos que juan... supongo que se trata simplemente de un error de dedo.

Ahora bien, también podrías obtener el resultado en forma de renglones, aunque la consulta es un poco más complicada.

Código MySQL:
Ver original
  1. mysql> SELECT "canicas", COUNT(DISTINCT id)
  2.     -> FROM juegos
  3.     -> WHERE pcanicas >= (SELECT pcanicas
  4.     ->                    FROM juegos
  5.     ->                    WHERE nombre = 'juan')
  6.     -> UNION
  7.     -> SELECT "cartas", COUNT(DISTINCT id)
  8.     -> FROM juegos
  9.     -> WHERE pcartas >= (SELECT pcartas
  10.     ->                    FROM juegos
  11.     ->                    WHERE nombre = 'juan');
  12. +---------+--------------------+
  13. | canicas | COUNT(DISTINCT id) |
  14. +---------+--------------------+
  15. | canicas |                  3 |
  16. | cartas  |                  2 |
  17. +---------+--------------------+
  18. 2 rows in set (0.00 sec)

Ambas consultas son bastante ineficientes por cierto, pero eso se debe a que desde mi punto de vista tienes un pésimo modelo de datos, pero bueno, puedes hacer la prueba para ver qué tanto se tardan en ejecutar estas consultas, o como lo planteas hacer cada consulta por separado, pero olvídate de eso de ordenar y buscar... simplemente cuenta el numero de jugadores con mayor puntuación.

Saludos
Leo.
  #7 (permalink)  
Antiguo 01/04/2013, 16:07
 
Fecha de Ingreso: mayo-2009
Mensajes: 232
Antigüedad: 14 años, 11 meses
Puntos: 3
Respuesta: Optimizar busqueda

Muchas gracias leo!

Lo ultimo que dices:

Cita:
Ambas consultas son bastante ineficientes por cierto, pero eso se debe a que desde mi punto de vista tienes un pésimo modelo de datos, pero bueno, puedes hacer la prueba para ver qué tanto se tardan en ejecutar estas consultas, o como lo planteas hacer cada consulta por separado, pero olvídate de eso de ordenar y buscar... simplemente cuenta el numero de jugadores con mayor puntuación.
Eso es justamente lo que necesitaba, no se mucho como organizar Bases de datos, el caso de mi bd es ipotetico, y aun puedo cambiar la estructura, ya que no he lanzado la palicacion aun..

Me gustaria saber como lo harias para hacer mas efectiva la busqueda, con una tabla para cada juego? aun asi se haria una consulta poara cada tabla..

Haber si me puedes informar o lanzarme a algun link especifico ya que no encontre nada..

Es eso, como estructurar el tema para hacerlo mas eficiente. Y menos tedioso al buscar.
  #8 (permalink)  
Antiguo 01/04/2013, 16:33
Colaborador
 
Fecha de Ingreso: enero-2007
Ubicación: México
Mensajes: 2.097
Antigüedad: 17 años, 3 meses
Puntos: 447
Respuesta: Optimizar busqueda

Hola de nuevo:

Mira, en lo referente a un buen modelo de BD no todo está escrito, depende mucho de la lógica de negocio que tengas y también de experiencia, sin embargo aquí habría que hacer algunas preguntas:

1. ¿Todos los jugadores juegan todos los juegos? si la respuesta es no entonces el modelo que tienes no aplica para esto.

2. ¿Los atributos que quieres almacenar para cada juego son distintos? es decir, ¿además de los puntos guardas información adicional? si la respuesta es no, entonces un modelo utilizando una tabla para cada juego tampoco aplica.

3. ¿Un jugador juega una vez y solo una vez cada juego? ¿o puede jugar varias veces un mismo juego y obtener un puntaje cada vez?, si este fuera el caso me supongo que lo que pretendes hacer es actualizar el score mediante un UPDATE cada vez que termina un juego... esto tampoco es optimo.

En lo particular optaría por un modelo más o menos así:

Un catálogo de juegos (id_juego, nombre_juego):

Código:
1|canicas
2|cartas
3|domino
...
Un catálogo de jugadores (id_jugador, nombre_jugador):

Código:
1|juan
2|marco
3|silvia
...
y una tabla de partidas o juegos por jugador (id_partida, id_juego, id_jugador, puntos):

Código:
1|1|1|10
2|2|2|40
3|3|2|60
4|1|2|20
5|2|3|10
6|2|1|70
7|3|1|30
...
cada vez que un jugador termina una partida, simplemente se agrega un registro a la tabla... para obtener los puntajes por jugador/juego simplemente utilizas las funciones de agrupación SUM y la cláusula GROUP BY, y para obtener el ranking del jugador tienes muchas formas, utilizando técnicas como las que te puse en los post's u otras como simular la función RANK:

http://www.artfulsoftware.com/infotr...tip.php?id=460

Pero ese es un tema bastante extenso que bien merece que abras otro post, nos expliques bien qué es lo que quieres almacenar de información y así podemos darte algunos consejos...

saludos
Leo.
  #9 (permalink)  
Antiguo 01/04/2013, 17:14
 
Fecha de Ingreso: mayo-2009
Mensajes: 232
Antigüedad: 14 años, 11 meses
Puntos: 3
Respuesta: Optimizar busqueda

Muchas gracias de nuevo leo,

primero contestarte:

1. Todos los jugadores pueden jugar a todos los juegos, aunque alguien de media jugaria a lamitad de ellos.

2.Solo necesito guardar nombre, password, y puntuaciones de cada juego, quizas email.

3.Puede jugar las veces que quiera a cada juego para mejorar su marca.

Tu estructura me parece correcta, aunque solo por el echo de dividir, ordenar cada cosa en su sitio, peor al final queda igual una ultima tabla donde no solo hay la ultima marca conseguida en cada juego sino todas las anteriores. Así si haciendo updates deberia recorrer 1000 filas de 1000 usuarios, de esta manera deberia recorrer mil usuarios x todas su partidas...
  #10 (permalink)  
Antiguo 02/04/2013, 08:31
Colaborador
 
Fecha de Ingreso: enero-2007
Ubicación: México
Mensajes: 2.097
Antigüedad: 17 años, 3 meses
Puntos: 447
Respuesta: Optimizar busqueda

Hola de nuevo phyronx:

Creo que no estás empapado de muchos conceptos de BD y por eso te estás complicando la existencia.

Cita:
peor al final queda igual una ultima tabla donde no solo hay la ultima marca conseguida en cada juego sino todas las anteriores. Así si haciendo updates deberia recorrer 1000 filas de 1000 usuarios, de esta manera deberia recorrer mil usuarios x todas su partidas...
Olvidate de eso de los updates, eso es completamente ineficiente... en mi post ponía, por si pones un poco de atención:

Cita:
cada vez que un jugador termina una partida, simplemente se agrega un registro a la tabla... para obtener los puntajes por jugador/juego simplemente utilizas las funciones de agrupación SUM y la cláusula GROUP BY, y para obtener el ranking del jugador tienes muchas formas
Es decir, para obtener la puntuación de un jugador en cierto juego NO NECESITAS HACER UN UPDATE, NI MIL UPDATES NI NADA POR EL ESTILO, simplemente tienes que hacer uso de las funciones de agrupación, creo que te conviene leer cualquier libro de SQL para principiantes para que te comiences a involucrar con estos conceptos.

Como te dije, conviene también que de des un vistazo a algún libro o manual de Diseño de Base de Datos, para que te ayude a modelar tus tablas.

con respecto a las preguntas:

Código:
1. Todos los jugadores pueden jugar a todos los juegos, aunque alguien de media jugaria a lamitad de ellos.
Tal como te comenté, si un atributo es opcional, debe ponerse en una tabla distinta (Conceptos de normalización y diseño de Base de Datos)

Código:
2.Solo necesito guardar nombre, password, y puntuaciones de cada juego, quizas email.
Estás confundiendo los datos del juego y los datos del jugador... son dos entidades completamente distintas y no tienen en realidad nada que ver con las puntuaciones del juego.

Código:
3.Puede jugar las veces que quiera a cada juego para mejorar su marca.
Lo que te comenté también, cada que un jugador termine un juego simplemente se agrega un registro a la tabla, no se realiza un update.

Insisto en que esto es un tema que nos puede llevar muchísimo tiempo para continuar discutiendo y no terminaríamos de ponernos de acuerdo.

Saludos
Leo.

Etiquetas: busqueda, campo, select, tabla
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 08:15.