台灣最大程式設計社群網站
線上人數
931
 
會員總數:245149
討論主題:189053
歡迎您免費加入會員
討論區列表 >> PHP >> PHP的分頁及置頂問題
[]  
[我要回覆]
回應主題 加入我的關注話題 檢舉此篇討論 將提問者加入個人黑名單
PHP的分頁及置頂問題
價值 : 50 QP  點閱數:1748 回應數:18

樓主

Yall
門外漢
0 4
68 4
發送站內信

小的目前用一個PHP做了一個BBS,並與MySQL連動,
基本上都做完了,但是有一個我就是想不到該怎麼做。
就是:當一個已經發表的文章受到其他人回復時,文章會置頂
我試過用時間排序

這樣有做到跳搜索的方式,但是我遇到的問題是
用時間排序時,因為舊有文章遭到置頂,所以會導致ID不是倒序排列的情況。
舉例來說
第一頁的資料依照上方排列(ID)是
2
9
8
7
6...
但是換到第二頁就會變成
2
5
4
3..
原因是因為我使用了where id<=$offs的關係,請問我該怎麼改寫,才能使他排序是依照時間並且又能跳過搜索(讓資料庫不會搜索太多而拖慢效能)?
像這樣:
第一頁:
2
9
8
7
6..
第二頁:
5
4
3
2..
我想了老半天就是找不到解法!

搜尋相關Tags的文章: [ 分頁及置頂問題 ] ,
本篇文章發表於2016-11-14 20:16
別忘捐VP感謝幫助你的人 新手會員瞧一瞧
1樓
回應

可樂快跑
檢舉此回應
二件事注意:
1.資料庫的搜尋速度遠比你想像中的快很多。這等到你有個上百甚至上千萬筆資料才有要開始考慮速度這件事。
2.你的limit還少一個必要的參數。
本篇文章回覆於2016-11-14 22:31
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
2樓
不錯的參考

浩瀚星空
捐贈 VP 給 浩瀚星空 檢舉此回應
看樣子你真的還有待加強了@@"

mysql的limit本身就可以做到你想做的事。
limit 取得數量

limit 開始位置,取得數量

這兩種用法。

你根本無需去做id的判斷。那是不可能判斷正常的。

你這支程式其實可以直接改成

另外如果會需要讀取置頂的文章處理原則上最好採用分開顯示。
因為我不太清楚你的置頂的文章是只會在第一頁上面顯示。還是每一頁都會出現的文章。
因為這樣的寫法各自有不同的寫法。

加強一下sql的語法應用吧。
本篇文章回覆於2016-11-15 11:44
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
3樓
作者回應

Yall
檢舉此回應
我的置頂文章是只有第一頁要顯示

還有我是想要用個東西讓他判斷
我知道可以用 limit 開始位置,取得數量
但是這會讓後面頁數的開始位置變高,使他搜索的數量過高呀!
本篇文章回覆於2016-11-15 18:22
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
4樓
回應

浩瀚星空
捐贈 VP 給 浩瀚星空 檢舉此回應
100萬筆的資料。從10萬筆取500筆。跟從50萬位置取500筆。
都是一樣的東西。

哪來的搜尋數量過高的問題啊???是誰教你這個的。

只有where條件才有可能會造成全表搜尋。
本篇文章回覆於2016-11-15 19:56
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
5樓
不錯的參考

可樂快跑
檢舉此回應
只能說發問者太小看資料庫處理資料的承載能力了。

事實上大部份會造成資料庫搜尋問題的,要不就是sql語句有問題。
還有資料庫設計結構有問題外。

我們看過最多問題的……是搜尋結果後又將結果再搜尋而且還重覆超多次。
這種不斷製造query才是拖整個速度的元兇。
本篇文章回覆於2016-11-15 21:49
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
6樓
回應

迷路
捐贈 VP 給 迷路 檢舉此回應
異議!樓主所提出的理由是正確的!
我拿一個總數在4百萬筆的資料表作測試

測試一,排序後取最前面的三十筆
SELECT * FROM `xxx` ORDER BY `ID` LIMIT 0 , 30
顯示第 0 - 29 列 (總計 4729413 筆, 查詢花費 0.0005 秒) [ID: 1 - 30]

測試二,排序後取中間三十筆
SELECT * FROM `xxx` ORDER BY `ID` LIMIT 2000000 , 30
顯示第 2000000 - 2000029 列 (總計 30 筆, 查詢花費 1.3243 秒) [ID: 2139916 - 2139952]

測試三,以條件式排除前半後排序,再取三十筆
SELECT * FROM `xxx` WHERE `ID` >2139915 ORDER BY `ID` LIMIT 0 , 30
顯示第 0 - 29 列 (總計 2729416 筆, 查詢花費 0.0055 秒) [ID: 2139916 - 2139952]

從時間上來看是有差別的,只不過一般做成系統負荷過大,等待時間過長的理由通常不是在這

另外找了一個總數在六十萬筆的資料表作測試
測試一,排序主鍵後取最前面三十筆
SELECT * FROM `yyy` ORDER BY `ID` LIMIT 0 , 30
顯示第 0 - 29 列 (總計 699307 筆, 查詢花費 0.0005 秒) [ID: 1382015 - 1382044]

測試二,排序非鍵值欄位後取最前面三十筆
SELECT * FROM `yyy` ORDER BY `CreatedTime` LIMIT 0 , 30
顯示第 0 - 29 列 (總計 699307 筆, 查詢花費 1.0840 秒) [CreatedTime: 2016-07-01 00:00:29 - 2016-07-01 00:06:44]

`CreatedTime`是建立資料的時間,`ID`是流水後主鍵,所以取出來的其實是同樣三十筆資料
但是時間整整差了兩千倍以上,這才是常碰到的問題點

最後扯回樓主的問題
資料庫的處理能力遠超你的想像,就算是四百萬筆資料排序取中段也不過就是1秒半不到的時間,所以不需要太過擔心
更重要的是
所謂優化這件事,必須建立在正確的執行結果上!!!
如果出來的結果不正確,速度再快效能再好也沒半點意義!!!
本篇文章回覆於2016-11-16 10:04
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
7樓
回應

可樂快跑
檢舉此回應
@迷路
如果你的資料是400萬筆,我估計你的測試3的limit改成2000000……時間應該又會拉長。

另外對主鍵索引跟對非主鍵索引本來時間上就會有差。
如果說某個欄位很經常被用作於搜尋條件的話,的確有必要加上索引。

因為樓主會有更新置頂的情形,所以他必然無法使用id做為置頂的條件,而必須用時間。
那麼他要做的就是把時間欄位加入index,這樣會加快搜尋效率。

不過置頂通常又有二種情形:文章依時間順序調整,以及板主手動置頂。
但是通常這二種情形都會各自給予不同的查詢條件再依序整理回view中顯示。

當然,sql語句處理得當或是不當本身對sql查詢的影響就很大。



本篇文章回覆於2016-11-16 11:45
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
8樓
回應

浩瀚星空
捐贈 VP 給 浩瀚星空 檢舉此回應
@迷路

你測試的方式,與我說的limit的東西意義不大。

你這樣的測試方式,只是在於order的問題而已。並非是limit的問題。
樓主的意思(我猜測的)
是從第0筆與從第10萬筆取100筆資料。後者需消耗很大的資源。
依照我解讀的意思是,他認為從10萬筆的位置取資料,還是需要全部取出來才取其100筆
這樣的論點是錯誤的。

如果是這樣,我現在有一筆高達1000萬筆的log。要怎麼活啊,光本身的資料將近1g多了。
不要太小看資料庫的能力。它沒那麼笨搞死自已。(不過有時它的確也很笨就是了)

關於order的問題,其實認真來說,它確實會影響到很大的效能。
畢竟它的動作一定得要全表取出才行。不過如果有做了索引。其影響其實是不大的。
因為這樣它本身就有索引庫可以直接處理。怕的就是並沒建立索引。

另回到主題。如果有針對置頂處理的話。其可以做多重排序。
假設置頂的欄位是top
那就可以用
SELECT * FROM db ORDER BY top DESC,CreatedTime ASC LIMIT 0 , 30
這樣就會先將置頂的文章排在最前面,然後再依照其發表的時間排序。

比較麻煩的是全文置頂的模式就是了。(也就是置頂文章是每一頁都出現的)
本篇文章回覆於2016-11-16 14:04
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
9樓
作者回應

Yall
檢舉此回應
所以根據以上各位大大所述
如果我非得要用
$info=mysql_query("SELECT ID,ti,user,time,del from bbs where id<=$offs order by id desc limit $info_num");
使用ID當做條件的話,就只能捨棄置頂功能囉?
本篇文章回覆於2016-11-16 19:48
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
10樓
回應

可樂快跑
檢舉此回應
@Yall
沒!你要做的事情應該是先棄用「mysql()」相關指令集
例如mysql_connect()、mysql_select_db()、mysql_query()這一類掛「mysql」開頭的。
基本建議使用mysqli指令集,而且要用他的物件導向用法。
最佳選擇則是使用pdo。
不明白pdo去google可以找到很多教學。

再來,沒有什麼叫做非得要用。你要做什麼功能,你就要用相對應的作法。
而不是堅持非要用什麼方法不可。

總之,建議你先去改用pdo,再來考慮優化你的sql語句,來達到你要的功能需求。

本篇文章回覆於2016-11-16 20:38
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
11樓
回應

迷路
捐贈 VP 給 迷路 檢舉此回應
ORDER的欄位有無索引,對於大資料表搜尋是很有感覺的
這也是我在第二組測試想表達的問題

但是如果說LIMIT對搜尋的時間沒有影響
那第一組測試的測試一和二超過2000倍的時間差就難以解釋了
畢竟都是無條件,排序也都是只用主鍵,也都是抓取全欄位資料
所以我才會認為LIMIT確實會對時間有影響
不過絕大多數的情況下,我不會將優化的重點放在避免使用LIMIT
本篇文章回覆於2016-11-17 09:50
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
12樓
回應

浩瀚星空
捐贈 VP 給 浩瀚星空 檢舉此回應
@Yall

程式要怎麼寫是隨便人想。重點是你要能符合優化的條件。
因為照你想要的做法。利用id來處理的話,又要計算置頂跟頁數的情況下。
一般來說只能用分批的方式來做處理。
這是吃力不討好的事,增加連線數量及增加效能消耗。

我也只能給你能比較優化的方式而已,重點是你想要達到的結果是什麼而已。
想用id來做處理,你就得考驗你的數學能力。我倒是可以教你一招。

如一頁顯示100筆資料的話。你每次都取150筆(用你所謂的id判斷處理)
再用程式扣除置頂的量另外抓取。

可以的話,將置頂的量給緩存起來。這樣就不需要每一頁去從新計算。

@迷路

LIMIT的影響確實是有。但一般這是非常小的影響。
就如0.1跟0.00000001來說。看起來差了百萬倍。
但實際感覺上其實也是一瞬間。

就如我上面的倉庫說。走到定位位置也是需要時間的。(光要跑索引檔就需要一些時間了)
但使用條件式的處理方式。就是原本就該要處理的方式。將定點位置不要拉到那麼長。
自然其速度就是會快。

說真的~~~真400萬筆每頁取1000筆好了。4000頁的資料有誰會想要去看呢??
在資料庫或是報表的操作面來講,做這樣的事本身就是一種錯誤了。

為何不能用id來判斷取值,可以啊~~~~
也就是拿id來當筆數跳躍。為何不行??
當然是可以的。但為何沒人想要這樣做?

因為~~~要達到這樣的條件,
其一你的id一定得要連號且無中斷。
所以~~~當你無法做到上面這一個條件。limit才是你最好的選擇。

程式設計有百種,哪種是否是最好的。見仁見智。
就像你說的用where條件後再撈資料。這樣當然是最好的效能。
畢竟我不需要再跑這好幾百萬筆的資料。

只是~~~~如果說只是為了微秒的時間差距。造成我日後的可能性問題。
那我情願不要。如上面說的id建立方式。哪天哪個傢伙手賤給你從中刪了幾筆。
或是需要做資料轉移的情況下。
你覺得上面的方式是否會造成麻煩呢???不是嗎???

本篇文章回覆於2016-11-17 17:21
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
13樓
作者回應

Yall
檢舉此回應
其實我不一定要用id當做條件
我只是需要有一個WHERE的值可以當做LIMIT的搜索條件而已
不一定是ID,只是我想不出那個方法
本篇文章回覆於2016-11-18 22:33
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
14樓
最有價值解答

可樂快跑
檢舉此回應
@Yall
你可以設定where time >= 日期 (如果你是存在unix time會比較好處理)
然後在這日期之後的再照日期排序,最新的會在最前面,資料取出然後limit的內容也就不會過多。
一般條件來了where大都是設id為「= 」而少用使用id做比較「大小」的情形。(也就是指定那一筆)
你如果有其他搜尋排序的條件應該都是其他的欄位。
然後對速度有疑慮就把那個會做為搜尋的欄位也做索引。
你的問題其實一點都不複雜。
是你想的太複雜。
本篇文章回覆於2016-11-19 11:15
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
15樓
作者回應

Yall
檢舉此回應
原來這麼簡單阿!
不過我是用DATETIME的形式儲存
要把它轉成unix time嗎?
還是說DATETIME也可以比較,因為之前有用過>=去比較,結果不行
本篇文章回覆於2016-11-19 20:48
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
   

回覆
如要回應,請先登入.