99999久久久久久亚洲,欧美人与禽猛交狂配,高清日韩av在线影院,一个人在线高清免费观看,啦啦啦在线视频免费观看www

熱線電話:13121318867

登錄
首頁大數(shù)據(jù)時代【CDA干貨】MySQL執(zhí)行計劃中rows的計算邏輯:從原理到實踐
【CDA干貨】MySQL執(zhí)行計劃中rows的計算邏輯:從原理到實踐
2025-07-21
收藏

MySQL執(zhí)行計劃中rows的計算邏輯:從原理到實踐

MySQL 執(zhí)行計劃中 rows 的計算邏輯:從原理到實踐

在 MySQL 數(shù)據(jù)庫的查詢優(yōu)化中,執(zhí)行計劃(EXPLAIN輸出)是開發(fā)者和 DBA 分析查詢性能的核心工具。其中,rows列作為執(zhí)行計劃的關(guān)鍵指標(biāo),代表優(yōu)化器估計的當(dāng)前操作需要掃描的行數(shù)。這個數(shù)值直接反映了查詢的效率 —— 行數(shù)越少,查詢通常越高效。但很多人對這個數(shù)值的計算邏輯感到困惑:它究竟是怎么來的?為何有時會與實際掃描行數(shù)相差較大?本文將從原理到實踐,全面解析 MySQL 執(zhí)行計劃中rows的計算邏輯。

一、rows 的核心作用:優(yōu)化器的 “決策依據(jù)”

在深入計算邏輯前,需先明確rows的本質(zhì):它是 MySQL 優(yōu)化器基于統(tǒng)計信息數(shù)據(jù)分布規(guī)律,對查詢執(zhí)行過程中需要訪問的行數(shù)的 “預(yù)測值”,而非實際執(zhí)行時的真實掃描行數(shù)。

優(yōu)化器的核心任務(wù)是選擇最優(yōu)執(zhí)行計劃(如全表掃描還是索引掃描、多表連接的順序等),而rows值是優(yōu)化器判斷成本的重要依據(jù)。例如,對于一個簡單的過濾查詢,優(yōu)化器會比較 “全表掃描估計的 rows” 和 “索引掃描估計的 rows”,選擇成本更低的方案。因此,rows的準(zhǔn)確性直接影響優(yōu)化器決策的合理性。

二、rows 計算的核心依據(jù):統(tǒng)計信息

MySQL 優(yōu)化器之所以能 “估計” 行數(shù),依賴于數(shù)據(jù)庫收集的統(tǒng)計信息(statistics)。這些信息存儲在系統(tǒng)表中(如mysql.innodb_index_stats、mysql.innodb_table_stats),記錄了表、索引、列的數(shù)據(jù)分布特征。統(tǒng)計信息是rows計算的 “原始數(shù)據(jù)”,主要包括以下關(guān)鍵指標(biāo):

1. 表級統(tǒng)計信息

  • 總行數(shù)(table_rows):表中記錄的估計總數(shù)量。對于 InnoDB 表,這個值并非實時精確值,而是通過采樣計算的近似值(具體采樣邏輯后文詳述)。

  • 數(shù)據(jù)長度(data_length):表數(shù)據(jù)占用的存儲空間,用于輔助判斷表的 “大小”。

2. 索引級統(tǒng)計信息

  • 基數(shù)(Cardinality)索引列中不重復(fù)值的估計數(shù)量。例如,一個性別列(值為 “男”“女”)的基數(shù)約為 2,而一個用戶 ID 列的基數(shù)接近表的總行數(shù)。基數(shù)直接影響索引的 “選擇性”(Selectivity,即不重復(fù)值占總行數(shù)的比例),選擇性越高(基數(shù)越大),索引過濾效果越好。

  • 索引深度(index_depth)索引 B + 樹的高度,影響索引掃描的 IO 成本。

3. 列級統(tǒng)計信息

  • 值分布(value distribution):部分列的直方圖(Histogram)統(tǒng)計,記錄列值的分布范圍和頻率。例如,一個訂單金額列的直方圖可能顯示 “0-100 元占 60%,100-500 元占 30%” 等分布特征,幫助優(yōu)化器更精準(zhǔn)地估計過濾條件后的行數(shù)。

三、不同操作場景下 rows 的具體計算邏輯

rows的計算方式并非一成不變,而是根據(jù)查詢操作的類型(如全表掃描、索引掃描、連接查詢)動態(tài)調(diào)整。以下是常見場景的計算邏輯:

1. 全表掃描(type: ALL)

當(dāng)查詢無法使用索引(如無合適索引、條件過于寬泛)時,優(yōu)化器會選擇全表掃描,此時rows的估計值主要基于表級統(tǒng)計信息中的總行數(shù)(table_rows)

例如,對于一張user表,table_rows統(tǒng)計值為 10000,執(zhí)行EXPLAIN SELECT * FROM user時,rows列通常會接近 10000。但需注意:table_rows是 InnoDB 通過采樣計算的近似值(默認(rèn)采樣 8 個數(shù)據(jù)頁),若表數(shù)據(jù)分布不均或采樣偏差rows可能與實際總行數(shù)存在差異。

2. 索引掃描(type: ref、range、index 等)

當(dāng)查詢使用索引時,rows的計算依賴于索引的基數(shù)、選擇性及查詢條件,核心公式可簡化為:

估計掃描行數(shù) = 索引過濾后的基數(shù) × 數(shù)據(jù)分布系數(shù)  

具體場景如下:

  • 等值查詢(ref 類型):如WHERE age = 30,優(yōu)化器會先通過索引統(tǒng)計獲取age列的基數(shù),計算 “值 = 30” 的選擇性(即該值在列中的占比),再用表總行數(shù)乘以選擇性,得到估計行數(shù)。 例:

    例:user表總行數(shù) 10000,age列基數(shù)為 50(假設(shè)年齡分布在 18-67 歲,共 50 個可能值),則 “age=30” 的選擇性約為 1/50,估計行數(shù)為 10000 × (1/50) = 200。

  • 范圍查詢(range 類型):如WHERE price BETWEEN 100 AND 500,優(yōu)化器會結(jié)合索引直方圖統(tǒng)計(若啟用)或索引值的分布范圍,估算范圍內(nèi)的值占總基數(shù)的比例,再乘以總行數(shù)。 例:

    例:product表總行數(shù) 50000,price索引基數(shù)為 10000,若統(tǒng)計顯示 “100-500 元” 的價格占比約 20%,則估計行數(shù)為 50000 × 20% = 10000。

  • 索引全掃描(index 類型):當(dāng)查詢需要掃描整個索引(如SELECT COUNT(*) FROM user USE INDEX(age_idx)),rows值接近索引的總記錄數(shù),該值基于索引的統(tǒng)計信息(如innodb_index_stats中的sum_of_rows)。

3. 連接查詢(JOIN)

多表連接時,rows的計算更為復(fù)雜,優(yōu)化器需估計每一步連接的 “驅(qū)動表” 和 “被驅(qū)動表” 的掃描行數(shù),核心邏輯基于嵌套循環(huán)連接的成本模型:

總估計行數(shù) = 驅(qū)動表估計行數(shù) × 被驅(qū)動表單條驅(qū)動記錄的匹配行數(shù)  

例如,SELECT * FROM order o JOIN user u ON o.user_id = ``u.id,優(yōu)化器會先確定驅(qū)動表(如order表,估計行數(shù) 1000),再根據(jù)user表中id索引的基數(shù),計算每條order記錄匹配的user記錄數(shù)(假設(shè)id是主鍵,基數(shù) = 總行數(shù),匹配行數(shù) = 1),則總rows估計為 1000 × 1 = 1000。

四、影響 rows 估計準(zhǔn)確性的關(guān)鍵因素

實際使用中,rows估計值與真實值的偏差往往源于以下因素,需重點關(guān)注:

1. 統(tǒng)計信息過時或缺失

MySQL 的統(tǒng)計信息默認(rèn)通過采樣更新(InnoDB 默認(rèn)每 10% 數(shù)據(jù)變更觸發(fā)自動更新,或通過ANALYZE TABLE手動更新)。若表數(shù)據(jù)頻繁插入、刪除或更新,統(tǒng)計信息未及時更新,會導(dǎo)致table_rows、基數(shù)等指標(biāo)失真,進而影響rows估計。

例如,一張表剛插入 10 萬條新數(shù)據(jù)但未更新統(tǒng)計信息,優(yōu)化器仍使用舊的table_rows(如 5 萬),此時rows估計會遠小于實際值。

2. 數(shù)據(jù)分布極端不均

當(dāng)列數(shù)據(jù)存在 “長尾分布”(如某值占比 90%,其他值共占 10%),采樣統(tǒng)計可能無法準(zhǔn)確捕捉分布特征。例如,status列中 90% 的值為 “normal”,10% 為 “error”,優(yōu)化器基于采樣可能誤判 “status='normal'” 的選擇性為 50%,導(dǎo)致rows估計偏差。

3. 索引失效或使用不當(dāng)

索引存在重復(fù)值過多(選擇性低)、索引碎片嚴(yán)重等問題,優(yōu)化器可能低估或高估索引掃描的行數(shù)。例如,對一個選擇性極低的索引(如性別列)執(zhí)行查詢,優(yōu)化器可能認(rèn)為 “索引掃描 rows” 與 “全表掃描 rows” 接近,進而選擇全表掃描,導(dǎo)致執(zhí)行計劃不符合預(yù)期。

4. 復(fù)雜查詢的估計誤差累積

對于包含子查詢、聚合函數(shù)(GROUP BY)、排序(ORDER BY)的復(fù)雜查詢,優(yōu)化器需對多個步驟的rows進行估計,誤差會逐步累積,導(dǎo)致最終rows值與實際偏差較大。

五、優(yōu)化 rows 估計準(zhǔn)確性的實踐方法

要讓rows值更接近實際掃描行數(shù),需從統(tǒng)計信息維護、數(shù)據(jù)設(shè)計和查詢優(yōu)化三方面入手:

1. 及時更新統(tǒng)計信息

  • 對頻繁變更的表定期執(zhí)行ANALYZE TABLE table_name,強制更新統(tǒng)計信息(InnoDB 會重新采樣計算table_rows、基數(shù)等)。

  • 調(diào)整統(tǒng)計信息采樣參數(shù):通過innodb_stats_persistent_sample_pages(持久化統(tǒng)計采樣頁數(shù)量,默認(rèn) 20)或innodb_stats_transient_sample_pages(臨時統(tǒng)計采樣頁數(shù)量,默認(rèn) 8)提高采樣精度(需權(quán)衡性能開銷)。

2. 優(yōu)化數(shù)據(jù)分布與索引設(shè)計

  • 避免在低選擇性列上創(chuàng)建索引(如性別、狀態(tài)等),此類索引rows估計和查詢效率提升有限。

  • 對高選擇性列(如用戶 ID、訂單號)建立索引,并通過SHOW INDEX FROM table_name定期檢查索引基數(shù)是否合理。

3. 結(jié)合實際執(zhí)行計劃調(diào)優(yōu)查詢

  • rows估計值與實際掃描行數(shù)偏差較大(可通過SHOW PROFILE或慢查詢?nèi)罩静榭磳嶋H行數(shù)),嘗試改寫查詢(如調(diào)整過濾條件順序、避免子查詢嵌套過深)。

  • 對復(fù)雜連接查詢,通過STRAIGHT_JOIN指定連接順序,避免優(yōu)化器因rows估計錯誤選擇低效連接方式。

六、案例:從 rows 異???a href='/map/chaxunyouhua/' style='color:#000;font-size:inherit;'>查詢優(yōu)化

某電商平臺的訂單查詢 SQL 執(zhí)行緩慢,EXPLAIN輸出顯示rows估計為 1000,但實際掃描行數(shù)達 10 萬。排查發(fā)現(xiàn):

  1. 訂單表order近期新增 50 萬條數(shù)據(jù),但未執(zhí)行ANALYZE TABLE,table_rows仍為舊值 10 萬,導(dǎo)致優(yōu)化器低估總行數(shù);

  2. 過濾條件WHERE create_time > '2023-01-01'使用的create_time索引存在大量碎片,基數(shù)統(tǒng)計失真,優(yōu)化器誤判范圍查詢的選擇性為 1%(實際為 20%)。

解決方法:

  • 執(zhí)行ANALYZE TABLE order更新統(tǒng)計信息,table_rows修正為 60 萬;

  • 重建create_time索引ALTER TABLE order REBUILD INDEX create_time_idx),修復(fù)碎片并更新基數(shù);

  • 優(yōu)化后,rows估計值為 12000(60 萬 × 20%),與實際掃描行數(shù)(11 萬)接近,優(yōu)化器選擇了更合理的索引掃描計劃,查詢性能提升 80%。

結(jié)語

MySQL 執(zhí)行計劃中的rows值是優(yōu)化器基于統(tǒng)計信息和數(shù)據(jù)分布的 “智能預(yù)測”,其計算邏輯貫穿查詢執(zhí)行的全流程。理解rows的來源、影響因素及優(yōu)化方法,不僅能幫助開發(fā)者快速定位查詢性能瓶頸,更能深入掌握 MySQL 優(yōu)化器的工作原理。在實際工作中,需結(jié)合EXPLAIN輸出、統(tǒng)計信息維護和數(shù)據(jù)特征分析,讓rows成為查詢優(yōu)化的 “指路明燈”,而非誤導(dǎo)決策的 “迷霧”。

學(xué)習(xí)入口:https://edu.cda.cn/goods/show/3814?targetId=6587&preview=0

推薦學(xué)習(xí)書籍 《CDA一級教材》適合CDA一級考生備考,也適合業(yè)務(wù)及數(shù)據(jù)分析崗位的從業(yè)者提升自我。完整電子版已上線CDA網(wǎng)校,累計已有10萬+在讀~ 免費加入閱讀:https://edu.cda.cn/goods/show/3151?targetId=5147&preview=0

數(shù)據(jù)分析師資訊
更多

OK
客服在線
立即咨詢
客服在線
立即咨詢
') } function initGt() { var handler = function (captchaObj) { captchaObj.appendTo('#captcha'); captchaObj.onReady(function () { $("#wait").hide(); }).onSuccess(function(){ $('.getcheckcode').removeClass('dis'); $('.getcheckcode').trigger('click'); }); window.captchaObj = captchaObj; }; $('#captcha').show(); $.ajax({ url: "/login/gtstart?t=" + (new Date()).getTime(), // 加隨機數(shù)防止緩存 type: "get", dataType: "json", success: function (data) { $('#text').hide(); $('#wait').show(); // 調(diào)用 initGeetest 進行初始化 // 參數(shù)1:配置參數(shù) // 參數(shù)2:回調(diào),回調(diào)的第一個參數(shù)驗證碼對象,之后可以使用它調(diào)用相應(yīng)的接口 initGeetest({ // 以下 4 個配置參數(shù)為必須,不能缺少 gt: data.gt, challenge: data.challenge, offline: !data.success, // 表示用戶后臺檢測極驗服務(wù)器是否宕機 new_captcha: data.new_captcha, // 用于宕機時表示是新驗證碼的宕機 product: "float", // 產(chǎn)品形式,包括:float,popup width: "280px", https: true // 更多配置參數(shù)說明請參見:http://docs.geetest.com/install/client/web-front/ }, handler); } }); } function codeCutdown() { if(_wait == 0){ //倒計時完成 $(".getcheckcode").removeClass('dis').html("重新獲取"); }else{ $(".getcheckcode").addClass('dis').html("重新獲取("+_wait+"s)"); _wait--; setTimeout(function () { codeCutdown(); },1000); } } function inputValidate(ele,telInput) { var oInput = ele; var inputVal = oInput.val(); var oType = ele.attr('data-type'); var oEtag = $('#etag').val(); var oErr = oInput.closest('.form_box').next('.err_txt'); var empTxt = '請輸入'+oInput.attr('placeholder')+'!'; var errTxt = '請輸入正確的'+oInput.attr('placeholder')+'!'; var pattern; if(inputVal==""){ if(!telInput){ errFun(oErr,empTxt); } return false; }else { switch (oType){ case 'login_mobile': pattern = /^1[3456789]\d{9}$/; if(inputVal.length==11) { $.ajax({ url: '/login/checkmobile', type: "post", dataType: "json", data: { mobile: inputVal, etag: oEtag, page_ur: window.location.href, page_referer: document.referrer }, success: function (data) { } }); } break; case 'login_yzm': pattern = /^\d{6}$/; break; } if(oType=='login_mobile'){ } if(!!validateFun(pattern,inputVal)){ errFun(oErr,'') if(telInput){ $('.getcheckcode').removeClass('dis'); } }else { if(!telInput) { errFun(oErr, errTxt); }else { $('.getcheckcode').addClass('dis'); } return false; } } return true; } function errFun(obj,msg) { obj.html(msg); if(msg==''){ $('.login_submit').removeClass('dis'); }else { $('.login_submit').addClass('dis'); } } function validateFun(pat,val) { return pat.test(val); }