久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

MySQL查詢優(yōu)化的示例分析

132次閱讀
沒有評論

共計 6531 個字符,預(yù)計需要花費(fèi) 17 分鐘才能閱讀完成。

自動寫代碼機(jī)器人,免費(fèi)開通

丸趣 TV 小編給大家分享一下 MySQL 查詢優(yōu)化的示例分析,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

一、優(yōu)化的思路和原則有哪些

1、優(yōu)化更需要優(yōu)化的查詢
2、定位優(yōu)化對象的性能瓶頸
3、明確優(yōu)化的目標(biāo)
4、從 Explain 入手
5、多使用 profile
6、永遠(yuǎn)用小結(jié)果集驅(qū)動大結(jié)果集
7、盡可能在索引中完成排序
8、只取出自己需要的字段(Columns)
9、僅僅使用最有效的過濾條件
10、盡可能避免復(fù)雜的 join

相關(guān)免費(fèi)學(xué)習(xí)推薦:mysql 視頻教程

1、優(yōu)化更需要優(yōu)化的查詢

?高并發(fā)的低消耗(相對)的查詢 對整個系統(tǒng)影響遠(yuǎn)大于低并發(fā)高消耗的查詢。

2、定位優(yōu)化對象的性能瓶頸

?在拿到一條需要優(yōu)化的查詢時,我們首先要判斷出這個查詢的瓶頸到底是 IO 還是 CPU。到底是數(shù)據(jù)庫訪問消耗多還是數(shù)據(jù)的運(yùn)算(如分組排序)消耗多。

3、明確優(yōu)化的目標(biāo)

?了解數(shù)據(jù)庫目前整體狀態(tài),就能知道數(shù)據(jù)庫所能承受的最大壓力,也就是我們知道最悲觀狀況;
?要把握該查詢相關(guān)的數(shù)據(jù)庫對象信息,我們就能知道最理想和最糟糕狀態(tài)下需要消耗多少資源;
?要知道該查詢在應(yīng)用系統(tǒng)中的地位,我們可以分析出改查詢可以占用系統(tǒng)資源的比例,也能夠知道該查詢的效率對客戶的體驗影響有多大。

4、從 Explain 入手

Explain 能夠告訴你這個查詢在數(shù)據(jù)庫中是一個什么樣的執(zhí)行計劃來實現(xiàn)的。首先我們需要有個目標(biāo),通過不斷調(diào)整嘗試,再借助 Explain 來驗證結(jié)果是否滿足自己的需求,直到得到預(yù)期的結(jié)果。

5、永遠(yuǎn)用小結(jié)果集驅(qū)動大結(jié)果集

?很多人喜歡在 SQL 優(yōu)化的時候說用“小表驅(qū)動大表”,這個說法是不嚴(yán)謹(jǐn)?shù)摹R驗榇蟊斫?jīng)過 where 條件過濾后返回的結(jié)果集并不一定就比小表所返回的結(jié)果集大,這個時候還用大表驅(qū)動小表,就會得到相反的性能效果。
?這樣的結(jié)果也非常容易理解,在 MySQL 中的 Join,只有 Nested Loop 一種 Join 方式,也就是 MySQL 的 Join 都是通過嵌套循環(huán)來實現(xiàn)的。驅(qū)動結(jié)果集越大,所需要循環(huán)的此時就越多,那么被驅(qū)動表的訪問次數(shù)自然也就越多,而每次訪問被驅(qū)動表,即使需要的邏輯 IO 很少,循環(huán)次數(shù)多了,總量自然也不可能很小,而且每次循環(huán)都不能避免的需要消耗 CPU,所以 CPU 運(yùn)算量也會跟著增加。所以,如果我們僅僅以表的大小來作為驅(qū)動表的判斷依據(jù),假若小表過濾后所剩下的結(jié)果集比大表多很多,結(jié)果就是需要的嵌套循環(huán)中帶來更多的循環(huán)次數(shù),反之,所需要的循環(huán)次數(shù)就會更少,總體 IO 量和 CPU 運(yùn)算量也會少。而且,就算是非 Nested Loop 的 Join 算法,如 Oracle 中的 Hash Join,同樣是小結(jié)果集驅(qū)動大的結(jié)果集是最優(yōu)的選擇。
?所以,在優(yōu)化 Join Query 的時候,最基本的原則就是“小結(jié)果集驅(qū)動大結(jié)果集”,通過這個原則來減少嵌套循環(huán)中的循環(huán)次數(shù),達(dá)到減少 IO 總量以及 CPU 運(yùn)算的次數(shù)。盡可能在索引中完成排序

6、只取出自己需要的字段(Columns)

?對于任何查詢,返回的數(shù)據(jù)都是需要通過網(wǎng)絡(luò)數(shù)據(jù)包傳輸給客戶端,如果取出的 Column 越多,需要傳輸?shù)臄?shù)據(jù)量自然會越大,不論從網(wǎng)絡(luò)帶寬還是網(wǎng)絡(luò)傳輸緩沖區(qū)來看,都是一種浪費(fèi)。

7、僅僅使用最有效的過濾條件

?舉個例子一個用戶表 user 有 id 和 nick_name 等字段,索引是 id 和 nike_name 兩個索引,下面是兩個查詢語句

#1
select * from user where id = 1 and nick_name =  zs 
selet * from user where id = 1

?兩個查詢得到結(jié)果是一樣的,但是第一個語句用到的索引占用空間是比第二個語句大很多的。占用空間大也代表著要讀取的數(shù)據(jù)量也更多。,也就是說 2 的查詢語句才是最優(yōu)查詢。

8、避免復(fù)雜的 join 查詢

?我們的查詢語句所涉及到的表越多,所需要鎖定的資源就越多。也就是說,越復(fù)雜的 Join 語句,所需要鎖定的資源也就越多,所阻塞的其他線程也就越多。相反,如果我們將比較復(fù)雜的查詢語句分拆成多個較為簡單的查詢語句分步執(zhí)行,每次鎖定的資源也就會少很多,所阻塞的其他線程也要少一些。
?可能很多人會有疑問,將復(fù)雜 Join 語句分拆成多個簡單的查詢語句之后,那不是我們的網(wǎng)絡(luò)交互就會更多了嗎?網(wǎng)絡(luò)延時方面的總體消耗也就更大了啊,完成整個查詢的時間不是反而更長了嗎?是的,這種情況是可能存在,但也并不是肯定就會如此。我們可以再分析一下,一個復(fù)雜的查詢語句在執(zhí)行的時候,所需要鎖定的資源比較多,可能被別人阻塞的概率也就更大,如果是一個簡單的查詢,由于需要鎖定的資源較少,被阻塞的概率也會小很多。所以 較為復(fù)雜的連接查詢也有可能在執(zhí)行之前被阻塞而浪費(fèi)更多的時間。而且我們的數(shù)據(jù)庫所服務(wù)的并不是單單這一個查詢請求,還有很多很多其他的請求,在高并發(fā)的系統(tǒng)中,犧牲單個查詢的短暫響應(yīng)時間而提高整體處理能力也是非常值得的。優(yōu)化本身就是一門平衡與取舍的藝術(shù),只有懂得取舍,平衡整體,才能讓系統(tǒng)更優(yōu)。

二、利用 Explain 和 Profiling

1、Explain 使用

各種信息展示

字段說明 ID 執(zhí)行計劃中查詢的序列號 Select_type 查詢類型:
DEPENDENT SUBQUERY : 子查詢中內(nèi)層的第一個 SELECT, 依賴于外部查詢結(jié)果集;
DEPENDENT UNION:子查詢中的 UNION 中從第二個 SELECT 開始的后面所有 SELECT, 同樣依賴于外部查詢結(jié)果集;
PRIMARY: 子查詢中的最外層查詢,不是主鍵查詢;
SUBQUERY:子查詢內(nèi)層查詢的第一個 SELECT, 結(jié)果不依賴于外部結(jié)果集;
UNCACHEABLE SUBQUERY:結(jié)果集無法緩存的子查詢;
UNION:UNION 語句中第二個 SELECT 開始的后面所有 SELECT, 第一個 SELECT 為 PRIMARY
UNION RESULT:UNION 中的合并結(jié)果 Table 所訪問的數(shù)據(jù)庫中表名稱 TYPE 訪問方式:
ALL: 全表掃描
const: 常量,最多只有一條記錄匹配,由于是常量,所以實際上只需要讀一次
eq_ref: 最多只有一條匹配結(jié)果,一般是主鍵或者唯一索引來訪問的
index: 全索引掃描
range: 索引范圍掃描
ref: jion 語句中被驅(qū)動表索引的引用查詢
system: 系統(tǒng)表,表中只有一行數(shù)據(jù) Possible_keys 可能用到的索引 Key 使用的索引 Key_len 索引長度 Rows 估算出來的結(jié)果集記錄條數(shù) Extra 額外信息

2、Profiling 使用

該工具可以獲取一條 Query 在整個執(zhí)行過程中多種資源消耗情況,如 CPU,IO,IPC,SWAP 等,以及發(fā)生 PAGE FAULTS, CONTEXT SWITCHE 等等,同時還能得到該 Query 執(zhí)行過程中 MySQL 所調(diào)用的各個函數(shù)在源文件中的位置。

1、開啟 profiling 參數(shù) 1- 開啟,0- 關(guān)閉

# 開啟 profiling 參數(shù)  1- 開啟,0- 關(guān)閉 set profiling=1;SHOW VARIABLES LIKE  %profiling%

2、然后執(zhí)行一條 Query
MySQL 查詢優(yōu)化的示例分析
3、獲取系統(tǒng)保存的 profiling 信息

show PROFILES;

MySQL 查詢優(yōu)化的示例分析4、通過 QUERY_ID 獲取 profile 的詳細(xì)信息(下面以獲取 CPU 和 IO 為例)

show profile cpu, block io for QUERY 7;

MySQL 查詢優(yōu)化的示例分析

三、合理利用索引

1、什么是索引

?簡單來說,在關(guān)系型數(shù)據(jù)庫中,索引是一種單獨(dú)的,物理的對數(shù)據(jù)庫表中一列或者多列的值進(jìn)行排序的一種存儲結(jié)構(gòu)。就像書的目錄,可以根據(jù)目錄中的頁碼快速找到需要的內(nèi)容。
?在 MySQL 中主要有四種類型索引,分別是:B-Tree 索引,Hash 索引,F(xiàn)ullText 索引,R-Tree 索引,下面主要說一下我們常用的 B -Tree 索引,其他索引可以自行查找資料。

2、索引的數(shù)據(jù)結(jié)構(gòu)

?一般來說,MySQL 中的 B -Tree 索引的物理文件大多數(shù)都是以平衡樹的結(jié)構(gòu)來存儲的,也就是所有實際需要存儲的數(shù)據(jù)都存儲于樹的葉子節(jié)點,二到任何一個葉子節(jié)點的最短路徑的長度都是完全相同的。MySQL 中的存儲引擎也會稍作改造,比如 Innodb 存儲引擎的 B -Tree 索引實際上使用的存儲結(jié)構(gòu)是 B +Tree, 在每個葉子節(jié)點存儲了索引鍵相關(guān)信息之外,還存儲了指向相鄰的葉子節(jié)點的指針信息,這是為了加快檢索多個相鄰的葉子節(jié)點的效率。
?在 Innodb 中,存在兩種形式的索引,一種是聚簇形式的主鍵索引,另外一種形式是和其他存儲引擎(如 MyISAM)存放形式基本相同的普通 B -Tree 索引,這種索引在 Innodb 存儲引擎中被稱作二級索引。
MySQL 查詢優(yōu)化的示例分析
?圖示中左邊為 Clustered 形式存放的 Primary Key,右側(cè)則為普通的 B-Tree 索引。兩種索引在根節(jié)點和 分支節(jié)點方面都還是完全一樣的。而 葉子節(jié)點就出現(xiàn)差異了。在主鍵索引中,葉子結(jié)點存放的是表的實際數(shù)據(jù),不僅僅包括主鍵字段的數(shù)據(jù),還包括其他字段的數(shù)據(jù),整個數(shù)據(jù)以主鍵值有序的排列。而二級索引則和其他普通的 B-Tree 索引沒有太大的差異,只是在葉子結(jié)點除了存放索引鍵的相關(guān)信息外,還存放了 Innodb 的主鍵值。
?所以,在 Innodb 中如果通過主鍵來訪問數(shù)據(jù)效率是非常高的,而如果是通過二級索引來訪問數(shù)據(jù)的話,Innodb 首先通過二級索引的相關(guān)信息,通過相應(yīng)的索引鍵檢索到葉子節(jié)點之后,需要再通過葉子節(jié)點中存放的主鍵值再通過主鍵索引來獲取相應(yīng)的數(shù)據(jù)行。
?MyISAM 存儲引擎的主鍵索引和非主鍵索引差別很小,只不過是主鍵索引的索引鍵是一個唯一且非空的鍵而已。而且 MyISAM 存儲引擎的索引和 Innodb 的二級索引的存儲結(jié)構(gòu)也基本相同,主要的區(qū)別只是 MyISAM 存儲引擎在葉子節(jié)點上面除了存放索引鍵信息之外,再存放能直接定位 MyISAM 數(shù)據(jù)文件中相應(yīng)的數(shù)據(jù)行的信息(如 Row Number),但并不會存放主鍵的鍵值信息。

3、索引的利弊

優(yōu)點:提高數(shù)據(jù)的檢索速度,降低數(shù)據(jù)庫的 IO 成本;
缺點:查詢需要更新索引信息帶來額外的資源消耗,索引還會占用額外的存儲空間

4、如何判斷是否需要建立索引

?上面說了索引的利弊,我們知道索引并不是越多越好,索引也會帶來副作用。那么我們該怎么判斷是否需要建立索引呢?
1、較頻繁的作為查詢條件的字段應(yīng)該創(chuàng)建索引;
2、更新頻繁的字段不適合建立索引;
3、唯一性太差的不適合創(chuàng)建索引,如狀態(tài)字段;
4、不出現(xiàn)在 where 中的字段不適合創(chuàng)建索引;

5、單索引還是組合索引?

?在一般的應(yīng)用場景,只要不是其中某個過濾字段在大多數(shù)場景下都能過濾 90% 以上的數(shù)據(jù),而且其他的過濾字段會頻繁更新,我一般更傾向于創(chuàng)建組合索引,尤其是在并發(fā)量較高的場景下更是如此。因為并發(fā)量搞的時候,即使我們?yōu)槊總€查詢節(jié)省很少 IO 消耗,但因為執(zhí)行量非常大,所節(jié)省的資源總量還是很大的。
?但是我們創(chuàng)建組合索引并不是說查詢條件中的所有字段都要放在一個索引中,我們應(yīng)該讓一個索引被多個查詢所利用,盡量減少索引的數(shù)量,以此來減少更新的成本和存儲成本。
?MySQL 為我們提供了一個減少優(yōu)化索引自身的功能,那就是“前綴索引”。也就是我們可以僅僅使用某個字段的前面部分內(nèi)容作為索引鍵來索引該字段, 減少索引所占用的空間和提高索引的訪問效率。當(dāng)然前綴索引只適合前綴比較隨機(jī)重復(fù)很少的字段。

6、索引的選擇

1、對于單鍵索引,盡量針對當(dāng)前查詢過濾最好的索引;
2、在選擇組合索引的時候,當(dāng)前查詢中過濾性最好的字段在索引字段順序中排列越靠前越好;
3、在選擇組合索引的時候,盡量選擇可以能夠包含當(dāng)前查詢的 where 字句中更多字段的索引;
4、盡可能通過分析統(tǒng)計信息和調(diào)整查詢的寫法來達(dá)到選擇合適的的索引來減少通過人為 Hint 控制索引的選擇,以為這樣后期維護(hù)成本會很高。

7、MySQL 索引的限制

1、MyISAM 存儲引擎索引鍵長總和不能超過 1000 字節(jié);
2、BLOB 和 TEXT 類型字段只能創(chuàng)建前綴索引;
3、MySQL 不支持函數(shù)索引;
4、使用 != 或者 時候,MySQL 索引無法使用;
5、過濾字段使用函數(shù)運(yùn)算后,MySQL 索引無法使用;
6、jion 語句中近字段類型不一致的時候,MySQL 索引無法使用;
7、使用 like 如果是前匹配(如:’%aaa’),MySQL 索引無法使用;
8、使用非等值查詢的時候,MySQL 無法使用 HASH 索引;
9、字符類型是數(shù)字的時候要使用 =‘1’不可以直接使用 = 1;
10、不要使用 or 可以用 in 代替或者 union all;

8、Join 原理以及優(yōu)化

Join 原理:在 MySQL 中,只有一種 join 算法,就是大名鼎鼎的嵌套循環(huán),實際上就是通過驅(qū)動表的結(jié)果集作為循環(huán)基礎(chǔ)數(shù)據(jù),然后一條一條的通過該結(jié)果集中的數(shù)據(jù)作為過濾條件到下一個表中查詢數(shù)據(jù),然后合并結(jié)果。如果還有近參與,再通過前面的近結(jié)果集作為循環(huán)基礎(chǔ)數(shù)據(jù),再循環(huán)遍歷,如此往復(fù)。
優(yōu)化:
1、盡可能減少 Join 語句中的循環(huán)總次數(shù)(還記得前面說過的小結(jié)果集驅(qū)動大結(jié)果集嗎);
2、優(yōu)先優(yōu)化內(nèi)層循環(huán);
3、保證 Join 語句中被驅(qū)動表上的 Join 條件字段已經(jīng)被索引;
4、當(dāng)無法保證被驅(qū)動表的 Join 條件字段被索引且內(nèi)存資源充足條件下,不要吝嗇 Join buffer 的設(shè)置(join buffer 只會在 All,index,range 才能夠用的上);

9、ORDER BY 優(yōu)化

在 MySQL 中,ORDER BY 的實現(xiàn)只有兩種類型:
?1、通過有序的索引直接取得有序的數(shù)據(jù),這樣不用進(jìn)行任何排序操作即可得到客戶端要求的有序數(shù)據(jù);

?2、通過 MySQL 排序算法將存儲的引擎中返回的數(shù)據(jù)進(jìn)行排序然后再將排序后的數(shù)據(jù)返回給客戶端。

利用索引排序是最佳的方法,但是如果沒有索引林勇的時候,MySQL 主要兩種算法實現(xiàn):

?1、取出滿足過濾條件的用于排序條件的字段以及可以直接定位到行數(shù)據(jù)的行指針信息,在 Sort Buffer 中進(jìn)行實際的排序操作,然后利用排好序之后的數(shù)據(jù)根據(jù)行指針信息返回表中取得客戶端請求的其他字段的數(shù)據(jù),再返回給客戶端;

?2、根據(jù)過濾條件一次取出排序字段以及客戶端請求的所有其他字段的數(shù)據(jù),并將不需要排序的字段存放在一塊內(nèi)存區(qū)域中,然后在 Sort Buffer 中將排序字段和行指針信息進(jìn)行排序,最后再利用排序后的行指針與存放在內(nèi)存區(qū)域中和其他字段一起的行指針信息進(jìn)行匹配合并結(jié)果集,再按照順序返回給客戶端。

?第二種算法相較于第一種算法,主要就是減少了數(shù)據(jù)的二次訪問。在排序好后,不需要再次回到表中取數(shù)據(jù),節(jié)省了 IO 操作。當(dāng)然第二種算法會消耗更多的內(nèi)存,一種典型的以空間換取時間的優(yōu)化方式。

?對于多表 Join 排序是先通過一個臨時表將之前 Join 的結(jié)果集存放入臨時表之后再將臨時表的數(shù)據(jù)取到 Sort Buffer 中進(jìn)行操作。

對于非索引排序的時候,盡量選擇第二種算法來進(jìn)行排序,手段有:

?1、加大 max_length_for_sort_data 參數(shù)設(shè)置:
?MySQL 決定使用哪個算法是通過參數(shù) max_length_for_sort_data 來決定的,當(dāng)我們返回字段的最大長度小于這個參數(shù)時候,MySQL 就會選擇第二中算法,相反則第一種算法。所以在有充足內(nèi)存情況下,加大這個參數(shù)值可以讓 MySQL 選擇第二種算法;

?2、減少不必要的返回字段
?上面一樣的道理,字段少了,就會盡量小于 max_length_for_sort_data 參數(shù);

?3、增大 sort_buffer_size 參數(shù)設(shè)置:
?增大 sort_buffer_size 并不是為了讓 MySQL 可以選擇改進(jìn)版的排序算法,而是為了讓 MySQL 可以盡量減少在排序過程中對需要排序的數(shù)據(jù)進(jìn)行分段,因為這樣會造成 MySQL 不得不使用臨時表來進(jìn)行交換排序。

四、最后

?調(diào)優(yōu)其實是件很難的事情,調(diào)優(yōu)也不限于上面的查詢調(diào)優(yōu)。諸如表的設(shè)計優(yōu)化,數(shù)據(jù)庫參數(shù)的調(diào)優(yōu),應(yīng)用程序調(diào)優(yōu)(減少循環(huán)操作數(shù)據(jù)庫,批量新增;數(shù)據(jù)庫連接池;緩存;)等等。當(dāng)然還有很多調(diào)優(yōu)技巧只有在實際實踐中才能真正體會。只有自己以理論為基礎(chǔ),事實為依據(jù),不斷嘗試去提升自己,才能成為一個真正的調(diào)優(yōu)高手。

看完了這篇文章,相信你對“MySQL 查詢優(yōu)化的示例分析”有了一定的了解,如果想了解更多相關(guān)知識,歡迎關(guān)注丸趣 TV 行業(yè)資訊頻道,感謝各位的閱讀!

向 AI 問一下細(xì)節(jié)

正文完
 
丸趣
版權(quán)聲明:本站原創(chuàng)文章,由 丸趣 2023-12-04發(fā)表,共計6531字。
轉(zhuǎn)載說明:除特殊說明外本站除技術(shù)相關(guān)以外文章皆由網(wǎng)絡(luò)搜集發(fā)布,轉(zhuǎn)載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 姜堰市| 东平县| 南丹县| 虹口区| 平安县| 保定市| 肃宁县| 瑞金市| 通化县| 巴林右旗| 克拉玛依市| 濮阳市| 上饶市| 新安县| 阜新市| 乐都县| 牡丹江市| 汉源县| 宣恩县| 汪清县| 广州市| 望江县| 彝良县| 灌云县| 遂昌县| 晋宁县| 山东| 咸宁市| 曲松县| 西安市| 剑川县| 蒙山县| 澄迈县| 四会市| 广丰县| 银川市| 和田市| 乐至县| 庆安县| 宾川县| 建昌县|