2011-10-04 17 views
8

Estoy desarrollando un sistema de recompensa para nuestro VLE que utiliza tres tecnologías separadas: JavaScript para la mayoría del procesamiento del cliente/pantalla, PHP para comunicarse con la base de datos y MySQL para la base de datos.Optimización de la estructura de la base de datos

He adjuntado tres capturas de pantalla de mi tabla de "transacciones". Su estructura, algunos registros de ejemplo y una visión general de sus detalles.

La premisa es que los miembros del personal otorgan puntos a los estudiantes por su buen comportamiento, etc. Esto puede significar que las clases de 30 estudiantes reciben puntos a la vez. El personal tiene un límite de 300 puntos por semana y hay alrededor de 85 empleados que actualmente acceden al sistema (esto puede aumentar).

La forma en que lo estoy haciendo en este momento, cada "transacción" tiene un "Giver_ID" (el miembro del personal que otorga puntos), un "Recipient_ID" (el estudiante que recibe los puntos), una categoría y un motivo . De esta forma, cada vez que un miembro del personal emite 30 puntos, estoy ingresando 30 filas en la base de datos.

Esto pareció funcionar desde el principio, pero en tres semanas ya tengo más de 12,000 transacciones en la base de datos.

En este punto se vuelve un poco más complicado. En la página Asignar puntos (otra captura de pantalla adjunta), cuando un profesor hace clic en una de sus clases o busca un alumno en particular, quiero que se muestren los puntos de los alumnos. La única forma en que actualmente puedo hacer esto en mi sistema es hacer un "SELECT * FROM 'transactions'" y poner toda la información en una matriz utilizando la JS siguiente:

var Points = { "Recipient_ID" : "0", "Points" : "0" }; 

function getPoints (data) { 
    for (var i = 0; i < data.length; i++) { 
     if (Points[data[i].Recipient_ID]) { 
      Points[data[i].Recipient_ID] = parseInt(Points[data[i].Recipient_ID]) + parseInt(data[i].Points); 
     } else { 
      Points[data[i].Recipient_ID] = data[i].Points; 
     } 
    } 
} 

Al registrarse en el sistema internamente, esto parece funcionar Suficientemente rapido. Sin embargo, cuando se inicia sesión externamente, este proceso toma alrededor de 20 segundos y, por lo tanto, no muestra los valores de puntos de los estudiantes hasta que haya hecho clic/buscado varias veces.

estoy usando el siguiente código en mi PHP para acceder a estas operaciones:

function getTotalPoints() { 
    $sql = "SELECT * 
     FROM `transactions`"; 

    $res = mysql_query($sql); 
    $rows = array(); 
    while($r = mysql_fetch_assoc($res)) { 
     $rows[] = $r; 
    } 

    if ($rows) { 
     return $rows; 
    } else { 
     $err = Array("err_id" => 1); 
     return $err; 
    } 
} 

lo tanto, mi pregunta es, ¿cómo debo en realidad estar acercándose a esto? Índices de texto completo; tal vez una tabla de estudiantes con sus valores totales de puntos que se actualiza cada vez que se ingresa una transacción; transacciones masivas (es decir, más de un estudiante recibiendo los mismos puntos para la misma categoría) agrupados en una única fila de base de datos? Estas son todas las cosas que he contemplado, pero me encantaría que alguien con más conocimientos de DB que yo para proporcionar la iluminación.

Ejemplo registra Example records

estructura Tabla Table structure

Tabla de resumen Table overview

Puntos Asignar interfaz Assign Points interface

Muchas gracias de antemano.

+0

Bien pedido ... – slandau

Respuesta

3

Su problema es su consulta:

SELECT * FROM `transactions` 

A medida que el conjunto de datos se hace más grande, esto va a tomar más tiempo para cargar y requieren más memoria para almacenarlo. Más bien determine qué datos necesita específicamente. Si es para un usuario en particular:

SELECT SUM(points) FROM `transactions` WHERE Recipient_ID=[x] 

O si desea que todas las sumas para todos sus estudiantes:

SELECT Recipient_ID, SUM(points) AS Total_Points FROM `transactions` GROUP BY Recipient_ID; 

Para acelerar las selecciones en un campo particular, se puede añadir un índice para ese campo. Esto acelerará las selecciones, especialmente a medida que la mesa crece.

ALTER TABLE `transactions` ADD INDEX Recipient_ID (Recipient_ID); 

O si desea mostrar una lista paginada de todas las entradas en transactions:

SELECT * FROM `transactions` LIMIT [page*num_records_per_page],[num_records_per_page]; 

e.g.: SELECT * FROM `transactions` LIMIT 0,25 ORDER BY Datetime; # First 25 records 
+0

Muchas gracias Tom. Esto ha mejorado la velocidad en muchas áreas de mi sistema. – dunc

1

que había indexar el recipient_id para que pueda buscar para 1 persona en concreto en un momento dado o por lo menos capaz de agrupar sus datos de manera más efectiva. Si optas por agrupar por category_id, entonces agregaría un índice separado o combinado a category_id también.

La segunda sugerencia sería agrupar y AGREGAR sus datos sobre la marcha. Por ejemplo:

SELECT Recipient_ID, Category_ID, SUM(points) FROM transactions GROUP BY Recipient_ID, Category_ID 

Estas dos sugerencias deben mejorar considerablemente su rendimiento, ya que en lugar de calcular el total de puntos para sus estudiantes en el lado PHP/JS, lo hará directamente en la base de datos.

2

Agregando a la sugerencia de Tom, es posible que desee considerar la normalización de su base de datos. Asumo que ahora tiene 3 mesas:

students (id, name, ...)

staff (id, name, ...)

transactions (id, student_id, staff_id, points, date, reason)

Una forma más normalizada utiliza más mesas con menos datos:

students (id, name, ...)

staff (id, name, ...)

transactions (id, staff_id, points, date, reason)

transactions_students (transaction_id, student_id)

Adición de una transacción se convierte entonces en un proceso de dos pasos: En primer lugar se crea un registro de la transacción, y luego inserta varios registros en transactions_students, cada una vinculación de la transacción a un estudiante. Observe que puede crear una vista que se comporta exactamente igual que la tabla sin normalizar original para la selección, algo así como:

CREATE VIEW vw_transactions AS SELECT transactions.*, transactions_students.student_id FROM transactions INNER JOIN transactions_students WHERE transactions_students.transaction_id = transactions.id 

Esto reducirá drásticamente el número de registros de la tabla de transacciones, y se evita el almacenamiento de la fecha y la razón de manera redundante.La desventaja es que vincular las transacciones a los estudiantes requiere una unión adicional, pero si tiene sus claves e índices externos configurados correctamente, esto no tiene por qué ser un problema en absoluto.

+0

Gracias tdammers. ¿Podría darme un ejemplo de cómo almacenaría una transacción en esas tablas? En realidad, no tengo tablas de estudiantes o personal, ya que todas las identificaciones provienen de nuestro VLE usando una llamada 'Frog.API.get ('users.getInfo')'. – dunc

+1

Editado mi respuesta. HTH. – tdammers

Cuestiones relacionadas