亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

前言

在程序上線運行一段時間后,一旦數(shù)據(jù)量上去了,或多或少會感覺到系統(tǒng)出現(xiàn)延遲、卡頓等現(xiàn)象,出現(xiàn)這種問題,就需要程序員或架構(gòu)師進行系統(tǒng)調(diào)優(yōu)工作了。

其中,大量的實踐經(jīng)驗表明,調(diào)優(yōu)的手段盡管有很多,但涉及到SQL調(diào)優(yōu)的內(nèi)容仍然是非常重要的一環(huán),本文將結(jié)合實例,總結(jié)一些工作中可能涉及到的SQL優(yōu)化策略。

一、查詢優(yōu)化

可以說,對于大多數(shù)系統(tǒng)來說,讀多寫少一定是常態(tài),這就表示涉及到查詢的SQL是非常高頻的操作。

前置準備:給一張測試表添加10萬條數(shù)據(jù)。

使用下面的存儲過程給單表造一批數(shù)據(jù),將表換成自己的就好了。

create procedure addMyData()

begin

declare num int;

set num =1;

while num <= 100000 do

insert into XXX_table values(

replace(uuid(),'-',''),concat('測試',num),concat('cs',num),'123456'

);

set num =num +1;

end while;

end ;

然后調(diào)用該存儲過程:

call addMyData();

本篇準備了3張表,分別為學生(student)表,班級(class)表,賬戶(account)表,各自有50萬,1萬和10萬條數(shù)據(jù)用于測試。

實用性極強的MySQL查詢優(yōu)化策略

實用性極強的MySQL查詢優(yōu)化策略

二、分頁查詢優(yōu)化

分頁查詢是開發(fā)中經(jīng)常會遇到的,有一種情況是,當分頁的數(shù)量非常大的時候,查詢的時候往往非常耗時,比如查詢student表,使用下面的sql查詢,耗時達到0.2秒。

實用性極強的MySQL查詢優(yōu)化策略

實踐經(jīng)驗告訴我們,越往后,分頁查詢效率越低,這就是分頁查詢的問題所在, 因為,當在進行分頁查詢時,如果執(zhí)行 limit 400000,10 ,此時需要 MySQL 排序前4000 10 記錄,僅僅返回400000 - 4 00010 的記錄,其他記錄丟棄,查詢排序的代價非常大。

優(yōu)化思路:

一般分頁查詢時,通過創(chuàng)建 覆蓋索引 能夠比較好地提高性能,可以通過覆蓋索引加子查詢形式進行優(yōu)化。

1.在索引上完成排序分頁操作,最后根據(jù)主鍵關(guān)聯(lián)回原表查詢所需要的其他列內(nèi)容

SELECT * FROM student t1,(SELECT id FROM student ORDER BY id LIMIT 400000,10) t2 WHERE t1.id =t2.id;

執(zhí)行上面的sql,可以看到響應(yīng)時間有一定的提升。

實用性極強的MySQL查詢優(yōu)化策略

2.對于主鍵自增的表,可以把Limit 查詢轉(zhuǎn)換成某個位置的查詢

select * from student where id > 400000 limit 10;

執(zhí)行上面的sql,可以看到響應(yīng)時間有一定的提升。

三、關(guān)聯(lián)查詢優(yōu)化

在實際的業(yè)務(wù)開發(fā)過程中,關(guān)聯(lián)查詢可以說隨處可見,關(guān)聯(lián)查詢的優(yōu)化核心思路是,最好為關(guān)聯(lián)查詢的字段添加索引,這是關(guān)鍵。具體到不同的場景,還需要具體分析,這個跟mysql的引擎在執(zhí)行優(yōu)化策略的方案選擇時有一定關(guān)系。

1.左連接或右連接

下面是一個使用left join 的查詢,可以預想到這條sql查詢的結(jié)果集非常大。

select t.* from student t left join class cs on t.classId = cs.id;

為了檢查下sql的執(zhí)行效率,使用explAIn做一下分析,可以看到,第一張表即left join左邊的表student走了全表掃描,而class表走了主鍵索引,盡管結(jié)果集較大,還是走了索引。

實用性極強的MySQL查詢優(yōu)化策略

針對這種場景的查詢,思路如下:

  • 讓查詢的字段盡量包含在主鍵索引或者覆蓋索引中;
  • 查詢的時候盡量使用分頁查詢。

實用性極強的MySQL查詢優(yōu)化策略

關(guān)于左連接(右連接)的explain結(jié)果補充說明:

  • 左連接左邊的表一般為驅(qū)動表,右邊的表為被驅(qū)動表;
  • 盡可能讓數(shù)據(jù)集小的表作為驅(qū)動表,減少mysql內(nèi)部循環(huán)的次數(shù);
  • 兩表關(guān)聯(lián)時,explain結(jié)果展示中,第一欄一般為驅(qū)動表。

2.關(guān)聯(lián)查詢關(guān)聯(lián)的字段建立索引

看下面的這條sql,其關(guān)聯(lián)字段非表的主鍵,而是普通的字段。

explain select u.* from tenant t left join `user` u on u.account = t.tenant_name where t.removed is null and u.removed is null;

實用性極強的MySQL查詢優(yōu)化策略

通過explain分析可以發(fā)現(xiàn),左邊的表走了全表掃描,可以考慮給左邊的表的tenant_name和user表的account 各自創(chuàng)建索引。

create index idx_name on tenant(tenant_name);

create index idx_account on `user`(account);

再次使用explain分析結(jié)果如下:

實用性極強的MySQL查詢優(yōu)化策略

可以看到第二行type變?yōu)閞ef,rows的數(shù)量優(yōu)化比較明顯。這是由左連接特性決定的,LEFT JOIN條件用于確定如何從右表搜索行,左邊一定都有,所以右邊是我們的關(guān)鍵點,一定需要建立索引。

3.內(nèi)連接關(guān)聯(lián)的字段建立索引

我們知道,左連接和右連接查詢的數(shù)據(jù)分別是完全包含左表數(shù)據(jù),完全包含右表數(shù)據(jù),而內(nèi)連接(inner join 或join) 則是取交集(共有的部分),在這種情況下,驅(qū)動表的選擇是由mysql優(yōu)化器自動選擇的。

在上面的基礎(chǔ)上,首先移除兩張表的索引:

ALTER TABLE `user` DROP INDEX idx_account;

ALTER TABLE `tenant` DROP INDEX idx_name;

使用explain語句進行分析:

實用性極強的MySQL查詢優(yōu)化策略

然后給user表的account字段添加索引,再次執(zhí)行explain我們發(fā)現(xiàn),user表竟然被當作是被驅(qū)動表了。

實用性極強的MySQL查詢優(yōu)化策略

此時,如果我們給tenant表的tenant_name加索引,并移除user表的account索引,得出的結(jié)果竟然都沒有走索引,再次說明,使用內(nèi)連接的情況下,查詢優(yōu)化器將會根據(jù)自己的判斷進行選擇。

實用性極強的MySQL查詢優(yōu)化策略

四、子查詢優(yōu)化

子查詢在日常編寫業(yè)務(wù)的SQL時也是使用非常頻繁的做法,不是說子查詢不能用,而是當數(shù)據(jù)量超出一定的范圍之后,子查詢的性能下降是很明顯的,關(guān)于這一點,本人在日常工作中深有體會。

比如下面這條sql,由于student表數(shù)據(jù)量較大,執(zhí)行起來耗時非常長,可以看到耗費了將近3秒。

select st.* from student st where st.classId in (

select id from class where id > 100

);

通過執(zhí)行explain進行分析得知,內(nèi)層查詢 id > 100的子查詢盡管用上了主鍵索引,但是由于結(jié)果集太大,帶入到外層查詢,即作為in的條件時,查詢優(yōu)化器還是走了全表掃描。

實用性極強的MySQL查詢優(yōu)化策略

針對上面的情況,可以考慮下面的優(yōu)化方式:

select st.id from student st join class cl on st.classId = cl.id where cl.id > 100;

子查詢性能低效的原因

  • 子查詢時,MySQL需要為內(nèi)層查詢語句的查詢結(jié)果建立一個臨時表 ,然后外層查詢語句從臨時表中查詢記錄,查詢完畢后,再撤銷這些臨時表 。這樣會消耗過多的CPU和IO資源,產(chǎn)生大量的慢查詢;
  • 子查詢結(jié)果集存儲的臨時表,不論是內(nèi)存臨時表還是磁盤臨時表都不能走索引,所以查詢性能會受到一定的影響;
  • 對于返回結(jié)果集比較大的子查詢,其對查詢性能的影響也就越大。

使用mysql查詢時,可以使用連接(JOIN)查詢來替代子查詢。連接查詢不需要建立臨時表 ,其速度比子查詢要快 ,如果查詢中使用索引的話,性能就會更好,盡量不要使用NOT IN 或者 NOT EXISTS,用LEFT JOIN xxx ON xx WHERE xx IS NULL替代。

一個真實的案例

在下面的這段sql中,優(yōu)化前使用的是子查詢,在一次生產(chǎn)問題的性能分析中,發(fā)現(xiàn)某個tenant_id下的數(shù)據(jù)達到了35萬多,這樣直接導致某個列表頁面的接口查詢耗時達到了5秒左右。

實用性極強的MySQL查詢優(yōu)化策略

找到了問題的根源后,嘗試使用上面的優(yōu)化思路進行解決即可,優(yōu)化后的sql大概如下:

實用性極強的MySQL查詢優(yōu)化策略

五、排序(order by)優(yōu)化

在MySQL,排序主要有兩種方式:

  • Using filesort : 通過表索引或全表掃描,讀取滿足條件的數(shù)據(jù)行,然后在排序緩沖區(qū)sort buffer中完成排序操作,所有不是通過索引直接返回排序結(jié)果的排序都叫 FileSort 排序;
  • Using index : 通過有序的索引順序掃描直接返回有序數(shù)據(jù),這種情況即為 using index,不需要額外排序,操作效率高。

對于以上兩種排序方式,Using index的性能高,而Using filesort的性能低,我們在優(yōu)化排序操作時,盡量要優(yōu)化為 Using index。

1.使用age字段進行排序

由于age字段未加索引,查詢結(jié)果按照age排序的時候發(fā)現(xiàn)使用了filesort,排序性能較低。

實用性極強的MySQL查詢優(yōu)化策略

給age字段添加索引,再次使用order by時就走了索引。

實用性極強的MySQL查詢優(yōu)化策略

2.使用多字段進行排序

通常在實際業(yè)務(wù)中,參與排序的字段往往不只一個,這時候,就可以對參與排序的多個字段創(chuàng)建聯(lián)合索引。

如下根據(jù)stuno和age排序:

實用性極強的MySQL查詢優(yōu)化策略

給stuno和age添加聯(lián)合索引:

create index idx_stuno_age on `student`(stuno,age);

再次分析時結(jié)果如下,此時排序走了索引:

實用性極強的MySQL查詢優(yōu)化策略

1)關(guān)于多字段排序時的注意事項

  • 排序時,需要滿足最左前綴法則,否則也會出現(xiàn) filesort

在上面我們創(chuàng)建的聯(lián)合索引順序是stuno和age,即stuno在前面,而age在后,如果查詢的時候調(diào)換排序順序會怎樣呢?通過分析結(jié)果發(fā)現(xiàn),走了filesort。

實用性極強的MySQL查詢優(yōu)化策略

  • 排序時,排序的類型保持一致

在保持字段排序順序不變時,默認情況下,如果都按照升序或者降序時,order by可以使用index,如果一個是升序,另一個是降序會如何呢?分析發(fā)現(xiàn),這種情況下也會走filesort。

六、分組(group by)優(yōu)化

group by 的優(yōu)化策略和order by 的優(yōu)化策略非常像,主要列舉如下幾個要點:

  • group by 即使沒有過濾條件用到索引,也可以直接使用索引;
  • group by 先排序再分組,遵照索引建的最佳左前綴法則;
  • 當無法使用索引列時,增大 max_length_for_sort_data 和 sort_buffer_size 參數(shù)的設(shè)置;
  • where效率高于having,能寫在where限定的條件就不要寫在having中了;
  • 減少使用order by,能不排序就不排序,或?qū)⑴判蚍诺匠绦蛉プ觥rder by、groupby、distinct這些語句較為耗費CPU,數(shù)據(jù)庫的CPU資源是極其寶貴的;
  • 如果sql包含了order by、group by、distinct這些查詢的語句,where條件過濾出來的結(jié)果集請保持在1000行以內(nèi),否則SQL會很慢;

1.給group by的字段添加索引

如果字段未加索引,分析結(jié)果如下,這種結(jié)果性能顯然很低效。

實用性極強的MySQL查詢優(yōu)化策略

給stuno添加索引之后:

實用性極強的MySQL查詢優(yōu)化策略

給stuno和age添加聯(lián)合索引:

實用性極強的MySQL查詢優(yōu)化策略

如果不遵循最佳左前綴,group by 性能將會比較低效。

實用性極強的MySQL查詢優(yōu)化策略

遵循最佳左前綴的情況如下:

實用性極強的MySQL查詢優(yōu)化策略

七、count 優(yōu)化

count() 是一個聚合函數(shù),對于返回的結(jié)果集,一行行判斷,如果 count 函數(shù)的參數(shù)不是NULL,累計值就加 1,否則不加,最后返回累計值。

用法:count(*)、count(主鍵)、count(字段)、count(數(shù)字)

如下列舉了count的幾種寫法的詳細說明:

實用性極強的MySQL查詢優(yōu)化策略

經(jīng)驗值總結(jié):

按照效率排序來看,count(字段) < count(主鍵 id) < count(1) ≈ count(*),所以盡量使用 count(*)

作者丨逆風飛翔的小叔

來源丨blog.csdn.NET/congge_study/article/details/127712927

分享到:
標簽:MySQL
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定