2011-10-04 136 views
8

我正在爲我們的VLE開發一個獎勵系統,該系統使用三種獨立的技術 - 用於大多數客戶端/顯示處理的JavaScript,用於與數據庫通信的PHP以及用於數據庫本身的MySQL。優化數據庫結構

我附上了我的「交易」表的三個屏幕截圖。其結構,一些示例記錄和其細節概述。

前提是員工成員獎勵指向學生的良好行爲等。這可能意味着30名學生的班級在同一時間給予積分。員工每週限制300點,目前有85名員工正在訪問系統(這可能會增加)。

我現在的做法是,每個「交易」都有一個「Giver_ID」(員工獎勵積分),一個「Recipient_ID」(接收積分的學生),一個類別和一個原因。這樣,每當員工發出30分時,我就把30行放入數據庫中。

這似乎在早期工作,但在三個星期內,我已經在數據庫中有超過12,000個事務。

在這一點上它變得更復雜一點。在Assign Points頁面(附帶的另一個屏幕截圖)上,當老師點擊其中一個班級或搜索某個學生時,我希望顯示學生的分數。我目前能做到這一點我的系統上的唯一方法是做一個「SELECT * FROM 'transactions'」,用把所有的信息到一個數組以下JS:

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

當登錄到內部系統中,這似乎工作足夠快。但是,當從外部登錄時,此過程大約需要20秒,因此在您點擊/搜索幾次之前不會顯示學生的積分值。

我用我的PHP下面的代碼來訪問這些數據:

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

所以,我的問題是,我應該怎麼實際地接近這一點?全文索引;可能是一張學生表,其總積分值每次進入交易時都會更新;大量交易(即多於一名學生接受同一類別的相同分數)被分組到單個數據庫行中?這些都是我所想到的,但我會喜歡有比我更多的數據庫知識的人來提供啓發。

實施例記錄 Example records

表結構 Table structure

表概述 Table overview

分配點數接口 Assign Points interface

非常感謝提前。

+0

很好問... – slandau

回答

3

你的問題是你查詢:

SELECT * FROM `transactions` 

隨着數據集變得更大,這將需要更長的時間來加載,需要更多的內存來存儲它。而是確定你需要什麼數據。如果它是一個特定的用戶:

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

或者,如果你想爲所有的學生全部款項:

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

要加快對某一特定領域的選擇,你可以爲字段添加一個索引。這將加快選擇,特別是隨着桌子的增長。

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

或者,如果你想在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

非常感謝湯姆。這提高了我係統中很多區域的速度。 – dunc

1

我倒是指數Recipient_ID所以你可以專門在任何給定的點或者在搜索1人至少能夠更有效地對數據進行分組。如果你選擇按category_id進行分組,那麼我會爲category_id添加一個單獨的或組合的索引。

第二個建議是GROUP和Aggregate您的數據。例如:

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

這兩個建議,應該大幅升級的性能,因爲不是計算總積分爲您的學生在PHP/JS的一面,你會直接做在數據庫上。

2

增加湯姆的建議,你可能要考慮進一步規範化你的數據庫。我假設你現在有3個表:

students (id, name, ...)

staff (id, name, ...)

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

更規範化的形式使用多個表數據較少:

students (id, name, ...)

staff (id, name, ...)

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

transactions_students (transaction_id, student_id)

添加一個事務,然後變成了兩個步驟:首先創建一個交易記錄,然後插入多條記錄到transactions_students,每一個交易鏈接到一個學生。請注意,您可以創建行爲完全像選擇原來的非規範化的表視圖,是這樣的:

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

這將大大減少在交易表中的記錄數,並且避免了存儲日期和原因redunantly。缺點是,將交易鏈接到學生需要一個額外的連接 - 但是如果你的外鍵和索引設置正確,這根本就不是問題。

+0

謝謝tdammers。你能否給我舉一個你如何在這些表中存儲交易的例子?實際上我沒有學生或職員表,因爲所有的ID都來自我們的VLE,使用'Frog.API.get('users.getInfo')'調用。 – dunc

+1

編輯我的答案。 HTH。 – tdammers