日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
Java如何定位自己項(xiàng)目中的慢業(yè)務(wù)

我們都知道,在日常開(kāi)發(fā)中我們經(jīng)常遇到在釘釘群或者在業(yè)務(wù)群中會(huì)出現(xiàn)各種各樣的慢業(yè)務(wù)的接口,比如某個(gè)接口在釘釘群瘋狂出現(xiàn),然后就有某些領(lǐng)導(dǎo)艾特你來(lái)解決這個(gè)慢業(yè)務(wù)問(wèn)題,今天阿粉就來(lái)說(shuō)說(shuō)如何通過(guò)各種手段來(lái)定位慢業(yè)務(wù)問(wèn)題,以及如何解決慢業(yè)務(wù)的問(wèn)題。

定位慢業(yè)務(wù)問(wèn)題

首先我們先來(lái)說(shuō)這么慢業(yè)務(wù)問(wèn)題,一般的慢業(yè)務(wù)問(wèn)題,總歸就那么幾種,SQL 問(wèn)題,代碼業(yè)務(wù)問(wèn)題,前端解析問(wèn)題,前端的解析問(wèn)題我們就不說(shuō)了,為什么呢?因?yàn)槿绻乔岸私馕鼍徛脑?,身為后端,我們也沒(méi)什么好的處理辦法,但是如果另外的兩種情況,那么我們就可以來(lái)好好的掰扯一下了。

代碼業(yè)務(wù)問(wèn)題

那么什么是會(huì)出現(xiàn)代碼業(yè)務(wù)問(wèn)題呢?

循環(huán)調(diào)用:

這種情況,一般都循環(huán)調(diào)用同一段代碼,每次循環(huán)的邏輯一致,前后不關(guān)聯(lián)。比如說(shuō),我們要初始化一個(gè)列表,預(yù)置12個(gè)月的數(shù)據(jù)給前端

List list = new ArrayList<>();
for(int i = 0 ; i < 12 ; i ++) {
// 計(jì)算某個(gè)月的數(shù)據(jù),邏輯比較復(fù)雜,難以批量計(jì)算,效率也無(wú)法很高
Model model = calOneMonthData(i);
list.add(model);
}

這只是其中來(lái)計(jì)算某些數(shù)據(jù),但是甚至還有人會(huì)在循環(huán)中去查詢一些表的數(shù)據(jù),也就是我們通常所說(shuō)的最不可取的那種 for 循環(huán)中有查詢。

如果這時(shí)候每個(gè)月的數(shù)據(jù)計(jì)算相互都是獨(dú)立的,我們完全可以采用多線程方式進(jìn)行:

// 建立一個(gè)線程池,注意要放在外面,不要每次執(zhí)行代碼就建立一個(gè),具體線程池的使用就不展開(kāi)了
public static ExecutorService commonThreadPool = new ThreadPoolExecutor(5, 5, 300L,
TimeUnit.SECONDS, new LinkedBlockingQueue<>(10), commonThreadFactory, new ThreadPoolExecutor.DiscardPolicy());

// 開(kāi)始多線程調(diào)用
List> futures = new ArrayList<>();
for(int i = 0 ; i < 12 ; i ++) {
Future future = commonThreadPool.submit(() -> calOneMonthData(i););
futures.add(future);
}

// 獲取結(jié)果
List list = new ArrayList<>();
try {
for (int i = 0 ; i < futures.size() ; i ++) {
list.add(futures.get(i).get());
}
} catch (Exception e) {
LOGGER.error("出現(xiàn)錯(cuò)誤:", e);
}

這是循環(huán)調(diào)用的那種,但是還有其他的,比如出現(xiàn)順序調(diào)用,那么就是執(zhí)行兩個(gè)方法,執(zhí)行方法a,然后再執(zhí)行方法B,這種情況也是可以進(jìn)行優(yōu)化的。

A a = methodA();

B b = methodB();

這時(shí)候我們可以使用 JDK8 中的異步編程來(lái)實(shí)現(xiàn),


CompletableFuture futureA = CompletableFuture.supplyAsync(() -> methodA());
CompletableFuture futureB = CompletableFuture.supplyAsync(() -> methodB());

CompletableFuture.allOf(futureA,futureB) // 等a b 兩個(gè)任務(wù)都執(zhí)行完成

這樣A B 兩個(gè)邏輯可以并行執(zhí)行。

CompletableFuture 這個(gè)阿粉就不講了,為什么呢?因?yàn)榘⒎墼谥暗奈恼轮幸呀?jīng)詳細(xì)的講過(guò)了,大家如果有興趣的話,可以翻看一下。

如果你檢查過(guò)你的代碼之后,你發(fā)現(xiàn)并沒(méi)有能出現(xiàn)慢業(yè)務(wù)的操作,那么接下來(lái)就是重頭戲了。

SQL導(dǎo)致的慢業(yè)務(wù)

SQL導(dǎo)致的慢業(yè)務(wù),這個(gè)是七成以上的開(kāi)發(fā)都會(huì)遇到的問(wèn)題。因?yàn)橛邪俜种?0左右的慢業(yè)務(wù)都是因?yàn)樽约旱穆齋QL引起的。

那么我們?cè)撛趺慈ザㄎ贿@個(gè)慢SQL呢?

慢查詢?nèi)罩居涗浡齋QL

定位慢SQL可以通過(guò)慢查詢?nèi)罩緛?lái)查看慢SQL,默認(rèn)的情況下,MySQL數(shù)據(jù)庫(kù)不開(kāi)啟慢查詢?nèi)罩?slow query log),需要手動(dòng)把它打開(kāi)

SET GLOBAL slow_query_log = ‘ON’;

查看下慢查詢?nèi)罩九渲?/p>

SHOW VARIABLES LIKE ‘slow_query_log%’

explain查看分析SQL執(zhí)行計(jì)劃

當(dāng)我們?nèi)ザㄎ蛔约罕碇性黾拥乃饕袥](méi)有生效的時(shí)候,我們使用的一半都是 explain 關(guān)鍵字,通過(guò)關(guān)鍵字給我們返回的內(nèi)容,我們就能判斷我們寫(xiě)的SQL 有沒(méi)有命中索引。

那么他反饋的參數(shù)分別都是什么意思呢?

id 值相同時(shí),被視為一組從上向下執(zhí)行。

如果是子查詢,id 值會(huì)遞增,id 值越高,優(yōu)先級(jí)越高

id為NULL最后執(zhí)行

simple: 簡(jiǎn)單的select, 查詢中不包含子查詢或者 union。例如: select name from student where id= 100

primary: 子查詢中最外層查詢, 查詢中若包含任何復(fù)雜的子部分, 最外層的select被標(biāo)記為primary

derived:在 from 的列表中包含的子查詢被標(biāo)記成 derived(派生表)。例如: explain select id from (select id,name from student) student1 where name= ‘name100’

subquery:在 select 或 where 列表中包含了子查詢,則子查詢被標(biāo)記成 subquery。例如: explain select id from student where score = (select score from student where name=‘name100’);

union: union中的第二個(gè)或后面的select語(yǔ)句. 例如: EXPLAIN select id from student where id<12691055 UNION all select id from student where id<12691060;

顯示這一步所訪問(wèn)數(shù)據(jù)庫(kù)中表名稱. 有時(shí)候不是真實(shí)的表名, 可能是簡(jiǎn)稱

該字段看table所在的分區(qū), 值為NULL表示表未被分區(qū)

可能會(huì)使用到的索引

表示連接類型,查看索引執(zhí)行情況的一個(gè)重要指標(biāo) 以下性能從好到壞依次:system > const > eq_ref > ref >ref_or_null > index_merge > unique_subquery > index_subquery > range >index > ALL

system:這種類型要求數(shù)據(jù)庫(kù)表中只有一條數(shù)據(jù),是const類型的一個(gè)特例,一般情況下是不會(huì)出現(xiàn)的

const:通過(guò)一次索引就能找到數(shù)據(jù),一般用于主鍵或唯一索引作為條件,這類掃描效率極高,速度非???/p>

eq_ref:常用于主鍵或唯一索引掃描,一般指使用主鍵的關(guān)聯(lián)查詢 ref : 常用于非主鍵和唯一索引掃描

ref_or_null:這種連接類型類似于ref,區(qū)別在于MySQL會(huì)額外搜索包含NULL值的行

index_merge:使用了索引合并優(yōu)化方法,查詢使用了兩個(gè)以上的索引

unique_subquery:類似于eq_ref,條件用了in子查詢

index_subquery:區(qū)別于unique_subquery,用于非唯一索引,可以返回重復(fù)值

range:常用于范圍查詢,比如:between … and 或 In 等操作

index:全索引掃描

ALL:全表掃描

實(shí)際使用到的索引

實(shí)際使用到的索引的長(zhǎng)度

該列表示MySQL估算找到我們所需的記錄,需要讀取的行數(shù)

該列是一個(gè)百分比,是滿足條件的記錄數(shù)量與我們查詢了多少記錄數(shù)量的比值

該字段包含有關(guān)MySQL如何解析查詢的其他信息,它一般會(huì)出現(xiàn)這幾個(gè)值:

Usingfilesort:表示按文件排序,一般是在指定的排序和索引排序不一致的情況才會(huì)出現(xiàn),一般見(jiàn)于order by語(yǔ)句

Using index:表示是否用了覆蓋索引

Using temporary: 表示是否使用了臨時(shí)表,性能特別差,需要重點(diǎn)優(yōu)化,一般多見(jiàn)于groupby語(yǔ)句,或者union語(yǔ)句

Using where : 表示使用了where條件過(guò)濾

Using index condition:MySQL5.6之后新增的索引下推,在存儲(chǔ)引擎層進(jìn)行數(shù)據(jù)過(guò)濾,而不是在服務(wù)層過(guò)濾,利用索引現(xiàn)有的數(shù)據(jù)減少回表的數(shù)據(jù)

這個(gè)關(guān)鍵字是非常需要大家掌握的,因?yàn)槟芊浅?zhǔn)確的反映出你寫(xiě)的 SQL 語(yǔ)句到底有沒(méi)有命中索引,如果你的 SQL 都沒(méi)有命中索引的話,那么就可以從你的 SQL 上下手來(lái)解決這個(gè)慢業(yè)務(wù)的問(wèn)題了。

你學(xué)會(huì)怎么定位慢業(yè)務(wù)問(wèn)題了么?


分享文章:Java如何定位自己項(xiàng)目中的慢業(yè)務(wù)
文章出自:
http://www.dlmjj.cn/article/djhphgo.html