看板 PHP 關於我們 聯絡資訊
※ 引述《gname ((′口‵)↗︴<><...<><)》之銘言: : : 但又擔心被cookie檔案被解開有安全信的顧慮, 其實我覺得 cookie 沒啥不好,至少這不算什麼機敏資料...吧? 除了綁電腦跟 cookie 有大小限制以外沒想到什麼問題 嗯..好吧,每次都跟 request 一起傳回 server 感覺很冗,量大時看起來討厭 然後電腦換手機就會破功 : 突然想到一個很 low 的方法...XD : 我會在加一個欄位:read : 內容是把讀過的文章ID記起來, 例如: 11,22,33 這樣 : 然後撈DB時就用 not in 去撈......XD : 至於"無限擴充"我個人覺得不用想那麼遠,想像一下文章應該會有時效性, : 總不可能我進站你撈一個10年前的文章給我看吧? 「一個欄位」去存,那就是逗點分隔。這樣沒辦法用 in 來處理 MySQL 的話大概會用 find_in_set() 之類的鬼東西來下 或是整串讀出來用 PHP 邏輯判斷 缺點? - Code 不好看 - 資料不好看 - 看過一百篇文章就是一百個逗點分隔數字,聽起來就很討厭 - 欄位長度有上限,沒辦法無限擴充 - 會被有強迫症的人(例如我)抱怨資料沒有正規化 符合正規化而且不會爆欄位的做法是開一個 article_read table id user_id article_id create_time --------------------------------------------- 1 1 11 {timestamp} 2 2 11 {timestamp} 3 1 22 {timestamp} 4 3 22 {timestamp} 然後下個 user_id + article_id 的 index 確保你能快速抓到某個使用者是否讀過某篇文章 不過資料筆數會是個小問題 一千個使用者一天看十篇文章,那就是一天一萬筆資料 一年就是三百六十五萬筆 於是 會員資料數: 1000 ...以上 文章資料數: 3650 讀取紀錄數:3650000 這數字看起來感覺不太爽,而且資料成長的速度會正比於你的活躍使用者數跟文章數 反過來說,這是能處理的量,只存數字的 table 也不會太胖 如果你的使用情境需要存那就存吧 更何況,你的網站不一定會成長到這麼多人用...[遠目] 至於「不要無限擴充」,這邊正好有個案例:PTT 的看板已讀 https://github.com/ptt/pttbbs/blob/master/docs/brc.txt <- 說明 https://github.com/ptt/pttbbs/blob/master/mbbsd/brc.c <- code - 一年以上文章一律當已讀 - 一個看版紀錄 80 筆文章已讀紀錄 - 最多存 73 個看板的紀錄 - 儲存 expire_time,expire_time 之前的文章一律視為已讀 - 儲存 modified time,可以用來判斷推文 一句話說完就是「存最近N筆紀錄,多的丟掉,太舊的當成已讀」 這解決空間會持續膨脹的問題,只要資料長度不會無限增加 那麼放 cookie 還是放逗點分隔還是開專門 table 都是可行的方法 不過已讀未讀的判斷會有些問題 - 如果單純紀錄「最近一百筆」,那連看一百筆舊文章之後最新文章會從已讀變未讀 - PTT 的搞法我沒看懂(不會寫C了...),不過在八卦版連讀八十篇文章之後 會整個版的文章都變成已讀 反過來,如果你不喜歡這些靈異現象,或覺得使用者看到三年前的文章也該標未讀 那還是乖乖的開個 table 存完整的紀錄吧... -- 莉娜用魔法爆破進入屋內。 劫犯從另一個房間裡出現,大叫道︰「妳是誰!」 莉娜︰「我是個可疑的女人!」 劫犯無言以對。 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 61.218.242.230 ※ 文章網址: https://www.ptt.cc/bbs/PHP/M.1438775603.A.E8D.html 回頭看到標題才發現不對,我一直在想已讀紀錄,你要的是隨機撈未讀..... 「施主,隨機不好弄啊,苦海無涯回頭是岸」.... 講是這樣講,還是想一下可能的做法。 首先我是會限制要隨機的範圍,例如說「一年內的文章」或「最近一千篇文章」 如果我不限制範圍,那麼會變成我得拿「全部的文章」去比「全部的已讀紀錄」 這兩個都是會一直變大的東西,最好是不要每次開網頁都整份讀出來... 然後把「範圍內的文章 ID」扣掉「已經讀過的文章 ID」,最後隨機挑一筆 這邊實務可能像這樣 // 假設 query() 會回傳包含所有 id 的 array // 先只讀 id 而不讀全部文章資料,DB 可以少讀不少東西,會比較快 $sql = 'SELECT id FROM article ORDER BY publish_time DESC LIMIT 1000' $new_article_ids = query($sql); $sql = 'SELECT id FROM record WHERE user=1 ORDER BY time DESC LIMIT 1000' $read_ids = query($sql); $candidate_ids = array_diff($new_article_ids, $read_ids); $chosen_id = $candidate_ids[rand(0, count($candidate_ids) - 1)]; $article_data = getArticleData($chosen_id); 這邊會需要注意的問題有 - 讀取一年內/最近一千筆資料的時間會不會很久? - 可能會,可能不會...不過有限制數量的話至少不會越來越久 - 萬一使用者全部都看過怎麼辦? - 施主,這問題要問你自己.... 還有一個方法是,如果你保證文章 id 連號 那麼可以先 SELECT max(id) FROM article,然後 $article = null; $limit = 300; // 最多 try 300 次 for (; $limit > 0; $limit--) { $candidate_id = rand(0, $max_id); if (!isRead($candidate_id)) { $article = getArticleData($candidate_id); break; } } if (null === $article) { // 顯示錯誤訊息 } else { // 顯示文章 } ※ 編輯: GALINE (61.218.242.230), 08/05/2015 20:34:36
tas72732002: 效能是最大的隱憂 08/05 20:36
GALINE: 效能要測過,固定讀三千筆資料會不會「太慢」要看情況而定 08/05 20:38
GALINE: 當然情感上不喜歡,但是這會動 XD 08/05 20:39
GALINE: 不過確定會越跑越慢的東西就必須避免,所以不能每次都掃 08/05 20:40
GALINE: 整個 table, table 會變大... 08/05 20:40
GALINE: 讀最近一千筆太多的話,那至少也可以讀進一百筆.. 08/05 20:41
※ 編輯: GALINE (61.218.242.230), 08/05/2015 20:42:40
GALINE: 是說文章變動頻率不高,可以寫 memcache 紀錄最近n筆id... 08/05 20:58
gname: 推~重點是要解決數量膨漲與範圍內的抓取資料,而不是任由 08/06 00:28
gname: 膨漲再來解決效能問題 08/06 00:28