2013-10-08 78 views
2

信息優化while循環包含PDO查詢的

目前建立一個通知頁面,列出其中包含大約每一筆的通知信息的用戶通知所有登錄的。

例如,如果沒有信息

You have an unread message 

隨着信息

<Sarah> Sent you an message 

問題

由於通知需要諸如用戶名(用於消息通知)的數據或文章的標題(說你跟隨作者,他們發佈一個新的博客帖子,一個通知將需要拉usern ame形成用戶表,然後也是博客表中的博客標題),這導致我的頁面即使在本地主機上也滯後,我猜測一旦上傳並在野外進行測試,它會變得更糟糕。

目前代碼

function showNotifications($userid){ 
    $STH = $this->database->prepare('SELECT * FROM notifications WHERE user_id = :userid ORDER BY timestamp DESC'); 
    $STH->execute(array(':userid' => $userid)); 
    while($row = $STH->fetch(PDO::FETCH_ASSOC)){ 
     $this->sortNotif($row); 
} 

下面關於功能快速解釋,因爲我有不同類型的I創建一堆ID的特定類型的通知,例如類型1 =新的消息,類型2 =新的博客文章

function sortNotif($notif){ 

    switch ($notif['type']) { 

     case "1": 
      $msg = $this->getMessageData($notif['feature_id']); 
      $user = $this->userData($msg['sender']); 
      echo '<li><i>'.timeAgo($notif['timestamp']).'</i><a href="user.php?username='.$user['username'].'">'.$user['first_name'].'</a> sent you a <a href="inbox.php?message='.$msg['id'].'">message</a></li>'; 
      break; 

    } 

} 

正如你所看到的只是顯示一個用戶擁有它創建2查詢的,一旦通過40個左右通知循環,在100個左右的用戶一個新的消息成爲對T的應變他服務器。

最後的話

如果有人需要了解更多信息請諮詢我一定會盡快更新這個問題,謝謝!

編輯

下面是表的結構如下面的評論請求。

通知

id | user_id | feature_id | type | timestamp | read 

用戶

id | username | password | first_name | last_name | email | verify_hash | avatar | type 

消息

id | receiver | sender | replying_to | deleted | body | timestamp | read 
+0

你可以採取替換它們sortNotif函數中的switch/case語句中的一些常見代碼?你使用MySQL EXPLAIN或其他什麼來分析你的查詢嗎?那裏有優化的任何範圍? – Maximus2012

+0

我使用了一個我在網上找到的小型php代碼片段,並多次測試多個頁面。 notification.php頁面的頁面生成時間爲0.6599秒。而所有其他「頁面生成0.0467秒」。另外,頁面實際上明顯慢得多。如果你想,我可以嘗試另一種方法來測試速度,如果有什麼建議嗎? – Harry

+0

在這種情況下,是否會有其他可能會減慢最終頁面的內容? JavaScript或圖像可能? – Maximus2012

回答

0

計劃的變更,因爲我誤解了成立。

您將希望一次性從每個「類型」表中提取所有數據,而不是每次通知。這意味着您需要循環兩次通知,一次抓取所有ID和適當類型,然後再次輸出結果。

function showNotifications($userid){ 
    $STH = $this->database->prepare('SELECT * FROM notifications WHERE user_id = :userid ORDER BY timestamp DESC'); 
    $STH->execute(array(':userid' => $userid)); 

    // Centralized Book keeping for the types. 
    // When you add a new type to the entire system, add it here as well. 
    $types = array(); 

    // Add the first notification type 
    $types["1"] = array(); 
    // "query" is pulling all the data you need concerning a notification 
    $types["1"]["query"] = "SELECT m.id, u.username, u.firstname FROM messages m, users u WHERE m.sender = u.id AND m.id IN "; 
    // "ids" will hold the relevant ids that you need to look up. 
    $types["1"]["ids"] = array(); 

    // A second type, just for show. 
    // $types["2"] = array(); 
    // $types["2"]["query"] = "SELECT a.id, u.username, u.firstname FROM articles a, users u WHERE a.sender = u.id AND a.id IN "; 
    // $types["2"]["ids"] = array(); 

    // Use fetchAll to gather all of the notifications into an array 
    $notifications = $STH->fetchAll(); 

    // Walk through the notifications array, placing the notification id into the corret 
    // "ids" array in the $types array. 
    for($i=0; $i< count($notifications); $i++){ 
     $types[$notifications[$i]['type']]["ids"][] = $notifications[$i]['feature_id']; 
    } 

    // Walk through the types array, hit the database once for each type of notification that has ids. 
    foreach($types as $type_id => $type){ 
     if(count($type["ids"]) > 0){ 
      $STH = $this->database->prepare($type["query"] . "(" . implode(",", $type["ids"]) . ")"); 
      $STH->execute(); 
      // Creates a hash table with the primary key as the array key 
      $types[$type_id]['details'] = $STH->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_ASSOC); 
      $types[$type_id]['details'] = array_map('reset', $types[$type_id]['details']); 
      // run array_map to make it easier to work with, otherwise it looks like this: 
      // $results = array(
      //  1234 => array(0 => array('username' => 'abc', 'firstname' => '[...]')), 
      //  1235 => array(0 => array('username' => 'def', 'firstname' => '[...]')), 
      //); 
     } 
    } 

    // Now walk through notifications again and write out based on notification type, 
    // referencing $types[<notification type>]["details"][<message id>] for the details 
    for($i=0; $i< count($notifications); $i++){ 

     // check to see if details for the specific notification exist. 
     if(isset($types[$notifications[$i]['type']]["details"][$notifications[$i]['feature_id']])){ 
      $notification_details = $types[$notifications[$i]['type']]["details"][$notifications[$i]['feature_id']]; 

      switch ($notifications[$i]['type']) { 

       case "1": 
        echo '<li><i>'.timeAgo($notifications[$i]['timestamp']).'</i><a href="user.php?username=' . $notification_details['username'] . '">' . $notification_details['first_name'].'</a> sent you a <a href="inbox.php?message='.$notifications[$i]['feature_id'].'">message</a></li>'; 
       break; 

      } 
     } 
    } 
} 

更新:新增邏輯跳過通知,如果沒有細節被拉到

我想你想運行一個查詢合(例如無論是消息或用戶被刪除。)所有的信息通過連接或更復雜的地方聲明。

選項1:這可能需要進行調整,以不表的笛卡爾積

SELECT n.id, n.type, m.id, m.body, u.username, u.first_name 
FROM notifications n, messages m, users u 
WHERE n.user_id = :userid AND m.id = n.feature_id AND u.id = m.sender 

選項2:如果表的別名不工作,那麼你就需要與完整的表名

SELECT SELECT n.id, n.type, m.id, m.body, u.username, u.first_name 
FROM notifications n 
    JOIN messages m 
     ON n.feature_id = m.id 
    JOIN users u 
     ON m.sender = u.id 
WHERE n.user_id = :userid 

+0

但我將來會有很多不同類型的通知。消息,文章,用戶等等。我不能一次抓住所有的信息嗎? – Harry

+0

發佈需要「調整」的答案有什麼意義? –

+0

@Harry你所有的'types'都在消息表中,發送者,接收者,主體的基本格式是?如果是這樣,那麼應該沒有問題。 – miah