2015-08-23 65 views
0

我有超過6000個結果,大約超過235頁使用分頁。當我點擊第一頁時,它加載速度真的很快〜300毫秒,直到第40頁左右。之後它真的會在大約30〜40+秒的頁面加載時間下山。我正在使用索引數據庫。我試圖給我們mysql catch查詢,但不喜歡它。有人可以幫我嗎。php分頁大大減少或最後一頁減慢

PHP:

$sql = mysql_query("SELECT * FROM data WHERE (car = '$cars') AND (color = '$color' AND price BETWEEN '".$min."' AND '".$max."' 
ORDER BY price LIMIT {$startpoint} , {$limit}"); 

指數:

data 0 PRIMARY  1 id A 106199 NULL NULL  BTREE  
data 1 car_index 1 car  A 1799 NULL NULL  BTREE  
data 1 car_index 2 color A 2870 NULL NULL  BTREE  
data 1 car_index 3 price A 6247 NULL NULL  BTREE  
data 1 car_index 4 location A 106199 NULL NULL  BTREE  

回答

0

這將是在這裏發表的表結構,看看你有什麼指標是一個好主意。 請在列價格上添加索引,提高查詢性能。

Cheers

+0

我犯了一個單獨的指數價格,它只是增加的負載 – Matt

0

這是MySQL(和其他數據庫系統)的常見問題。使用LIMIT + OFFSET(這就是LIMIT x,y所隱含的使用方法),它起初效果很好,但隨着獲取行數的增長而呈指數級下降。 添加索引絕對是第一步,因爲您應該始終根據索引查詢數據,以避免全表掃描。

只有在價格上有索引是不夠的,因爲您有其他WHERE屬性。基本上,這是MySQL正在做的事情: 假設$limit = 25$startPoint = 0,MySQL將從頭開始讀取表,並在找到25個匹配的行並停止後返回它們。我們假設它在第一次迭代中讀取500行。下一次迭代,因爲它沒有car + color + price上的索引,它不知道如何直接跳轉到第25個匹配行(表中的第500行),因此它將從頭再次開始讀取,跳過前25個匹配行並返回25個匹配的行。我們假設這個迭代還需要讀取500個額外的行。

現在你看看發生了什麼問題。對於每一次迭代,MySQL都必須從頭開始讀取所有行,以指數方式增加返回行所需的時間。在我的示例中,要獲取100(25 * 4迭代)行,MySQL將不得不讀取500 + 1000 + 1500 + 2000 = 5000行,而您只能讀取500 * 4 = 2,000行。要獲取1000(25 * 40迭代)行,MySQL將不得不讀取500 + 1000 + 1500 + ... 20000 = 410,000行!這比您預期的500 * 40 = 20000行要多得多。

要優化您的查詢,請首先選擇您需要的數據(沒有SELECT *)。然後訣竅是記住最後提取的ID。

$lastFetchedId = 0; 
do { 
    $sql = mysql_query("SELECT * FROM data WHERE id > $lastFetchedId AND (car = '$cars' AND color = '$color' AND price BETWEEN '".$min."' AND '".$max."') 
ORDER BY price LIMIT {$limit}"); 

    $hasFoundRows = false; 
    while ($row = mysql_fetch_assoc($sql)) { 
     $hasFoundRows = true; 
     $lastFetchedId = $row['id']; 
     // do something with the row 
    } 
} while ($hasFoundRows === false); 

只有當您在WHERE子句中使用的所有列都有索引時,纔有MySQL處理排序的效果。這樣考慮一下:如果數據沒有被排序,MySQL如何知道哪些行將匹配以及匹配行的位置。爲了能夠對結果進行排序並僅返回一個子集,MySQL需要構建一個所有實際匹配行的排序列表。這意味着要遍歷整個表首先獲取所有匹配的行,然後對它們進行排序,最後只返回其中的一小部分。

希望幫助你更好地理解什麼,你可以做的更好在這裏:)

+0

獲取ID好主意的時間,但它不解決問題(加載時間是從〜30s到〜15s的1/2)。也許我做錯了什麼?我注意到你把「LIMIT {$ limit}」放在了「LIMIT {$ startpoint},{$ limit}」的位置,因爲第一個選項不能用作分頁。 – Matt

+0

$ lastFetchedId = 0; \t $ hasFoundRows = false; \t while($ row = mysql_fetch_assoc($ sql)){ \t $ hasFoundRows = true; $ lastFetchedId = $ row ['id']; } \t $ hasFoundRows === false; – Matt

+0

也應該記住,id是隨機的,因爲它按價格排序,其他行存在於 – Matt