2009-09-01 57 views
6

正如你們可能知道的那樣,在MySQL中使用LIMIT關鍵字並不排除它讀取前面的記錄。如何使用PHP和MySQL高效分頁大型數據集?

例如:

SELECT * FROM my_table LIMIT 10000, 20; 

意思是,MySQL仍然會讀取第一個10000條記錄,併產生20我們是前後扔掉。

因此,當分頁大型數據集時,高頁數意味着很長的加載時間。

有誰知道任何現有的分頁類/技術/方法,可以更有效的方式分頁大型數據集,即不依賴於LIMIT MySQL關鍵字嗎?

在PHP中如果可能的話,那是在我公司選擇的武器。

乾杯。

+2

如果您的數據集不太可能發生變化,您可以計算背景中每個元素的頁面索引,然後只在索引字段中選擇分頁。可能發生的情況是,偶爾你偶爾會在頁面上出現n + 1個元素。 – Zed 2009-09-01 11:39:15

+2

http://stackoverflow.com/questions/1243952/how-can-i-speed-up-a-mysql-query-with-a-large-offset-in-the-limit-clause – Sampson 2009-09-01 11:39:48

回答

1

解決方案可能不使用限制子句,而是使用連接 - 連接用作某種序列的表。

欲瞭解更多信息,在SO,我發現這個question/answer,這給出了一個例子 - 可以幫助你;-)

+1

感謝隊友我會看看! – Evernoob 2009-09-02 10:00:51

0

我不知道你提到的性能下降,我不知道有任何其他的分頁解決方案,但是一個ORDER BY子句可能會幫助你減少加載時間。

0

最好的方法是在my_table中定義索引字段,併爲每個新插入的行添加此字段。畢竟,你需要使用WHERE YOUR_INDEX_FIELD(10000和10020之間),它會快得多。

+1

這就要求你永遠不要刪除任何行,並且不顯示聚合。 – nos 2009-09-01 11:58:17

1

基本上有3種方法來此,每一個都有自己的權衡:

  1. 向客戶端發送所有10000條記錄,並通過Javascript或類似方式處理客戶端分頁。顯而易見的好處是對於所有記錄只需要一個查詢;顯而易見的缺點是,如果記錄大小有任何意義,發送給瀏覽器的頁面大小將成比例大小 - 用戶可能實際上並不關心整個記錄集。

  2. 做你正在做的事情,即SQL LIMIT,只抓取每個請求所需的記錄,完全無狀態。受益在於它只發送當前請求頁面的記錄,因此請求很小,其缺點在於a)它需要每個頁面的服務器請求,並且b)隨着記錄/頁面數量增加結果,正如你所提到的那樣。在單調遞增的id字段中使用JOIN或WHERE子句有時可以有所幫助,特別是如果您要求靜態表而不是動態查詢的結果。

  3. 在緩存查詢結果的服務器上維護某種狀態對象,並且可以在將來的請求中在有限的時間段內引用它。最重要的是它具有最好的查詢速度,因爲實際查詢只需要運行一次;缺點是不得不管理/存儲/清理那些狀態對象(特別是對於高流量網站來說令人討厭)。

0

一些其他的選擇,

  • 分區按每一頁表,因此忽略了極限
  • 存儲結果到一個會話(一個好的想法是使用創建數據的哈希md5,然後使用該緩存會話每個多個用戶)
+0

不是真的把這樣一個大型數據集存儲到會話中的粉絲 – Evernoob 2009-09-01 13:24:36

6

首先,如果你想分頁,你絕對必須有一個ORDER BY子句。那麼你只需要使用該子句來深入挖掘數據集。例如,考慮這個:

SELECT * FROM my_table ORDER BY id LIMIT 20 

您將獲得前20條記錄,假設他們的ID是:5,8,9,...,55,64。您的分頁鏈接到第2頁將看起來像「list.php的?頁= 2 & ID = 64」和您的查詢就會

SELECT * FROM my_table WHERE id > 64 ORDER BY id LIMIT 20 

無偏移,只有20條記錄讀取。它不允許你隨意跳到任何頁面,但大多數時候人們只是瀏覽下一頁/上一頁。即使使用大的OFFSET值,「id」上的索引也會提高性能。

+0

這個沒有考慮到的唯一的東西就是被刪除的行(它假定ID一致的編號)...... – 2009-09-01 15:58:18

+0

這是個好主意,但是我也是需要頁碼,這意味着我必須a)永不刪除任何行或b)計算並存儲結束每頁的每個記錄的id的某處。 – Evernoob 2009-09-01 16:01:18

+0

如果你沒有得到足夠的行,只是請求更多。繼續分批請求,直到你得到足夠的,或者你得到0(這意味着沒有更多的行)。請確保跟蹤實際結束的位置,以便下一組行與顯示給用戶的內容相鄰,而不是檢索到的內容。 – longneck 2009-09-01 17:08:29

1
SELECT * FROM my_table LIMIT 10000, 20; 

手段顯示20條記錄,從記錄#10000在搜索開始,如果在where子句中使用主鍵UR不會有沉重的負載上我的SQL

爲pagnation將採取任何其他方法真正的巨大負載如使用連接方法