SQL分頁過多時, 如何優化


問題:

我們經常會使用到分頁操作,這里有個問題,在偏移量非常大的時候,它會導致MySQL掃描大量不需要的行然后再拋棄掉。如:

SELECT id, name FROM A ORDER BY id DESC LIMIT 10000, 20;

上述這條SQL語句需要查詢10020條記錄然后只返回最后20條。前面的10000條記錄都將被拋棄,這樣代價非常高。

 

方法一、延遲關聯

優化此類分類查詢的一個最簡單的辦法就是盡可能地使用索引覆蓋掃描如果一個索引包含(或者說覆蓋)所有需要查詢的字段的值,我們就稱之為“覆蓋索引”。可以使用explain查看extra列信息,如果看到“Using index”的信息則說明使用到了覆蓋索引。),而不是查詢所有的列。然后根據需要做一次關聯操作再返回所需的列。對於偏移量很大的時候,這樣做的效率會提升非常大。

如上述SQL語句可以修改為:

SELECT id, name 
     FROM A 
         INNER JOIN (
            SELECT id FROM A 
            ORDER BY id DESC LIMIT 10000, 20
         ) AS tmp USING(id);

這里的“延遲關聯”將大大提升查詢效率,它讓MySQL掃描盡可能少的頁面,獲取需要訪問的記錄后再根據關聯列回原表查詢需要的所有列。

 

方法二、使用書簽記錄上次取數據的位置

可以使用書簽記錄上次取數據的位置,那么下次就可以直接從該書簽記錄的位置開始掃描,這樣就可以避免使用OFFSET。

如上一次記錄到10000為止,則可以修改為:

SELECT id, name FROM A WHERE id < 10000 ORDER BY id DESC LIMIT 20;

這種方法的好處是無論翻頁到多么后面,其性能都會很好。

 

方法三:使用between and

有時候也可以將LIMIT查詢轉換為已知位置的查詢,讓MySQL通過范圍掃描獲得到對應的結果。

如知道邊界值為10000,10020后上述語句可以修改為:

SELECT id , name FROM A WHERE id BETWEEN 10000 AND 10020 ORDER BY id DESC;

 

 

除上述方法外,還有一些其它方法,如:

  • 使用預先計算的匯總表
  • 關聯到一個冗余表,冗余表只包含主鍵列和需要做排序的數據列
  • 使用Sphinx優化一些搜索操作

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM