高性能MySQL——查询性能优化
在數據庫設計中,如果查詢寫得很糟糕,即使庫表結構設計再合理,索引再合理也無法實現高性能。
1、優化數據訪問
查詢性能低下最基本的原因是訪問的數據太多。對于低效的查詢,通過以下兩步來分析總是很有效:
是否向數據庫請求了不需要的數據
有些查詢會請求超過實際需要的數據,然后被應用程序丟棄,這會增加MySQL服務器的額外負擔,也會增加網絡開銷。
典型案例:
MySQL是否掃描額外的記錄
對于MySQL,最簡單的衡量查詢開銷的三個指標:響應時間;掃描行數;返回行數。
一般MySQL能夠使用三種方式應用where條件,從優到劣依次為:
如果發現查詢需要掃描大量數據,但是只返回少量數據時,可以嘗試如下方法去優化它:
2、重構查詢的方式
- 讓緩存的效率更高。許多引用程序可以方便的緩存單表查詢對應的結果對象;
- 將查詢分解后,執行單個查詢可以減少鎖的爭用;
- 在應用層做關聯,可以更容易對數據庫做拆分,更容易做到高性能和可擴展;
- 查詢本身效率也可能會有所提升。例如:使用IN()代替關聯查詢,可以讓MySQL按照ID順序進行查詢,這可能比隨機關聯更高效;
- 可以減少冗余記錄的查詢。
3、查詢執行的基礎(略)
4、MySQL查詢優化器的局限性
關聯子查詢
例如:SELECT * FROM film WHERE film_id IN(SELECT film_id FROM film_actor WHERE actor_id = 1); MySQL優化器優化后:SELECT * FROM film WHERE EXISTS(SELECT film_id FROM film_actor WHERE actor_id = 1 AND film_actor.film_id = film.film_id);
從優化器優化后的結果可以看出,MySQL會將相關外層表壓到子查詢中,此時子查詢需要根據“film_id”來關聯外部表film,因為需要“film_id”字段,MySQL認為無法執行子查詢,所以會對film表執行全表掃描,如此性能就非常低了。
優化方案:通過關聯查詢來改寫關聯子查詢。例如:SELECT film.* FROM film INNER JOIN film_actor USING(film_id) WHERE actor_id = 1;
UNION的限制
有時候MySQL不能將限制條件從外層下到內層。例如:希望UNION的各個子句能夠根據LIMIT只取部分結果集,或希望先排序再合并結果集,就需要在UNION的各個子句分別使用這些子句。
如:(SELECT first_name, last_name FROM actor ) UNION (SELECT first_name, last_name FROM customer) ORDER BY last_name LIMIT 20;
優化方案:(SELECT first_name, last_name FROM actor?ORDER BY last_name?LIMIT 20) UNION (SELECT first_name, last_name FROM customer?ORDER BY last_name?LIMIT 20) LIMIT 20;
松散索引掃描
由于歷史原因,MySQL不支持松散索引掃描,也就無法按照不連續的方式掃描一個索引。
例如:存在索引key(a, b);執行查詢SELECT * FROM table WHERE b BETWEEN 2 AND 5;?因為索引的前導字段是列a,但查詢中只指定了b,顧MySQL無法使用這個索引;
優化方案:給前導列加上可能的常數值。SELECT * FROM table WHERE a IN (2, 3, 5, ...) AND b BETWEEN 2 AND 5;
在同一張表上查詢和更新
MySQL不允許對同一張表同時進行查詢和更新。可以通過生成臨時表的形式來繞過此限制。
例如:UPDATE tbl AS outer_tbl SET cnt = (SELECT count(*) FROM tbl AS inner_tbl WHERE inner_tbl.type = outer_tbl.type);
優化方案:UPDATE tbl INNER JOIN(SELECT type, count(*) AS cnt FROM tbl GROUP BY type) SET tbl.cnt = der.cnt;
5、查詢優化器的提示
如果對優化器選擇的執行計劃不滿意,可以使用優化器提供的幾個提示(hint)來控制最終執行計劃。具體用法可查閱MySQL官方手冊。
6、優化特定類型的查詢
優化count()查詢
count()的作用:count()是一個特殊的聚合函數,有兩種非常不同的用法:統計某列值的數量;統計行數。在統計列值時,要求列值時非空的(不統計null)。如果count()括號中時某列或某列的表達式,則統計的是這個表達式有值的結果數。
? 優化關聯查詢
- 確保ON或者USING子句中的列上有索引;
- 確保任何GROUP BY 和 ORDER BY 中的表達式只涉及到一個表中的列,這樣MySQL才有可能利用索引來優化此過程;
- 當升級MySQL的時候需要注意:關聯語法、運算符優先級等其他可能會發生變化的地方。
優化子查詢
子查詢盡可能使用關聯查詢代替。但如果時MySQL5.6或更新版本或MariaDB,可忽略關于子查詢的這些優化建議。
優化GROUP BY 和DISTINCT
優化LIMIT分頁
優化UNION查詢
MySQL總是通過創建并填充臨時表的方式來執行UNION查詢。因此很多優化策略在UNION中都沒法很好的使用,經常需要手動將WHERE、LIMIT、GROUP BY 等子句下推到UNION的各個子查詢中。
注意:除非確實需要服務器消除重復行,否則一定要使用UNION All。因為如果沒有ALL關鍵字,MySQL會給臨時表加上DISTINCT選項,這會導致對臨時表的數據做唯一性檢查。
?
轉載于:https://www.cnblogs.com/zhuxiong/p/8268504.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的高性能MySQL——查询性能优化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 参考文献引用网页怎么标注 ?
- 下一篇: Redis-相关概念记录