MySQL分頁查詢優化

2021-09-19 06:46:26 字數 2220 閱讀 5907

之前搬磚的時候遇到對行數大的表進行分頁的操作,效能好差。最近在讀《高效能mysql》,正好講到這個方面的,記錄一下(基本上都是原文)。

在系統中需要進行分頁才做的時候,我們通常會使用limit加上偏移量的辦法實現,同時加上合適的order by字句。如果有對應的索引,通常效率會不錯,否則,mysql需要做大量的檔案排序操作。

乙個非常常見又令人頭疼的問題就是,在偏移量非常大的時候(翻頁到非常靠後的頁面),例如可能是limit 10000,20這樣的查詢,這時mysql需要查詢10020條記錄然後只返回最後20條,前面10000條記錄都被拋棄,這樣的代價非常高。如果素所的頁面被訪問的頻率都相同,那麼這樣的查詢平均需要訪問半個表的資料,要優化這種查詢,要麼在頁面中限制分頁的數量,要麼是優化大偏移量的效能。

優化此類分頁查詢的乙個最簡單的辦法就是盡可能地使用索引覆蓋查詢,而不是查詢所有的列。然後根據需要做乙個關聯操作再返回所需的列。對於偏移量很大的時候,這樣做的效率會提公升很大。考慮下面的查詢。

mysql> select film_id, description from sakila.film order by title limit 50, 5;
如果這張表非常大,那麼這個查詢最好改寫成下面的樣子:

mysql> select film.film_id, film.description

-> from sakila.film

-> inner join (

-> select film_id from sakila.film

-> order by title limit 50, 5

-> ) as lim using(film_id);

這裡的「延遲關聯」將大大提公升查詢效率,它讓mysql掃瞄盡可能的頁面,獲取需要訪問的記錄後再根據關聯列回原表查詢需要的所有列。這項技術也可以用於優化關聯查詢的limit字句。

有時候也可以將limit查詢轉換為已知位置的查詢,讓mysql通過範圍掃瞄獲得到對應的結果。例如,如果在乙個位置列上有索引,並且預先計算出了邊界值,上面的查詢就可以改寫為:

mysql> select film_id, description from sakila.film

-> where position between 50 and 54 order by position

對資料進行排名的問題也與此類似,但往往還會和group by混合使用。在這種情況下通常需要預先計算並儲存排名資訊。

limit和offset的問題,它會導致mysql掃瞄大量不需要的行然後再拋棄掉。如果可以使用書籤記錄上一次取資料的位置,那麼下一次就可以直接從該書籤的位置開始掃瞄,這樣就可以避免使用offset。例如,若需要按照租借記錄做翻頁,那麼可以根據最新一條租借記錄向後追溯,這種做法可行是因為租借記錄的逐漸是單調增長的。首先使用下面的查詢獲取第一組結果:

mysql> select * from sakila.rental

-> order by rental_id desc limit 20;

該技術的好處是無論翻頁到多麼後面,其效能都會很好。

分頁的時候,另乙個常用的技巧是在limit語句中加上sql_calc_found_rows提示(hint),這樣做可以獲得去掉limit以後滿足條件的行數,因此可以作為分頁的總數。看起來,mysql做了一些非常高深的優化,像是通過某種方法**了總行數。但實際上mysql只有在掃瞄了所有滿足條件的行,然後再拋棄掉不需要的行,而不是在滿足limit的行數後就終止掃瞄。所有該提示的代價可能非常高。(幾年前本菜鳥在大學做專案的時候,就是用這個查詢優化器的提示,以為這樣會減少查詢次數和掃瞄行數,後來我在工作後操作幾百萬行數的表的時候,這種方法效能很差)

一種做法是先獲取並快取較多的資料————例如,快取1000條————然後每次分頁都從這個快取中獲取。這樣做可以讓應用程式根據結果集的大小採取不同的策略,例如結果集少於1000,就可以在頁面上顯示所有的頁面鏈結,因為資料都在快取中,所以這樣做效能不會有問題。如果結果集大於1000,則可以在頁面上設計乙個額外的「找到的結果多餘1000條」之類的按鈕。這兩種策略都比每次生成全部結果集再拋棄掉不需要的資料的效率高很多。

有時候可以考慮使用explain的結果集中的rows列的值作為結果集總數的近似值(實際上google的搜尋結果總數也是個近似值)。當需要精確結果的時候,在單獨使用count(*)來滿足需求,這時如果能夠使用索引覆蓋掃瞄則通常會比sql_calc_found_rows快得多。

mysql 分頁優化 Mysql 查詢分頁優化

全表掃瞄,速度極慢 limit 語句的查詢時間與起始記錄的位置成正比 mysql 的 limit 語句是很方便,但是對記錄很多的表並不適合直接使用 建立測試表 drop table if exists t user create table test t user id int 10 unsigne...

Mysql 分頁查詢優化

分頁查詢優化 分頁查詢在 mysql 中常遇到,如以下語句 select from tablename limit 100,20 用時大約需要0.03 sec。用時很短。但是隨著偏移量的增加,查詢時間也隨之增加。比如如下 select from tablename limit 10000000,20...

MySQL分頁查詢優化

當需要從資料庫查詢的表有上萬條記錄的時候,一次性查詢所有結果會變得很慢,特別是隨著資料量的增加特別明顯,這時需要使用分頁查詢。對於資料庫分頁查詢,也有很多種方法和優化的點。下面簡單說一下我知道的一些方法。為了對下面列舉的一些優化進行測試,下面針對已有的一張表進行說明。三次查詢時間分別為 一般的分頁查...