Java如何定位自己項目中的慢業(yè)務(wù)
我們都知道,在日常開發(fā)中我們經(jīng)常遇到在釘釘群或者在業(yè)務(wù)群中會出現(xiàn)各種各樣的慢業(yè)務(wù)的接口,比如某個接口在釘釘群瘋狂出現(xiàn),然后就有某些領(lǐng)導(dǎo)艾特你來解決這個慢業(yè)務(wù)問題,今天阿粉就來說說如何通過各種手段來定位慢業(yè)務(wù)問題,以及如何解決慢業(yè)務(wù)的問題。
定位慢業(yè)務(wù)問題
首先我們先來說這么慢業(yè)務(wù)問題,一般的慢業(yè)務(wù)問題,總歸就那么幾種,SQL 問題,代碼業(yè)務(wù)問題,前端解析問題,前端的解析問題我們就不說了,為什么呢?因為如果是前端解析緩慢的話,身為后端,我們也沒什么好的處理辦法,但是如果另外的兩種情況,那么我們就可以來好好的掰扯一下了。
代碼業(yè)務(wù)問題
那么什么是會出現(xiàn)代碼業(yè)務(wù)問題呢?
循環(huán)調(diào)用:
這種情況,一般都循環(huán)調(diào)用同一段代碼,每次循環(huán)的邏輯一致,前后不關(guān)聯(lián)。比如說,我們要初始化一個列表,預(yù)置12個月的數(shù)據(jù)給前端
這只是其中來計算某些數(shù)據(jù),但是甚至還有人會在循環(huán)中去查詢一些表的數(shù)據(jù),也就是我們通常所說的最不可取的那種 for 循環(huán)中有查詢。
如果這時候每個月的數(shù)據(jù)計算相互都是獨立的,我們完全可以采用多線程方式進行:
這是循環(huán)調(diào)用的那種,但是還有其他的,比如出現(xiàn)順序調(diào)用,那么就是執(zhí)行兩個方法,執(zhí)行方法a,然后再執(zhí)行方法B,這種情況也是可以進行優(yōu)化的。
這時候我們可以使用 JDK8 中的異步編程來實現(xiàn),
這樣A B 兩個邏輯可以并行執(zhí)行。
CompletableFuture 這個阿粉就不講了,為什么呢?因為阿粉在之前的文章中已經(jīng)詳細的講過了,大家如果有興趣的話,可以翻看一下。
如果你檢查過你的代碼之后,你發(fā)現(xiàn)并沒有能出現(xiàn)慢業(yè)務(wù)的操作,那么接下來就是重頭戲了。
SQL導(dǎo)致的慢業(yè)務(wù)
SQL導(dǎo)致的慢業(yè)務(wù),這個是七成以上的開發(fā)都會遇到的問題。因為有百分之70左右的慢業(yè)務(wù)都是因為自己的慢SQL引起的。
那么我們該怎么去定位這個慢SQL呢?
慢查詢?nèi)罩居涗浡齋QL
定位慢SQL可以通過慢查詢?nèi)罩緛聿榭绰齋QL,默認的情況下,MySQL數(shù)據(jù)庫不開啟慢查詢?nèi)罩?slow query log),需要手動把它打開
查看下慢查詢?nèi)罩九渲?/p>
- slow_query_log:表示慢查詢開啟的狀態(tài)
- slow_query_log_file:表示慢查詢?nèi)罩敬娣诺奈恢?/li>
explain查看分析SQL執(zhí)行計劃
當我們?nèi)ザㄎ蛔约罕碇性黾拥乃饕袥]有生效的時候,我們使用的一半都是 explain 關(guān)鍵字,通過關(guān)鍵字給我們返回的內(nèi)容,我們就能判斷我們寫的SQL 有沒有命中索引。
那么他反饋的參數(shù)分別都是什么意思呢?
- id
id 值相同時,被視為一組從上向下執(zhí)行。
如果是子查詢,id 值會遞增,id 值越高,優(yōu)先級越高
id為NULL最后執(zhí)行
- select_type
simple: 簡單的select, 查詢中不包含子查詢或者 union。例如: select name from student where id= 100
primary: 子查詢中最外層查詢, 查詢中若包含任何復(fù)雜的子部分, 最外層的select被標記為primary
derived:在 from 的列表中包含的子查詢被標記成 derived(派生表)。例如: explain select id from (select id,name from student) student1 where name= ‘name100’
subquery:在 select 或 where 列表中包含了子查詢,則子查詢被標記成 subquery。例如: explain select id from student where score = (select score from student where name=‘name100’);
union: union中的第二個或后面的select語句. 例如: EXPLAIN select id from student where id<12691055 UNION all select id from student where id<12691060;
- table
顯示這一步所訪問數(shù)據(jù)庫中表名稱. 有時候不是真實的表名, 可能是簡稱
- partitions
該字段看table所在的分區(qū), 值為NULL表示表未被分區(qū)
- possible_keys
可能會使用到的索引
- type
表示連接類型,查看索引執(zhí)行情況的一個重要指標 以下性能從好到壞依次:system > const > eq_ref > ref >ref_or_null > index_merge > unique_subquery > index_subquery > range >index > ALL
system:這種類型要求數(shù)據(jù)庫表中只有一條數(shù)據(jù),是const類型的一個特例,一般情況下是不會出現(xiàn)的
const:通過一次索引就能找到數(shù)據(jù),一般用于主鍵或唯一索引作為條件,這類掃描效率極高,速度非常快
eq_ref:常用于主鍵或唯一索引掃描,一般指使用主鍵的關(guān)聯(lián)查詢 ref : 常用于非主鍵和唯一索引掃描
ref_or_null:這種連接類型類似于ref,區(qū)別在于MySQL會額外搜索包含NULL值的行
index_merge:使用了索引合并優(yōu)化方法,查詢使用了兩個以上的索引
unique_subquery:類似于eq_ref,條件用了in子查詢
index_subquery:區(qū)別于unique_subquery,用于非唯一索引,可以返回重復(fù)值
range:常用于范圍查詢,比如:between … and 或 In 等操作
index:全索引掃描
ALL:全表掃描
- key
實際使用到的索引
- key_len
實際使用到的索引的長度
- rows
該列表示MySQL估算找到我們所需的記錄,需要讀取的行數(shù)
- filtered
該列是一個百分比,是滿足條件的記錄數(shù)量與我們查詢了多少記錄數(shù)量的比值
- extra
該字段包含有關(guān)MySQL如何解析查詢的其他信息,它一般會出現(xiàn)這幾個值:
Usingfilesort:表示按文件排序,一般是在指定的排序和索引排序不一致的情況才會出現(xiàn),一般見于order by語句
Using index:表示是否用了覆蓋索引
Using temporary: 表示是否使用了臨時表,性能特別差,需要重點優(yōu)化,一般多見于groupby語句,或者union語句
Using where : 表示使用了where條件過濾
Using index condition:MySQL5.6之后新增的索引下推,在存儲引擎層進行數(shù)據(jù)過濾,而不是在服務(wù)層過濾,利用索引現(xiàn)有的數(shù)據(jù)減少回表的數(shù)據(jù)
這個關(guān)鍵字是非常需要大家掌握的,因為能非常準確的反映出你寫的 SQL 語句到底有沒有命中索引,如果你的 SQL 都沒有命中索引的話,那么就可以從你的 SQL 上下手來解決這個慢業(yè)務(wù)的問題了。
你學(xué)會怎么定位慢業(yè)務(wù)問題了么?