各位好:
目前想到的換頁(pagination)方式流程大概如下:
(PHP+MYSQL)
1.第一次query先撈出總筆數,並做好相關分頁計算,也準備將這些值帶入下一次的limit設定中
2.第二次query取出所有資料(limit筆數)
我是有聽過最好減少資料庫query的次數,盡量縮減成一次query就好?
尤其是在千人存取的環境下...
問題一:所以還有更好的query方式嗎?
問題二:我要來轉成PDO方式存取,概念是否雷同?
SUDO程式碼:
$smt="from test where name='john' ";
$query = "SELECT COUNT(*) as num $smt "; //第一次query
$result = mysql_query($query, $connection);
$query_data = mysql_fetch_row($result);
資料總筆數 = $query_data[0]; //取出SQL條件限制下的總筆數
....進行分頁所需計算:如算出頁數等....
略
//第二次query
$query = "SELECT tname FROM $smt limit 位置,10";
$result = mysql_query($query, $connection);
while($row=mysql_fetch_array($result)){
//loop
}
兩次 query 是分頁 general case 必要的成本。
不過因為第一次只是在算次數,假如索引設好的話,第一次 query 的成本是蠻低的。
另外,如果這個分頁是屬於《非個人化》,也就是一堆人上來所看到的分頁內容其實是同一頁,那就可以考慮使用暫存,例如下面的虛擬碼:
<pre class="c" name="code">if (暫存庫已經有這一頁資料,且未過期)
{
直接由暫存庫取出頁面資料輸出
}
else
{
由資料庫查詢 // 這個就是你現在寫的程式碼
存到暫存庫中一段時間
輸出頁面資料
}
但假如每個人上來看的頁面會依身份不一樣,比如你這例子有 where name='john' 可能是只看自己的資料,那就沒法暫存,或者暫存只能供自己看 (因為可能有 user 會在前後頁反覆翻來翻去,就不用每一次都向資料庫查詢)。
使用暫存,要注意的是暫存時間。就看這頁面資料變化的頻率而定了。
兩次 query 是分頁 general case 必要的成本。
ok!!那我大概知道了,
換頁主要是還是先透過(1)查出總筆數,框出所需的範圍後,以及產生供相對應的頁數等資料使用。
(2)在指定的範圍下(limit)在query一次。
看來是無可避免,以及應該是在可承受的範圍內。
另外wiseguy兄提到的,
我之前也有在實作。
將資料內容取出後存成文字檔緩存,避免每次都從mysql資料庫開啟撈資料,在緩存時間內直接從文字檔開啟(include進來)
假設{緩存更新時間}設定5秒,則在5秒內(未過時)的讀取內容都可以從文字檔載入,
若判斷到文字檔的本身檔案時間超過現在時間,則從mysql撈資料存到文字檔緩存。
if (file_exists($cachefile) && (filemtime($cachefile)+500)>time() ) {
include($cachefile);
exit;
}
ob_start();
//這邊要放資料輸出的文字,例如從mysql資料讀取
echo <<<EOD
echo "緩存時間:" . time();
//以上放資料輸出的文字
//以下為緩存更新檔案判斷
$fp = fopen($cachefile, 'w');
fwrite($fp, ob_get_contents());
fclose($fp);
ob_end_flush();
isthome提到:
$fp = fopen($cachefile, 'w');
fwrite($fp, ob_get_contents());
fclose($fp);
ob_end_flush();
這四行可以簡化成一行:
file_put_contents($cachefile, ob_get_clean());
isthome提到:
if (file_exists($cachefile) && (filemtime($cachefile)+500)>time() ) {
這一行也可以優化成
<pre class="c" name="code">if (($t = filemtime($cachefile)) !== FALSE && ($t+500)>(int)$_SERVER['REQUEST_TIME'] ) {
wiseguy兄:
發現若把四行簡化成一行:
file_put_contents($cachefile, ob_get_clean());
當程式要執行更新動作時,畫面會全空白....再來抓原因
喔~ 不好意思,沒注意你最後下的是 ob_end_flush() 那應該改用
file_put_contents($cachefile, ob_get_flush());