2010-06-05 22 views
6

Esto es para un próximo proyecto. Tengo dos tablas - en primer lugar se tiene pistas de fotos, y el segundo rastrea el rango de la foto¿Cómo optimizar esta tabla MySQL?

Photos: 
+-------+-----------+------------------+ 
| id | photo  | current_rank  | 
+-------+-----------+------------------+ 
| 1  | apple  | 5    | 
| 2  | orange | 9    | 
+-------+-----------+------------------+ 

El rango foto no deja de cambiar de forma regular, y esta es la tabla que sigue es:

Ranks: 
+-------+-----------+----------+-------------+ 
| id | photo_id | ranks | timestamp | 
+-------+-----------+----------+-------------+ 
| 1  | 1   | 8  | *   | 
| 2  | 2   | 2  | *   | 
| 3  | 1   | 3  | *   | 
| 4  | 1   | 7  | *   | 
| 5  | 1   | 5  | *   | 
| 6  | 2   | 9  | *   | 
+-------+-----------+----------+-------------+ * = current timestamp 

Todos los rangos se rastrean con fines de informe/análisis. [Editar] Los usuarios tendrán acceso a las estadísticas a pedido.

Hablé con alguien que tiene experiencia en este campo, y me dijo que el almacenamiento de rangos como el anterior es el camino a seguir. Pero todavía no estoy seguro.

El problema aquí es redundancia de datos. Habrá decenas de miles de fotos. El rango de la foto cambia cada hora (muchas veces, en minutos) para las fotos recientes, pero con menos frecuencia para las fotos anteriores. A este ritmo, la tabla tendrá millones de registros en unos meses. Y como no tengo experiencia en trabajar con grandes bases de datos, esto me pone un poco nervioso.

pensé en esto:

Ranks: 
+-------+-----------+--------------------+ 
| id | photo_id | ranks    | 
+-------+-----------+--------------------+ 
| 1  | 1   | 8:*,3:*,7:*,5:* | 
| 2  | 2   | 2:*,9:*   | 
+-------+-----------+--------------------+ * = current timestamp 

Eso significa algún código extra en PHP para dividir el rango/hora (y clasificación), pero que se ve bien para mí.

¿Es esta la manera correcta de optimizar la tabla para el rendimiento? ¿Qué recomendarías?

+0

es el rango conectado a cualquier otra cosa? como el usuario que lo dio? y si es así, ¿qué tan importante es esa relación? ¿es decir? ¿Necesitas almacenar el rango del juego del usuario? –

+0

El rango no está vinculado a otra cosa que no sea la foto. ¡Es calculado y cambiado por un algoritmo computacional! :) – Yeti

+1

@Col: ¡tus comentarios siempre me hacen sonreír! :) En realidad, los ID se parecen más a esto: ** 4606886418 **, en este momento hay alrededor de 2 millones de fotos. El rango de cada uno cambia más de 50 veces. Entonces, aunque puede que no sea demasiado grande, tampoco se puede llamar pequeño. – Yeti

Respuesta

7

El primero. Período.

En realidad, perderá mucho más. Una marca de tiempo almacenada en la columna int ocupará solo 4 bytes de espacio.

Si bien la misma marca de tiempo almacenada en el formato de cadena tendrá 10 bytes.

+0

Olvidé mencionar que la marca de tiempo no es la marca de tiempo de unix, es la fecha y hora. ¿Es eso lo mismo? – Yeti

+0

@Lost para su tarea: http://dev.mysql.com/doc/refman/5.0/en/storage-requirements.html –

2

Me quedaría con su primer enfoque. En el segundo tendrás una gran cantidad de datos almacenados en la fila, ¡a medida que pasa el tiempo obtiene más rangos! Es decir, si una foto obtiene miles y miles de clasificaciones.

El primer enfoque también es más fácil de mantener, es decir, si desea eliminar un rango.

+1

En realidad, los datos en la tabla de rangos nunca se actualizan porque se usan para mostrar estadísticas. – Yeti

+0

Gracias Peter (Tak Peter) – Phliplip

1

Creo que la base de datos 'hit' de sobre normalización (consultar la tabla de rangos una y otra vez) se evita muy bien al 'caché' del último rango en current_rank. En realidad, no importa los rangos está creciendo enormemente si rara vez se consulta (análisis/informes que usted dijo), nunca actualizado sino que simplemente inserta registros al final: incluso una caja muy clara no tendría problemas para tener millones de filas en esa tabla.

Su alternativa requeriría muchas actualizaciones en diferentes ubicaciones en el disco, lo que posiblemente daría como resultado un rendimiento degradado.

Por supuesto, si necesita todos los datos antiguos, y siempre con photo_id, puede planificar una ejecución programada en otra tabla rankings_old, posiblemente con photo_id, año, mes, clasificaciones (incluidas marcas de tiempo) cuando termine un mes, por lo tanto, la recuperación de datos antiguos sigue siendo posible, pero no se necesitan actualizaciones en rankings_old o rankings, solo insertos al final de la tabla.

Y tómenlo de mí: millones de registros en una tabla de registro puro no deberían ser absolutamente ningún problema.

+0

Malo, no mencioné que el registro está disponible para el propietario del propietario de la foto (pueden ver las estadísticas de rango). Por lo tanto, podría haber muchas consultas. – Yeti

+0

Luego está menos definido, pero sigo pensando que la primera solución sería mejor (el rendimiento de la actualización es la clave y las actualizaciones no deberían bloquear las selecciones). Es posible que trabaje con rankings diarios, en lugar de un mes. – Wrikken

2

Su primer diseño es el correcto para una base de datos relacional. La redundancia en las columnas clave es preferible porque le da mucha más flexibilidad en la forma de validar y consultar los rankings. Puede hacer ordenaciones, recuentos, promedios, etc. en SQL sin tener que escribir ningún código PHP para dividir su cadena de seis maneras desde el domingo.

Parece que le gustaría utilizar una base de datos que no sea SQL, como CouchDB o MongoDB. Estos serían que le permiten almacenar una lista semiestructurada de clasificaciones directamente en el registro de la foto, y posteriormente consultar las clasificaciones de manera eficiente. Con la advertencia de que realmente no sabes que los rankings están en el formato correcto, como lo haces con SQL.

0

Usted indicó que el rango solo está vinculado a la imagen, en cuyo caso todo lo que necesita es la tabla 1 y sigue actualizando el rango en tiempo real. La Tabla 2 simplemente almacena datos innecesarios. La desventaja de este enfoque es que el usuario no puede cambiar su voto.

1

Datos normalizados o datos no normalizados. Encontrarás miles de artículos sobre eso. :)

Realmente depende de sus necesidades.

Si desea construir su base de datos solo con el rendimiento (velocidad o consumo de RAM o ...) en mente, solo debe confiar en los números. Para hacer eso tienes que perfilar tus consultas con el "volumen" de datos esperado (puedes generar los datos con algún script que escribas). Para un perfil de sus consultas, aprender a leer los resultados de los 2 siguientes consultas:

  • EXPLAIN extended...
  • SHOW STATUS

luego aprender qué hacer para mejorar las cifras (configuración de MySQL, estructura de datos, hardware, etc.).

Como aperitivo, realmente aconsejan estos 2 grandes artículos:

  1. http://www.xaprb.com/blog/2006/10/12/how-to-profile-a-query-in-mysql/
  2. http://ajohnstone.com/archives/mysql-php-performance-optimization-tips/

Si usted quiere construir por la belleza académico de la normalización: sólo tiene que seguir los libros y las recomendaciones generales. :)

0

Dijiste que la segunda tabla es para analizar/estadísticas, por lo que en realidad no es algo que deba almacenarse en db. Mi sugerencia es deshacerse de la segunda tabla y usar un recurso de registro para registrar los cambios de rango.

+0

Olvidé mencionar que los usuarios pueden acceder a los datos de la segunda mesa. Has editado la pregunta. – Yeti

1

Fuera de las dos opciones - como todo el mundo antes me dijo - tiene la opción 1.

Lo que realmente debería estar preocupado son los cuellos de botella en la propia aplicación para ser. ¿Los usuarios van a referirse a los datos históricos con frecuencia o solo aparecen para algunos usuarios selectos? Si la respuesta es que todos pueden ver los datos históricos de los rangos, entonces la opción 1 es lo suficientemente buena. Si no va a referirse a los rangos históricos con tanta frecuencia, puede crear una tercera tabla de "archivo" y, antes de actualizar los rangos, puede copiar las filas de la tabla de rango original en la tabla de archivo. Esto garantiza que el número de filas sea mínimo en la tabla principal a la que se llama.

Recuerde, si está actualizando las filas, y hay decenas de miles, podría ser más fructífero obtener los resultados en su código (PHP/Python/etc), truncar la tabla e insertar los resultados en lugar de actualizándolo fila por fila, ya que eso sería un posible cuello de botella.

Es posible que desee para buscar sharding así (partición horizontal) - http://en.wikipedia.org/wiki/Shard_%28database_architecture%29

Y nunca se olvide de índice también.

Espero que haya ayudado.

0

Su segundo diseño es muy peligroso en caso de que tenga 1 millón de votos para una foto. ¿Puede PHP manejar eso?

Con el primer diseño puede hacer todas las operaciones matemáticas en el nivel de la base de datos que le devolverá un pequeño result set.

Cuestiones relacionadas