<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>

          SQL 優(yōu)化這么做就對(duì)了!

          共 5419字,需瀏覽 11分鐘

           ·

          2022-07-12 23:00

          點(diǎn)擊關(guān)注公眾號(hào),Java干貨及時(shí)送達(dá)

          作者:狼爺
          來(lái)源:www.cnblogs.com/powercto/p/14410128.html

          一、前言

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

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

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

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

          需要重點(diǎn)關(guān)注type、rows、filtered、extra。最新 MySQL 面試題整理好了,大家可以在Java面試庫(kù)小程序在線刷題。

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

          • ALL 全表掃描;
          • index 索引全掃描;
          • range 索引范圍掃描,常用語(yǔ)<,<=,>=,between,in等操作;
          • ref 使用非唯一索引掃描或唯一索引前綴掃描,返回單條記錄,常出現(xiàn)在關(guān)聯(lián)查詢中;
          • eq_ref 類似ref,區(qū)別在于使用的是唯一索引,使用主鍵的關(guān)聯(lián)查詢;
          • const/system 單條記錄,系統(tǒng)會(huì)把匹配行中的其他列作為常數(shù)處理,如主鍵或唯一索引查詢;
          • null MySQL不訪問任何表或索引,直接返回結(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需要額外的一次傳遞,以找出如何按排序順序檢索行。通過根據(jù)聯(lián)接類型瀏覽所有行并為所有匹配WHERE子句的行保存排序關(guān)鍵字和行的指針來(lái)完成排序。然后關(guān)鍵字被排序,并按排序順序檢索行;
          • Using temporary:使用了臨時(shí)表保存中間結(jié)果,性能特別差,需要重點(diǎn)優(yōu)化;
          • Using index:表示相應(yīng)的 select 操作中使用了覆蓋索引(Coveing Index),避免訪問了表的數(shù)據(jù)行,效率不錯(cuò)!如果同時(shí)出現(xiàn) using where,意味著無(wú)法直接通過索引查找來(lái)查詢到符合條件的數(shù)據(jù);
          • Using index condition:MySQL5.6之后新增的ICP,using index condtion就是使用了ICP(索引下推),在存儲(chǔ)引擎層進(jìn)行數(shù)據(jù)過濾,而不是在服務(wù)層過濾,利用索引現(xiàn)有的數(shù)據(jù)減少回表的數(shù)據(jù)。

          3、show profile 分析

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

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

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

          4、trace

          trace分析優(yōu)化器如何選擇執(zhí)行計(jì)劃,通過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、確定問題并采用相應(yīng)的措施

          • 優(yōu)化索引;
          • 優(yōu)化SQL語(yǔ)句:修改SQL、IN 查詢分段、時(shí)間查詢分段、基于上一次數(shù)據(jù)過濾;
          • 改用其他實(shí)現(xiàn)方式:ES、數(shù)倉(cāng)等;
          • 數(shù)據(jù)碎片處理。
          • 點(diǎn)擊Java面試庫(kù)小程序在線刷題。

          三、場(chǎng)景分析

          1、最左匹配

          1)索引

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

          2)SQL語(yǔ)句

          select * from _t where orderno=''

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

          2、隱式轉(zhuǎn)換

          1)索引

          KEY `idx_mobile` (`mobile`)

          2)SQL語(yǔ)句

          select * from _user where mobile=12345678901

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

          點(diǎn)擊關(guān)注公眾號(hào),Java干貨及時(shí)送達(dá)

          3、大分頁(yè)

          1)索引

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

          2)SQL語(yǔ)句

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

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

          • 一種是把上一次的最后一條數(shù)據(jù),也即上面的c傳過來(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 10000, 10) t2 where t1.id = t2.id;

          4、in + order by

          1)索引

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

          2)SQL語(yǔ)句

          select * from _order where shop_id = 1 and order_status in (1, 2, 3) order by created_at desc limit 10

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

          in查詢?cè)谶M(jìn)行cost代價(jià)計(jì)算時(shí)(代價(jià) = 元組數(shù) * IO平均值),是通過將in包含的數(shù)值,一條條去查詢獲取元組數(shù)的,因此這個(gè)計(jì)算過程會(huì)比較的慢,所以MySQL設(shè)置了個(gè)臨界值(eq_range_index_dive_limit),5.6之后超過這個(gè)臨界值后該列的cost就不參與計(jì)算了。因此會(huì)導(dǎo)致執(zhí)行計(jì)劃選擇不準(zhǔn)確。默認(rèn)是200,即in條件超過了200個(gè)數(shù)據(jù),會(huì)導(dǎo)致in的代價(jià)計(jì)算存在問題,可能會(huì)導(dǎo)致Mysql選擇的索引不準(zhǔn)確。

          最新面試題整理好了,大家可以在Java面試庫(kù)小程序在線刷題。

          3)處理方式

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

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

          1)索引

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

          2)SQL語(yǔ)句

          select * from _order where shop_id = 1 and created_at > '2021-01-01 00:00:00' and order_status = 10

          范圍查詢還有“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)化器選擇不使用索引的情況

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

          select * from _order where  order_status = 1

          查詢出所有未支付的訂單,一般這種訂單是很少的,即使建了索引,也沒法使用索引。

          8、復(fù)雜查詢

          select sum(amt) from _t where a = 1 and b in (1, 2, 3) and c > '2020-01-01';select * from _t where a = 1 and b in (1, 2, 3) and c > '2020-01-01' limit 10;

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

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

          最新面試題整理好了,大家可以在Java面試庫(kù)小程序在線刷題。

          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ù)開發(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







          Spring Cloud Alibaba 終于一統(tǒng)江湖!
          Spring Boot 定時(shí)任務(wù)開啟后,怎么自動(dòng)停止?
          23 種設(shè)計(jì)模式實(shí)戰(zhàn)(很全)
          Spring Boot 保護(hù)敏感配置的 4 種方法!
          面了個(gè) 5 年 Java,兩個(gè)線程數(shù)據(jù)交換都不會(huì)
          阿里為什么推薦使用 LongAdder?
          新來(lái)一個(gè)技術(shù)總監(jiān):禁止戴耳機(jī)寫代碼。。
          別用 System... 計(jì)時(shí)了,StopWatch 好用到爆!
          Java 8 排序的 10 個(gè)姿勢(shì),太秀了吧!
          Spring Boot Admin 橫空出世!
          Spring Boot 學(xué)習(xí)筆記,這個(gè)太全了!



          關(guān)注Java技術(shù)棧看更多干貨



          Spring Cloud Alibaba 最新實(shí)戰(zhàn)!
          瀏覽 48
          點(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>
                  亚洲无码免费看 | 大香蕉色性在线视频 | 最新国产免费地址 | 人妻爽爽人妻夜夜 | 亚洲欧美性色图 |