<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          場(chǎng)景+案例分析,SQL優(yōu)化這么做就對(duì)了!

          共 5583字,需瀏覽 12分鐘

           ·

          2021-04-14 11:13

          不點(diǎn)藍(lán)字,我們哪來(lái)故事?

          每天 11 點(diǎn)更新文章,餓了點(diǎn)外賣(mài),點(diǎn)擊 ??《無(wú)門(mén)檻外賣(mài)優(yōu)惠券,每天免費(fèi)領(lǐng)!》

          作者:狼爺

          cnblogs.com/powercto/p/14410128.html

          目錄

          • 前言
          • SQL優(yōu)化一般步驟
            • 1、通過(guò)慢查日志等定位那些執(zhí)行效率較低的SQL語(yǔ)句
            • 2、explain 分析SQL的執(zhí)行計(jì)劃
            • 3、show profile 分析
            • 4、trace
            • 5、確定問(wèn)題并采用相應(yīng)的措施
          • 場(chǎng)景分析
            • 案例1、最左匹配
            • 案例2、隱式轉(zhuǎn)換
            • 案例3、大分頁(yè)
            • 案例4、in + order by
            • 案例5、范圍查詢(xún)阻斷,后續(xù)字段不能走索引
            • 案例6、不等于、不包含不能用到索引的快速搜索。(可以用到ICP)
            • 案例7、優(yōu)化器選擇不使用索引的情況
            • 案例8、復(fù)雜查詢(xún)
            • 案例9、asc和desc混用
            • 案例10、大數(shù)據(jù)
          • 資料

          前言

          在應(yīng)用開(kāi)發(fā)的早期,數(shù)據(jù)量少,開(kāi)發(fā)人員開(kāi)發(fā)功能時(shí)更重視功能上的實(shí)現(xiàn),隨著生產(chǎn)數(shù)據(jù)的增長(zhǎng),很多SQL語(yǔ)句開(kāi)始暴露出性能問(wèn)題,對(duì)生產(chǎn)的影響也越來(lái)越大,有時(shí)可能這些有問(wèn)題的SQL就是整個(gè)系統(tǒng)性能的瓶頸。

          如果有不同意見(jiàn),歡迎留言指正,一起學(xué)習(xí)!

          SQL優(yōu)化一般步驟

          1、通過(guò)慢查日志等定位那些執(zhí)行效率較低的SQL語(yǔ)句

          2、explain 分析SQL的執(zhí)行計(jì)劃

          需要重點(diǎn)關(guān)注type、rows、filtered、extra。

          type由上至下,效率越來(lái)越高

          • ALL 全表掃描
          • index 索引全掃描
          • range 索引范圍掃描,常用語(yǔ)<,<=,>=,between,in等操作
          • ref 使用非唯一索引掃描或唯一索引前綴掃描,返回單條記錄,常出現(xiàn)在關(guān)聯(lián)查詢(xún)中
          • eq_ref 類(lèi)似ref,區(qū)別在于使用的是唯一索引,使用主鍵的關(guān)聯(lián)查詢(xún)
          • const/system 單條記錄,系統(tǒng)會(huì)把匹配行中的其他列作為常數(shù)處理,如主鍵或唯一索引查詢(xún)
          • null MySQL不訪(fǎng)問(wèn)任何表或索引,直接返回結(jié)果

          雖然上至下,效率越來(lái)越高,但是根據(jù)cost模型,假設(shè)有兩個(gè)索引idx1(a, b, c),idx2(a, c),SQL為select * from t where a = 1 and b in (1, 2) order by c;如果走idx1,那么是type為range,如果走idx2,那么type是ref;當(dāng)需要掃描的行數(shù),使用idx2大約是idx1的5倍以上時(shí),會(huì)用idx1,否則會(huì)用idx2

          Extra

          • Using filesort:MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。通過(guò)根據(jù)聯(lián)接類(lèi)型瀏覽所有行并為所有匹配WHERE子句的行保存排序關(guān)鍵字和行的指針來(lái)完成排序。然后關(guān)鍵字被排序,并按排序順序檢索行。
          • Using temporary:使用了臨時(shí)表保存中間結(jié)果,性能特別差,需要重點(diǎn)優(yōu)化
          • Using index:表示相應(yīng)的 select 操作中使用了覆蓋索引(Coveing Index),避免訪(fǎng)問(wèn)了表的數(shù)據(jù)行,效率不錯(cuò)!如果同時(shí)出現(xiàn) using where,意味著無(wú)法直接通過(guò)索引查找來(lái)查詢(xún)到符合條件的數(shù)據(jù)。
          • Using index condition:MySQL5.6之后新增的ICP,using index condtion就是使用了ICP(索引下推),在存儲(chǔ)引擎層進(jìn)行數(shù)據(jù)過(guò)濾,而不是在服務(wù)層過(guò)濾,利用索引現(xiàn)有的數(shù)據(jù)減少回表的數(shù)據(jù)。

          3、show profile 分析

          了解SQL執(zhí)行的線(xiàn)程的狀態(tài)及消耗的時(shí)間。

          默認(rèn)是關(guān)閉的,開(kāi)啟語(yǔ)句“set profiling = 1;”

          SHOW PROFILES ;
          SHOW PROFILE FOR QUERY  #{id};

          4、trace

          trace分析優(yōu)化器如何選擇執(zhí)行計(jì)劃,通過(guò)trace文件能夠進(jìn)一步了解為什么優(yōu)惠券選擇A執(zhí)行計(jì)劃而不選擇B執(zhí)行計(jì)劃。

          set optimizer_trace="enabled=on";
          set optimizer_trace_max_mem_size=1000000;
          select * from information_schema.optimizer_trace;

          5、確定問(wèn)題并采用相應(yīng)的措施

          • 優(yōu)化索引

          • 優(yōu)化SQL語(yǔ)句:修改SQL、IN 查詢(xún)分段、時(shí)間查詢(xún)分段、基于上一次數(shù)據(jù)過(guò)濾

          • 改用其他實(shí)現(xiàn)方式:ES、數(shù)倉(cāng)等

          • 數(shù)據(jù)碎片處理

          場(chǎng)景分析

          案例1、最左匹配

          索引

          KEY `idx_shopid_orderno` (`shop_id`,`order_no`)

          SQL語(yǔ)句

          select * from _t where orderno=''

          查詢(xún)匹配從左往右匹配,要使用order_no走索引,必須查詢(xún)條件攜帶shop_id或者索引(shop_id,order_no)調(diào)換前后順序。

          推薦:Java面試練題寶典

          案例2、隱式轉(zhuǎn)換

          索引

          KEY `idx_mobile` (`mobile`)

          SQL語(yǔ)句

          select * from _user where mobile=12345678901

          隱式轉(zhuǎn)換相當(dāng)于在索引上做運(yùn)算,會(huì)讓索引失效。mobile是字符類(lèi)型,使用了數(shù)字,應(yīng)該使用字符串匹配,否則MySQL會(huì)用到隱式替換,導(dǎo)致索引失效。

          案例3、大分頁(yè)

          索引

          KEY `idx_a_b_c` (`a`, `b`, `c`)

          SQL語(yǔ)句

          select * from _t where a = 1 and b = 2 order by c desc limit 1000010;

          對(duì)于大分頁(yè)的場(chǎng)景,可以?xún)?yōu)先讓產(chǎn)品優(yōu)化需求,如果沒(méi)有優(yōu)化的,有如下兩種優(yōu)化方式:

          一種是把上一次的最后一條數(shù)據(jù),也即上面的c傳過(guò)來(lái),然后做“c < xxx”處理,但是這種一般需要改接口協(xié)議,并不一定可行。

          另一種是采用延遲關(guān)聯(lián)的方式進(jìn)行處理,減少SQL回表,但是要記得索引需要完全覆蓋才有效果,SQL改動(dòng)如下

          SELECT
           t1.* 
          FROM
           _t t1,
           ( SELECT id FROM _t WHERE a = 1 AND b = 2 ORDER BY c DESC LIMIT 1000010 ) t2 
          WHERE
           t1.id = t2.id;

          案例4、in + order by

          索引

          KEY `idx_shopid_status_created` (`shop_id`, `order_status`, `created_at`)

          SQL語(yǔ)句

          SELECT
           * 
          FROM
           _order 
          WHERE
           shop_id = 1 
           AND order_status IN ( 123 ) 
          ORDER BY
           created_at DESC 
           LIMIT 10

          in查詢(xún)?cè)贛ySQL底層是通過(guò)n*m的方式去搜索,類(lèi)似union,但是效率比union高。

          in查詢(xún)?cè)谶M(jìn)行cost代價(jià)計(jì)算時(shí)(代價(jià) = 元組數(shù) * IO平均值),是通過(guò)將in包含的數(shù)值,一條條去查詢(xún)獲取元組數(shù)的,因此這個(gè)計(jì)算過(guò)程會(huì)比較的慢,所以MySQL設(shè)置了個(gè)臨界值(eq_range_index_dive_limit),5.6之后超過(guò)這個(gè)臨界值后該列的cost就不參與計(jì)算了。

          因此會(huì)導(dǎo)致執(zhí)行計(jì)劃選擇不準(zhǔn)確。默認(rèn)是200,即in條件超過(guò)了200個(gè)數(shù)據(jù),會(huì)導(dǎo)致in的代價(jià)計(jì)算存在問(wèn)題,可能會(huì)導(dǎo)致Mysql選擇的索引不準(zhǔn)確。

          處理方式,可以(order_statuscreated_at)互換前后順序,并且調(diào)整SQL為延遲關(guān)聯(lián)。

          推薦:Java面試練題寶典

          案例5、范圍查詢(xún)阻斷,后續(xù)字段不能走索引

          索引

          KEY `idx_shopid_created_status` (`shop_id`, `created_at`, `order_status`)

          SQL語(yǔ)句

          SELECT
           * 
          FROM
           _order 
          WHERE
           shop_id = 1 
           AND created_at > '2021-01-01 00:00:00' 
           AND order_status = 10

          范圍查詢(xún)還有“IN、between”

          案例6、不等于、不包含不能用到索引的快速搜索。(可以用到ICP)

          select * from _order where shop_id=1 and order_status not in (1,2)

          select * from _order where shop_id=1 and order_status != 1

          在索引上,避免使用NOT、!=、<>、!<、!>、NOT EXISTS、NOT IN、NOT LIKE等

          案例7、優(yōu)化器選擇不使用索引的情況

          如果要求訪(fǎng)問(wèn)的數(shù)據(jù)量很小,則優(yōu)化器還是會(huì)選擇輔助索引,但是當(dāng)訪(fǎng)問(wèn)的數(shù)據(jù)占整個(gè)表中數(shù)據(jù)的蠻大一部分時(shí)(一般是20%左右),優(yōu)化器會(huì)選擇通過(guò)聚集索引來(lái)查找數(shù)據(jù)。

          select * from _order where  order_status = 1

          查詢(xún)出所有未支付的訂單,一般這種訂單是很少的,即使建了索引,也沒(méi)法使用索引。

          案例8、復(fù)雜查詢(xún)

          select sum(amt) from _t where a = 1 and b in (123and c > '2020-01-01';

          select * from _t where a = 1 and b in (123and c > '2020-01-01' limit 10;

          如果是統(tǒng)計(jì)某些數(shù)據(jù),可能改用數(shù)倉(cāng)進(jìn)行解決;

          如果是業(yè)務(wù)上就有那么復(fù)雜的查詢(xún),可能就不建議繼續(xù)走SQL了,而是采用其他的方式進(jìn)行解決,比如使用ES等進(jìn)行解決。

          案例9、asc和desc混用

          select * from _t where a=1 order by b desc, c asc

          desc 和asc混用時(shí)會(huì)導(dǎo)致索引失效

          案例10、大數(shù)據(jù)

          對(duì)于推送業(yè)務(wù)的數(shù)據(jù)存儲(chǔ),可能數(shù)據(jù)量會(huì)很大,如果在方案的選擇上,最終選擇存儲(chǔ)在MySQL上,并且做7天等有效期的保存。

          那么需要注意,頻繁的清理數(shù)據(jù),會(huì)照成數(shù)據(jù)碎片,需要聯(lián)系DBA進(jìn)行數(shù)據(jù)碎片處理。

          資料

          • 深入淺出MySQL:數(shù)據(jù)庫(kù)開(kāi)發(fā)、優(yōu)化與管理維護(hù)(唐漢明 / 翟振興 / 關(guān)寶軍 / 王洪權(quán))

          • MySQL技術(shù)內(nèi)幕——InnoDB存儲(chǔ)引擎(姜承堯)

          • https://dev.mysql.com/doc/refman/5.7/en/explain-output.html

          • https://dev.mysql.com/doc/refman/5.7/en/cost-model.html

          • https://www.yuque.com/docs/share/3463148b-05e9-40ce-a551-ce93a53a2c66

          END


          往期推薦

          服務(wù)端如何防止訂單重復(fù)支付!

          快來(lái)?yè)尲t包!

          笑死,小米新logo是這么來(lái)的

          老大說(shuō),我們SpringBoot部署Jar文件太“肥”了,能“減肥”一下嗎?

          下方二維碼關(guān)注我

          技術(shù)草根堅(jiān)持分享 編程,算法,架構(gòu)

          看完文章,餓了點(diǎn)外賣(mài),點(diǎn)擊 ??《無(wú)門(mén)檻外賣(mài)優(yōu)惠券,每天免費(fèi)領(lǐng)!》

          朋友,助攻一把!點(diǎn)個(gè)在看
          瀏覽 38
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲黄色小电影 | 精品久久久久久久中文字幕 | 8809鲁大师日韩版免费使用 | 18禁啪啪网站 | 97国产超碰在线观看 |