優(yōu)化count()
1 降低單次查詢時間
- 正常使用 select count(*) from table_xx where ...
- 使用近似值 可以考慮使用EXPLAIN的結果集中的rows列的值作為結果集總數(shù)的近似值(實際上Google的搜索結果總數(shù)也是個近似值)本慕。當需要精確結果的時候肠缔,在單獨使用COUNT(*)來滿足需求。
- 做到索引覆蓋掃描, 但是因為where條件不固定,三星索引很難做到。
2 減少查詢次數(shù)
- 由于查詢條件不固定泞边,在第一次查詢總數(shù)時緩存逾条,后面直接從緩存中取數(shù)厂庇。(jvm堆緩存或者redis, 要考慮緩存失效問題)
3 更改分頁方案,直接不查詢總數(shù)
快速迷帜、精確物舒、實現(xiàn)簡單, 三者永遠只能滿足其二戏锹,必須舍棄其中一個冠胯。
優(yōu)化limit
通常使用limit加上偏移量的辦法實現(xiàn), 同時加上合適的order by子句锦针。如果有對應的索引荠察,通常效率會不錯,否則MySQL需要做大量的文件排序操作奈搜。
一個非常常見又令人頭疼的問題就是悉盆,在偏移量非常大的時候(翻頁到非常靠后的頁面)馋吗,例如可能是LIMIT 10000,20這樣的查詢焕盟,這時MySQL需要查詢10020條記錄然后只返回最后20條,前面10000條記錄都被拋棄宏粤,這樣的代價非常高脚翘。如果所有的頁面被訪問的頻率都相同,那么這樣的查詢平均需要訪問半個表的數(shù)據(jù)绍哎,要優(yōu)化這種查詢来农,要么在頁面中限制分頁的數(shù)量,要么是優(yōu)化大偏移量的性能崇堰。
優(yōu)化此類分頁查詢的一個最簡單的辦法就是盡可能地使用索引覆蓋查詢沃于,而不是查詢所有的列。然后根據(jù)需要做一個關聯(lián)操作再返回所需的列海诲。對于偏移量很大的時候繁莹,這樣做的效率會提升很大。
考慮下面的查詢饿肺。
mysql> SELECT film_id, description FROM sakila.film ORDER BY title LIMIT 50, 5;
如果這張表非常大蒋困,那么這個查詢最好改寫成下面的樣子:
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);
思考:和下面的區(qū)別:
SELECT film.film_id, film.description
FROM sakila.film where film_id >= (select film_id from sakila.film order by title limit 50,1) order by id limit 5;
這里的“延遲關聯(lián)”將大大提升查詢效率,它讓MySQL掃描盡可能的頁面敬辣,獲取需要訪問的記錄后再根據(jù)關聯(lián)列回原表查詢需要的所有列雪标。這項技術也可以用于優(yōu)化關聯(lián)查詢的LIMIT字句。
有時候也可以將LIMIT查詢轉換為已知位置的查詢溉跃,讓MySQL通過范圍掃描獲得到對應的結果(目前導出用的是這個思路)村刨。例如,如果在一個位置列上有索引撰茎,并且預先計算出了邊界值嵌牺,上面的查詢就可以改寫為:
mysql> SELECT film_id, description FROM sakila.film
-> WHERE position BETWEEN 50 AND 54 ORDER BY position
對數(shù)據(jù)進行排名的問題也與此類似,但往往還會和GROUP BY混合使用。在這種情況下通常需要預先計算并儲存排名信息逆粹。
LIMIT和OFFSET的問題募疮,它會導致MySQL掃描大量不需要的行然后再拋棄掉。如果可以使用書簽記錄上一次取數(shù)據(jù)的位置僻弹,那么下一次就可以直接從該書簽的位置開始掃描阿浓,這樣就可以避免使用OFFSET恐仑。例如矿辽,若需要按照租借記錄做翻頁,那么可以根據(jù)最新一條租借記錄向后追溯荤西,這種做法可行是因為租借記錄的逐漸是單調增長的卸耘。首先使用下面的查詢獲取第一組結果:
mysql> SELECT * FROM sakila.rental
-> ORDER BY rental_id DESC LIMIT 20;
假設上面的查詢返回的是主鍵為16049到16030的租借記錄退敦,那么下一頁查詢就可以直接從16030這個點開始:
mysql> SELECT * FROM sakila.rental
->WHERE rental_id < 16030
->ORDER BY rental_id DESC LIMIT 20;
該技術的好處是無論翻頁到多么后面,其性能都會很好蚣抗。
此外侈百,也可以用關聯(lián)到一個冗余表的方式提高LIMIT的性能,冗余表只包含主鍵列和需要做排序的數(shù)據(jù)列
結論:
1 使用以下語句優(yōu)化limit
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);
2 優(yōu)化頁面交互忠聚,避免count()查詢總數(shù)
將以上具體的頁數(shù)換成“下一頁”按鈕设哗,假設每頁顯示10條記錄,那么我們每次查詢時都是用limit返回11條記錄并顯示10條两蟀,如果第11條存在网梢,那么我們就顯示“下一頁”按鈕,否則就說明沒有更多的數(shù)據(jù)赂毯,也就無需顯示“下一頁”按鈕可战虏。
解決 MySQL 分頁數(shù)據(jù)錯亂重復
https://www.cnblogs.com/glon/p/6806064.html
MySQL 使用 limit 進行分頁時,可能會出現(xiàn)重復數(shù)據(jù)党涕,通過加入 order by 子句可以解決烦感,但是需要注意的是,如果排序字段有相同值的情況下膛堤,由于排序字段數(shù)據(jù)重復,可能會導致每次查詢排序后結果順序不同手趣,分頁還是會出現(xiàn)重復數(shù)據(jù),這時可以加入第二個排序字段肥荔,提高排序的唯一性绿渣,最好保證排序的字段在表中的值是唯一的,這樣就可以少寫一個排序字段燕耿,增加查詢效率中符,因為 order by 后面有多個排序字段時,無法用到索引誉帅。