MySQL中慢SQL優(yōu)化方法小結(jié)
優(yōu)化思路
慢sql的優(yōu)化無非是從兩個方向著手
- SQL語句本身的優(yōu)化
- 據(jù)庫設(shè)計的優(yōu)化
下面進行漸進式的分享一些常見優(yōu)化手段
避免查詢不必要的列
查詢應(yīng)該精準(zhǔn)的查出需要的列,對于select * 的寫法要避免,因為所有字段查出來不僅sql查詢執(zhí)行慢,若是直接返回給前端,大量的數(shù)據(jù)也會影響網(wǎng)絡(luò)傳輸效率。
分頁優(yōu)化
對于數(shù)據(jù)量特別大,這時分頁會比較深,查詢掃描的數(shù)據(jù)量會比較大效率自然低,我們就需要進行分頁優(yōu)化
假設(shè)我們有一個包含大量訂單記錄的訂單表,其中每個訂單都有一個唯一的不包含業(yè)務(wù)邏輯的主鍵,并且我們想要查詢最近一個月的訂單并按照訂單id從小到大進行分頁顯示某頁。
假設(shè)出現(xiàn)深分頁的sql如下:
select * from orders where order_date >= date_sub(now(), interval 1 month) order by id limit 100000, 10;
執(zhí)行此SQL時需要先掃描到100000行,然后再去取10行,但是隨著掃描的記錄數(shù)越多,SQL的性能就會越差,因為掃描的記錄越多,MySQL需要掃描越多的數(shù)據(jù)來定位到具體的多少行,這樣耗費大量的 IO 成本和時間成本。
對于解決該深分頁問題通常有兩種方法
1.延遲關(guān)聯(lián)
先通過 where 條件提取出主鍵,在將該表與原數(shù)據(jù)表關(guān)聯(lián),通過主鍵 id 提取數(shù)據(jù)行,而不是通過原來的二級索引提取數(shù)據(jù)行
優(yōu)化后sql:
select o.* from ( select id from orders where order_date >= date_sub(now(), interval 1 month) order by id limit 100000, 10 ) as sub join orders as o on sub.id = o.id;
優(yōu)化后SQL中的子查詢只取主鍵id,可避免通過二級索引中的主鍵去回表查詢,這樣性能會快一些。
2.id偏移量
偏移量就是找到 limit 第一個參數(shù)對應(yīng)的主鍵值,根據(jù)這個主鍵值再去過濾并 limit,這種方法又稱為基于游標(biāo)的分頁。基于游標(biāo)的分頁的前提是需要保證主鍵或排序列的連續(xù)性、唯一性。
優(yōu)化后sql:
select * from orders where id >= (select id from orders order by id limit 100000, 1) order by id limit 10;
這種方法相對于原來直接使用偏移量和限制結(jié)果數(shù)量的方式,可以在大數(shù)據(jù)集上提供更穩(wěn)定和一致的性能,因為它不需要掃描和跳過大量的行。
索引優(yōu)化
通過合理的設(shè)計和使用索引,能夠有效優(yōu)化sql性能,這也是我們使用最多的手段。
下面介紹一下如何進行索引優(yōu)化:
使用覆蓋索引
InnoDB使用二級索引查詢數(shù)據(jù)時會回表,但是如果索引的葉節(jié)點中已經(jīng)包含要查詢的字段,那它沒有必要再回表查詢了,這就叫覆蓋索引,還有一個簡單的理解查詢列都是索引列。
示例:
select product_name, price from products where category_id = 1; create index idx_category_id on products (category_id, product_name, price);
避免使用or查詢
在 MySQL 5.0 之前的版本要盡量避免使用 or 查詢,可以使用 union 或者子查詢來替代,因為早期的MySQL版本使用 or 查詢可能會導(dǎo)致索引失效,高版本引入了索引合并,解決了這個問題,不過建議大家在實際使用中還是規(guī)范寫法,能不用就少用。
避免使用 != 或者 <>操作符
SQL中,不等于操作符會導(dǎo)致查詢引擎放棄查詢索引,引起全表掃描,即使比較的字段上有索引。解決方法:通過把不等于操作符改成 or,可以使用索引,避免全表掃描
id <>'aaa' id >'aaa'or id<'aaa
適當(dāng)使用前綴索引
適當(dāng)?shù)厥褂们熬Y索引,可以降低索引的空間占用,提高索引的查詢效率。比如,郵箱的后綴都是固定的“@xxx.com”,那么類似這種后面幾位為固定值的字段就非常適合定義為前綴索引
create index idx_email_prefix on users (email(6)); -- 假設(shè)后綴長度為6
需要注意的是,前綴索引也存在缺點,MySQL無法利用前綴索引做 order by和 group by 操作,也無法作為覆蓋索引。
避免列上函數(shù)運算
要避免在列字段上進行算術(shù)運算或其他表達式運算,否則可能會導(dǎo)致存儲引擎無法正確使用索引,從而影響了查詢的效率。
select order_id from orders where total_amount / 2 > 100
正確使用聯(lián)合索引
使用聯(lián)合索引的時候,注意最左匹配原則。
JOIN優(yōu)化
優(yōu)化子查詢
盡量使用 Join 語句來替代子?xùn)嗽?,因為子?xùn)嗽兪乔短撞樵?,而嵌套查詢會新?chuàng)建一張臨時表,而臨時表的創(chuàng)建與銷毀會占用一定的系統(tǒng)資源以及花費一定的時間,同時對于返回結(jié)果集比較大的子查詢,其對查詢性能的影響更大
小表驅(qū)動大表
關(guān)聯(lián)查詢的時候要拿小表去驅(qū)動大表,因為關(guān)聯(lián)的時候,MySQL內(nèi)部會遍歷驅(qū)動表,再去連接被驅(qū)動表
select name from小表 left join 大表;
適當(dāng)增加冗余字段
增加冗余字段可以減少大量的連表查詢,因為多張表的連表查詢性能很低,所有可以適當(dāng)?shù)脑黾尤哂嘧侄危詼p少多張表的關(guān)聯(lián)查詢,這是以空間換時間的優(yōu)化策略。
避免使用 JOIN 關(guān)聯(lián)太多的表
《阿里巴巴 Java 開發(fā)手冊》規(guī)定不要 join 超過三張表,第一join 太多降低査詢的速度,第二 join 的buffer 會占用更多的內(nèi)存。
排序優(yōu)化
利用索引掃描做排序
MYSQL有兩種方式生成有序結(jié)果:一是對結(jié)果集進行排序的操作,二是按照索引順序掃描得出的結(jié)果,索引是排好序的數(shù)據(jù)結(jié)構(gòu),自然是有序的。
但是如果索引不能覆蓋查詢所需列(覆蓋索引),就會每掃描一條記錄回表查詢一次(逐個獲取),這個讀操作是隨機 IO,通常會比順序全表掃描還慢,有時會直接放棄使用索引轉(zhuǎn)為全表掃描。因此,在設(shè)計索引時,盡可能使用同一個索引既滿足排序又用于查找行。
#索引為 a,b,c select b,c from test where a like 'aa%' order by b,c;
只有當(dāng)索引的列順序和 ORDER BY 子句的順序完全一致,并且所有列的排序方向都一樣時,才能夠使用索引來對結(jié)果做排序。
UNION 優(yōu)化
條件下推
MySQL處理 union 的策略是先創(chuàng)建臨時表,然后將各個查詢結(jié)果填充到臨時表中最后再來做查詢,很多優(yōu)化策略在 union 查詢中都會失效,因為它無法利用索引。所以需要將 where、limit 等子句下推到 union 的各個子查詢中,以便優(yōu)化器可以充分利用這些條件進行優(yōu)化。
此外,除非確實需要服務(wù)器去重,一定要使用 union all,如果不加 all 關(guān)鍵字,MySQL 會給臨時表加上distinct 選項,這會導(dǎo)致對整個臨時表做唯一性檢查,代價很高。
到此這篇關(guān)于MySQL中慢SQL優(yōu)化方法小結(jié)的文章就介紹到這了,更多相關(guān)MySQL慢SQL優(yōu)化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL數(shù)據(jù)庫維護中監(jiān)控所用到的常用命令
這篇文章主要介紹額MySQL監(jiān)控時常用的的幾個MySQL命令,需要的朋友可以收藏下2013-08-08MySQL中創(chuàng)建時間和更新時間的自動更新的實現(xiàn)示例
本文主要介紹了MySQL中創(chuàng)建時間和更新時間的自動更新的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07MYSQL設(shè)置觸發(fā)器權(quán)限問題的解決方法
這篇文章主要介紹了MYSQL設(shè)置觸發(fā)器權(quán)限問題的解決方法,需要的朋友可以參考下2014-09-09MySQL腳本批量自動插入數(shù)據(jù)及數(shù)據(jù)可按條件插入實現(xiàn)
在初始化數(shù)據(jù)庫或者導(dǎo)入一些數(shù)據(jù)時,常常會用到批量的操作,本文主要介紹了MySQL腳本批量自動插入數(shù)據(jù)及數(shù)據(jù)可按條件插入實現(xiàn),具有一定的參考價值,感興趣的可以了解一下2024-01-01Windows下實現(xiàn)MySQL自動備份的批處理(復(fù)制目錄或mysqldump備份)
Windows下實現(xiàn)MySQL自動備份的批處理,新建目錄并復(fù)制壓縮,結(jié)合windows計劃任務(wù)方便實現(xiàn)每天的自動備份2012-05-05phpstudy中mysql無法啟動(與本地安裝的mysql沖突)的解決方式
這篇文章主要給大家介紹了關(guān)于phpstudy中mysql無法啟動(與本地安裝的mysql沖突)的解決方式,文中通過圖文將解決的方法介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09使用Kubernetes集群環(huán)境部署MySQL數(shù)據(jù)庫的實戰(zhàn)記錄
這篇文章主要介紹了使用Kubernetes集群環(huán)境部署MySQL數(shù)據(jù)庫,主要包括編寫 mysql.yaml文件,執(zhí)行如下命令創(chuàng)建,通過相關(guān)命令查看創(chuàng)建結(jié)果,對Kubernetes部署MySQL數(shù)據(jù)庫的過程感興趣的朋友一起看看吧2022-05-05