2011-10-04 57 views
8

Tôi đang phát triển hệ thống phần thưởng cho VLE sử dụng ba công nghệ riêng biệt - JavaScript cho hầu hết các xử lý phía máy khách/hiển thị, PHP để giao tiếp với cơ sở dữ liệu và MySQL cho cơ sở dữ liệu.Tối ưu hóa cấu trúc cơ sở dữ liệu

Tôi đã đính kèm ba ảnh chụp màn hình của bảng "giao dịch" của tôi. Cấu trúc của nó, một vài bản ghi ví dụ và tổng quan về các chi tiết của nó.

Tiền đề là các thành viên của điểm thưởng nhân viên cho sinh viên có hành vi tốt vv Điều này có nghĩa là các lớp học của 30 sinh viên được cho điểm tại một thời điểm. Nhân viên có giới hạn 300 điểm/tuần và có khoảng 85 nhân viên hiện đang truy cập vào hệ thống (điều này có thể tăng).

Cách tôi đang thực hiện tại thời điểm này, mọi "giao dịch" đều có "Giver_ID" (thành viên của nhân viên trao điểm), "Recipient_ID" (sinh viên nhận điểm), danh mục và lý do . Bằng cách này, mỗi khi một thành viên của nhân viên phát hành 30 điểm, tôi sẽ đặt 30 hàng vào cơ sở dữ liệu.

Điều này dường như hoạt động sớm, nhưng trong vòng ba tuần, tôi đã có hơn 12.000 giao dịch trong cơ sở dữ liệu.

Tại thời điểm này nó trở nên phức tạp hơn một chút. Trên trang Gán điểm (một ảnh chụp màn hình khác được đính kèm), khi giáo viên nhấp vào một trong các lớp học của họ hoặc tìm kiếm một cá nhân học sinh, tôi muốn các điểm của sinh viên được hiển thị. Cách duy nhất mà tôi hiện có thể làm điều này trên hệ thống của tôi là để làm một "SELECT * FROM 'transactions'" và đặt tất cả các thông tin vào một mảng bằng cách sử dụng JS sau:

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; 
     } 
    } 
} 

Khi đăng nhập vào hệ thống nội bộ, điều này dường như làm việc đủ nhanh. Tuy nhiên, khi đăng nhập bên ngoài, quá trình này mất khoảng 20 giây và do đó không hiển thị giá trị điểm của sinh viên cho đến khi bạn nhấp/tìm kiếm một vài lần.

Tôi đang sử dụng đoạn mã sau trong PHP của tôi để truy cập vào các giao dịch:

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; 
    } 
} 

Vì vậy, câu hỏi của tôi là, làm thế nào nên tôi thực sự được tiếp cận này? Chỉ mục toàn văn; có thể là một bảng học sinh với tổng giá trị điểm được cập nhật mỗi khi một giao dịch được nhập vào; giao dịch đại chúng (nghĩa là nhiều hơn một sinh viên nhận cùng một điểm cho cùng một danh mục) được nhóm thành một hàng cơ sở dữ liệu duy nhất? Đây là tất cả những điều tôi đã dự tính nhưng tôi yêu một người có nhiều kiến ​​thức về DB hơn bản thân mình để cung cấp sự giác ngộ.

Ví dụ ghi Example records

cấu trúc Bảng Table structure

tổng quan Bảng Table overview

Điểm Gán giao diện Assign Points interface

Rất cám ơn trước.

+0

Được yêu thích ... – slandau

Trả lời

3

Vấn đề của bạn là truy vấn của bạn:

SELECT * FROM `transactions` 

Vì bộ dữ liệu của bạn được lớn hơn, điều này sẽ mất nhiều thời gian để tải và đòi hỏi nhiều bộ nhớ hơn để lưu trữ nó. Thay vì xác định dữ liệu nào bạn cần cụ thể. Nếu nó cho một người dùng cụ thể:

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

Hoặc nếu bạn muốn tất cả các khoản tiền cho tất cả học sinh của bạn:

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

Đẩy nhanh tiến độ các lựa chọn trên một lĩnh vực cụ thể bạn có thể thêm một chỉ số cho trường đó. Điều này sẽ tăng tốc các lựa chọn, đặc biệt khi bảng tăng lên.

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

Hoặc nếu bạn muốn hiển thị một danh sách phân trang của tất cả các mục trong 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

Cảm ơn rất nhiều Tom. Điều này đã cải thiện tốc độ trong nhiều lĩnh vực trên hệ thống của tôi. – dunc

1

tôi muốn chỉ mục các Recipient_ID vì vậy bạn có thể tìm kiếm 1 người đặc biệt tại bất kỳ điểm nào hoặc ít ít nhất có thể NHÓM dữ liệu của bạn hiệu quả hơn. Nếu bạn chọn nhóm theo category_id thì tôi cũng sẽ thêm một chỉ mục riêng biệt hoặc kết hợp vào category_id.

Đề xuất thứ hai là GROUP và AGGREGATE dữ liệu của bạn khi đang di chuyển. Ví dụ:

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

Hai gợi ý nên nâng cấp đáng kể hiệu suất của bạn bởi vì thay vì tính toán tổng số điểm cho các sinh viên của bạn ở phía bên PHP/JS, bạn sẽ làm điều đó trực tiếp trên cơ sở dữ liệu.

2

Thêm vào đề xuất của Tom, bạn có thể cân nhắc việc chuẩn hóa cơ sở dữ liệu của mình thêm nữa. Tôi giả sử bây giờ bạn có 3 bảng:

students (id, name, ...)

staff (id, name, ...)

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

Một hình thức bình thường hóa hơn sử dụng nhiều bảng với dữ liệu ít:

students (id, name, ...)

staff (id, name, ...)

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

transactions_students (transaction_id, student_id)

Thêm một giao dịch sau đó trở thành một quá trình hai bước: Trước tiên, bạn tạo một bản ghi giao dịch, và sau đó bạn chèn nhiều hồ sơ vào transactions_students, mỗi một liên kết giao dịch cho một học sinh. Lưu ý rằng bạn có thể tạo ra một cái nhìn mà cư xử hệt như bảng denormalized ban đầu cho việc lựa chọn, một cái gì đó như:

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

Điều này sẽ làm giảm đáng kể số lượng các bản ghi trong bảng giao dịch, và nó tránh lưu trữ ngày và lý do redunantly.Nhược điểm là việc liên kết các giao dịch với các sinh viên đòi hỏi một sự gia nhập thêm - nhưng nếu bạn có các khóa và chỉ mục ngoài được thiết lập đúng, thì điều này không phải là vấn đề gì cả.

+0

Cảm ơn người gửi thư rác. Bạn có thể vui lòng cho tôi ví dụ về cách bạn lưu trữ một giao dịch trên các bảng đó không? Tôi thực sự không có bảng học sinh hoặc nhân viên, vì tất cả các ID đến từ VLE của chúng tôi bằng cách sử dụng một cuộc gọi 'Frog.API.get ('users.getInfo')'. – dunc

+1

Đã chỉnh sửa câu trả lời của tôi. HTH. – tdammers

Các vấn đề liên quan