
在 MySQL SQL 調(diào)優(yōu)中,EXPLAIN
執(zhí)行計劃是核心工具,而其中的rows
列(估算的掃描行數(shù))更是優(yōu)化器選擇執(zhí)行計劃的關(guān)鍵參考 —— 它直接影響優(yōu)化器對 “全表掃描 vs 索引掃描”“join 表順序”“索引選擇” 的判斷。但實(shí)際使用中,開發(fā)者常困惑:rows
值是精確值還是估算值?為什么有時和實(shí)際掃描行數(shù)相差懸殊?本文將從rows
的計算原理出發(fā),拆解準(zhǔn)確性的影響因素,提供判斷與優(yōu)化方法,幫助讀者正確利用rows
進(jìn)行 SQL 調(diào)優(yōu)。
首先需明確一個核心前提:MySQL 執(zhí)行計劃中的rows
列,不是實(shí)際執(zhí)行 SQL 時掃描的行數(shù),而是優(yōu)化器基于 “統(tǒng)計信息” 估算的 “需要掃描的行數(shù)”。其核心作用是為優(yōu)化器提供 “成本評估依據(jù)”—— 優(yōu)化器通過rows
估算 “IO 成本”(讀取數(shù)據(jù)頁的數(shù)量)和 “CPU 成本”(處理數(shù)據(jù)的耗時),最終選擇成本最低的執(zhí)行計劃。
MySQL 優(yōu)化器無法實(shí)時遍歷表或索引獲取精確行數(shù)(否則會消耗大量資源,違背 “執(zhí)行計劃快速生成” 的初衷),而是依賴存儲引擎(如 InnoDB、MyISAM)維護(hù)的 “統(tǒng)計信息” 進(jìn)行估算,核心統(tǒng)計信息包括:
表級統(tǒng)計:表的總行數(shù)(TABLE_ROWS
,可通過INFORMATION_SCHEMA.TABLES
查詢)、數(shù)據(jù)頁數(shù)量、平均行長度;
索引級統(tǒng)計:索引的基數(shù)(CARDINALITY
,索引列不重復(fù)值的數(shù)量,可通過SHOW INDEX FROM 表名
查詢)、索引樹的深度、索引頁數(shù)量;
列值分布統(tǒng)計:列值的直方圖(MySQL 8.0 引入,記錄列值的分布區(qū)間及每個區(qū)間的行數(shù),用于優(yōu)化范圍查詢的估算)。
例如,對于單表等值查詢SELECT * FROM user WHERE age = 30
,優(yōu)化器的估算邏輯為:
rows ≈ 表總行數(shù)(TABLE_ROWS) / 索引列age的基數(shù)(CARDINALITY)
若表總行數(shù) 10000,age 的基數(shù) 100(即 age 有 100 個不同值,平均每個值對應(yīng) 100 行),則rows
估算為 100。
不必追求rows
與實(shí)際掃描行數(shù)完全一致 —— 優(yōu)化器只需rows
在 “合理誤差范圍”(通常認(rèn)為 10 倍以內(nèi)),就能正確選擇執(zhí)行計劃。例如:
若實(shí)際掃描行數(shù) 100,rows
估算為 80 或 120,優(yōu)化器仍會選擇正確的索引;
若rows
估算為 1000(實(shí)際 100),可能導(dǎo)致優(yōu)化器誤判 “索引掃描成本高”,轉(zhuǎn)而選擇全表掃描,此時才需關(guān)注準(zhǔn)確性問題。
rows
的準(zhǔn)確性由 “統(tǒng)計信息質(zhì)量”“查詢復(fù)雜度”“存儲引擎特性” 三大維度決定,不同場景下準(zhǔn)確性差異顯著。
當(dāng)統(tǒng)計信息新鮮、查詢邏輯簡單、數(shù)據(jù)分布均勻時,rows
估算值與實(shí)際值偏差通常小于 20%,典型場景包括:
剛執(zhí)行過ANALYZE TABLE 表名
(手動更新統(tǒng)計信息),或 MySQL 自動觸發(fā)統(tǒng)計信息更新(如 InnoDB 在數(shù)據(jù)修改量超過 10% 時自動更新);
表數(shù)據(jù)量?。ㄈ?< 1 萬行),統(tǒng)計信息采樣率足夠高(小表默認(rèn)全量采樣,無抽樣誤差)。
示例:
對 1000 行的user
表執(zhí)行ANALYZE TABLE user
后,執(zhí)行EXPLAIN SELECT * FROM user WHERE id = 10
(id
為主鍵,基數(shù) 1000):
rows = 1
(主鍵唯一,每個值對應(yīng) 1 行),實(shí)際掃描行數(shù)也為 1,偏差 0%。查詢條件為等值查詢(=
)或極小范圍查詢(BETWEEN 1 AND 5
),數(shù)據(jù)分布均勻。
示例:
user
表有 10 萬行,phone
列唯一索引(基數(shù) 10 萬),執(zhí)行EXPLAIN SELECT * FROM user WHERE phone = '13800138000'
:
優(yōu)化器估算rows = 1
,實(shí)際掃描行數(shù) 1,偏差 0%;
若phone
列非唯一(基數(shù) 5 萬,平均每個值對應(yīng) 2 行),執(zhí)行EXPLAIN SELECT * FROM user WHERE phone = '13800138000'
,估算rows = 2
,實(shí)際掃描行數(shù)通常為 1-3 行,偏差 < 50%。
MySQL 8.0 引入 “列值直方圖”,針對數(shù)據(jù)分布不均勻的列(如電商訂單表的amount
列,多數(shù)訂單集中在 100-500 元,少數(shù)大額訂單 > 10000 元),能更精準(zhǔn)估算范圍查詢的rows
值。
示例:
order
表amount
列有直方圖,執(zhí)行EXPLAIN SELECT * FROM order WHERE amount BETWEEN 200 AND 300
:
無直方圖時,優(yōu)化器可能按 “平均分布” 估算(如總行數(shù) 10 萬,amount
基數(shù) 1000,估算rows = 100
);
有直方圖時,優(yōu)化器能識別 “200-300 元區(qū)間占比 30%”,估算rows = 30000
,與實(shí)際行數(shù)偏差 < 10%。
當(dāng)統(tǒng)計信息過期、查詢復(fù)雜、數(shù)據(jù)分布極端時,rows
偏差可能超過 10 倍甚至 100 倍,典型場景包括:
表數(shù)據(jù)頻繁增刪改(如每小時新增 1 萬行),但未觸發(fā)統(tǒng)計信息更新(InnoDB 默認(rèn)修改量超 10% 才更新,大表可能延遲);
大表(如 1000 萬行以上)使用默認(rèn)采樣率(InnoDB 持久化統(tǒng)計信息默認(rèn)采樣innodb_stats_persistent_sample_pages = 20
),采樣誤差導(dǎo)致基數(shù)估算偏差。
示例:
1000 萬行的log
表,create_time
列普通索引,默認(rèn)采樣 20 個數(shù)據(jù)頁:
實(shí)際create_time
的基數(shù)為 100 萬(每天新增約 3 萬行,共 300 天數(shù)據(jù)),但采樣時恰好命中 “某幾天的重復(fù)數(shù)據(jù)”,導(dǎo)致優(yōu)化器估算基數(shù)為 10 萬;
執(zhí)行EXPLAIN SELECT * FROM log WHERE create_time BETWEEN '2024-01-01' AND '2024-01-02'
,實(shí)際掃描行數(shù) 3 萬,估算rows = 30萬
(偏差 10 倍)。
多表 join、子查詢、復(fù)雜條件(OR
、NOT IN
、函數(shù)操作)會增加優(yōu)化器的估算難度,導(dǎo)致rows
偏差放大:
多表 join:優(yōu)化器需估算 “驅(qū)動表與被驅(qū)動表的匹配行數(shù)”,若其中一個表的rows
估算不準(zhǔn),會連鎖影響整體 join 行數(shù)的估算;
子查詢:尤其是IN (子查詢)
或EXISTS (子查詢)
,優(yōu)化器可能簡化子查詢的估算邏輯,導(dǎo)致外層查詢rows
偏差;
函數(shù)操作:如WHERE DATE(create_time) = '2024-01-01'
(索引失效,優(yōu)化器只能按全表掃描估算,rows
接近表總行數(shù),與實(shí)際掃描行數(shù)偏差大)。
示例:
3 表 join 查詢EXPLAIN SELECT * FROM a JOIN b ON ``a.id`` = b.a_id JOIN c ON ``b.id`` = c.b_id WHERE a.status = 1
:
a
表status=1
的實(shí)際行數(shù) 100,但優(yōu)化器估算rows=1000
(統(tǒng)計信息過期),則b
表和c
表的rows
估算會基于 1000 行驅(qū)動,最終整體rows
偏差可能達(dá) 10 倍以上。低選擇性索引:索引列重復(fù)值多(如gender
列,只有 “男 / 女” 兩個值,基數(shù) = 2),優(yōu)化器按 “表總行數(shù) / 基數(shù)” 估算rows
(如 10 萬行表,估算rows=5萬
),但實(shí)際某一性別可能占 80%(8 萬行),偏差 60%;
極端數(shù)據(jù)分布:如user
表age
列,90% 的行集中在 18-30 歲,10% 在 30 歲以上,執(zhí)行EXPLAIN SELECT * FROM user WHERE age > 30
,優(yōu)化器按 “平均分布” 估算rows=1萬
(10 萬 ×10%),但實(shí)際可能因采樣誤差估算為 5 萬(偏差 5 倍)。
MyISAM:統(tǒng)計信息存儲在內(nèi)存中,表關(guān)閉后會丟失,重啟 MySQL 后需重新計算(可能導(dǎo)致臨時估算偏差);
InnoDB:早期版本(<5.6)不支持持久化統(tǒng)計信息,重啟后統(tǒng)計信息重置,大表估算偏差顯著;MySQL 5.6 + 支持持久化統(tǒng)計信息(innodb_stats_persistent = ON
),但默認(rèn)采樣率仍可能不足。
判斷rows
是否 “足夠準(zhǔn)確”,核心是對比 “執(zhí)行計劃的rows
” 與 “實(shí)際掃描行數(shù)”,常用方法有 3 種:
SHOW PROFILE
查看實(shí)際掃描行數(shù)SHOW PROFILE
可查看 SQL 執(zhí)行的詳細(xì)步驟,包括 “實(shí)際掃描的行數(shù)”(Rows_examined
):
-- 1. 開啟profiling
SET profiling = 1;
-- 2. 執(zhí)行目標(biāo)SQL
SELECT * FROM user WHERE age BETWEEN 20 AND 30;
-- 3. 查看profile結(jié)果
SHOW PROFILE FOR QUERY 1; -- Query 1為SQL的編號,可通過SHOW PROFILES查看
-- 關(guān)鍵輸出:Rows_examined: 1200(實(shí)際掃描行數(shù))
-- 對比執(zhí)行計劃的rows:若EXPLAIN中rows=1000,偏差20%,屬于可接受范圍;若rows=5000,偏差4倍,需優(yōu)化
EXPLAIN ANALYZE
(MySQL 8.0.18+)直接對比MySQL 8.0.18 引入EXPLAIN ANALYZE
,會實(shí)際執(zhí)行 SQL(但不返回結(jié)果集),同時輸出 “估算 rows” 與 “實(shí)際 rows”,是最直觀的判斷方法:
EXPLAIN ANALYZE
SELECT * FROM user WHERE age BETWEEN 20 AND 30;
-- 典型輸出(關(guān)鍵部分):
-- -> Index Range Scan on user using idx_age over (age between 20 and 30)
-- (cost=120.00 rows=1000) (actual time=0.022..0.150 rows=1200 loops=1)
-- 解讀:估算rows=1000,實(shí)際rows=1200,偏差20%,準(zhǔn)確性可接受
對于數(shù)據(jù)量較小的表(如 < 10 萬行),可直接執(zhí)行 SQL 并計數(shù),與EXPLAIN
的rows
對比:
-- 1. 查看執(zhí)行計劃的rows
EXPLAIN SELECT * FROM user WHERE age BETWEEN 20 AND 30; -- 假設(shè)rows=1000
-- 2. 手動計數(shù)實(shí)際行數(shù)
SELECT COUNT(*) FROM user WHERE age BETWEEN 20 AND 30; -- 假設(shè)結(jié)果=1200
-- 對比:偏差20%,可接受;若計數(shù)=5000,偏差5倍,需優(yōu)化
當(dāng)rows
偏差過大(如超過 10 倍),導(dǎo)致優(yōu)化器選擇錯誤執(zhí)行計劃(如該用索引卻全表掃描)時,可通過以下策略優(yōu)化:
通過ANALYZE TABLE
手動更新表的統(tǒng)計信息,適用于統(tǒng)計信息過期的場景:
-- 1. 基礎(chǔ)更新:更新指定表的統(tǒng)計信息
ANALYZE TABLE user, order;
-- 2. 進(jìn)階:InnoDB強(qiáng)制全量采樣(大表慎用,可能耗時)
-- 臨時設(shè)置采樣頁數(shù)量為表的總數(shù)據(jù)頁數(shù)(需先查詢總頁數(shù))
SELECT CEIL(data_length / @@innodb_page_size) AS total_pages FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'user';
SET innodb_stats_persistent_sample_pages = 1000; -- 假設(shè)總頁數(shù)1000
ANALYZE TABLE user;
SET innodb_stats_persistent_sample_pages = 20; -- 恢復(fù)默認(rèn)值,避免后續(xù)性能影響
注意:ANALYZE TABLE
會對表加 “讀鎖”(InnoDB 在 MySQL 8.0 中已優(yōu)化為輕量級鎖,不阻塞 DML),大表(如 1000 萬行以上)建議在業(yè)務(wù)低峰期執(zhí)行。
InnoDB 的統(tǒng)計信息采樣率由以下參數(shù)控制,可根據(jù)表大小調(diào)整:
innodb_stats_persistent_sample_pages
:持久化統(tǒng)計信息的采樣頁數(shù)量(默認(rèn) 20),大表可增大至 100-1000,提升基數(shù)估算準(zhǔn)確性;
innodb_stats_transient_sample_pages
:臨時統(tǒng)計信息的采樣頁數(shù)量(默認(rèn) 8),若禁用持久化統(tǒng)計信息(innodb_stats_persistent = OFF
),需調(diào)整此參數(shù)。
示例:
對 1000 萬行的log
表,永久調(diào)整采樣頁數(shù)量:
-- 1. 全局調(diào)整(需重啟MySQL生效)
SET GLOBAL innodb_stats_persistent_sample_pages = 200;
-- 修改配置文件my.cnf,避免重啟失效
innodb_stats_persistent_sample_pages = 200
-- 2. 僅對指定表調(diào)整(MySQL 8.0+支持)
ALTER TABLE log SET STATISTICS_SAMPLE_PAGES = 200;
復(fù)雜查詢是rows
偏差的主要誘因,可通過簡化查詢邏輯提升準(zhǔn)確性:
避免函數(shù)操作索引列:如將DATE(create_time) = '2024-01-01'
改為create_time BETWEEN '2024-01-01 00:00:00' AND '2024-01-01 23:59:59'
,利用索引精準(zhǔn)估算;
拆分復(fù)雜 join:將 3 表以上 join 拆分為 “子查詢 + 關(guān)聯(lián)”,或用STRAIGHT_JOIN
強(qiáng)制指定 join 順序(減少優(yōu)化器的估算誤差);
MySQL 8.0 + 支持為列創(chuàng)建直方圖,針對數(shù)據(jù)分布不均勻的列(如amount
、create_time
),能顯著提升范圍查詢的rows
準(zhǔn)確性:
-- 1. 為order表的amount列創(chuàng)建直方圖
ANALYZE TABLE order UPDATE HISTOGRAM ON amount;
-- 2. 查看直方圖信息
SELECT * FROM INFORMATION_SCHEMA.COLUMN_STATISTICS WHERE TABLE_NAME = 'order' AND COLUMN_NAME = 'amount';
-- 3. 執(zhí)行范圍查詢,查看rows估算
EXPLAIN ANALYZE SELECT * FROM order WHERE amount BETWEEN 200 AND 300;
-- 此時估算rows與實(shí)際rows偏差通常<10%
MySQL 新版本對統(tǒng)計信息和估算算法持續(xù)優(yōu)化:
若使用 MySQL 5.6 及以下版本,升級到 8.0 可顯著提升rows
估算準(zhǔn)確性。
MySQL 執(zhí)行計劃中的rows
是 “估算值”,其核心價值是幫助優(yōu)化器選擇 “成本最低的執(zhí)行計劃”,而非提供 “精確的掃描行數(shù)”。實(shí)際調(diào)優(yōu)中,需把握以下原則:
可接受偏差范圍:若rows
與實(shí)際行數(shù)偏差 < 10 倍,且優(yōu)化器選擇了正確的執(zhí)行計劃(如用索引而非全表掃描),無需過度優(yōu)化;
優(yōu)先解決 “嚴(yán)重偏差”:僅當(dāng)rows
偏差導(dǎo)致優(yōu)化器選擇錯誤執(zhí)行計劃(如該用主鍵索引卻全表掃描)時,才需通過更新統(tǒng)計信息、調(diào)整采樣率等方式優(yōu)化;
結(jié)合其他指標(biāo)判斷:rows
需與執(zhí)行計劃的type
(訪問類型,如ref
、range
、ALL
)、key
(使用的索引)、Extra
(額外信息,如Using index
)結(jié)合,綜合評估 SQL 性能,而非單一依賴rows
。
最終,掌握rows
的估算原理與優(yōu)化方法,能讓開發(fā)者更高效地利用執(zhí)行計劃定位 SQL 性能瓶頸,實(shí)現(xiàn) “精準(zhǔn)調(diào)優(yōu)” 而非 “盲目優(yōu)化”。
數(shù)據(jù)分析咨詢請掃描二維碼
若不方便掃碼,搜微信號:CDAshujufenxi
DSGE 模型中的 Et:理性預(yù)期算子的內(nèi)涵、作用與應(yīng)用解析 動態(tài)隨機(jī)一般均衡(Dynamic Stochastic General Equilibrium, DSGE)模 ...
2025-09-17Python 提取 TIF 中地名的完整指南 一、先明確:TIF 中的地名有哪兩種存在形式? 在開始提取前,需先判斷 TIF 文件的類型 —— ...
2025-09-17CDA 數(shù)據(jù)分析師:解鎖表結(jié)構(gòu)數(shù)據(jù)特征價值的專業(yè)核心 表結(jié)構(gòu)數(shù)據(jù)(以 “行 - 列” 規(guī)范存儲的結(jié)構(gòu)化數(shù)據(jù),如數(shù)據(jù)庫表、Excel 表、 ...
2025-09-17Excel 導(dǎo)入數(shù)據(jù)含缺失值?詳解 dropna 函數(shù)的功能與實(shí)戰(zhàn)應(yīng)用 在用 Python(如 pandas 庫)處理 Excel 數(shù)據(jù)時,“缺失值” 是高頻 ...
2025-09-16深入解析卡方檢驗與 t 檢驗:差異、適用場景與實(shí)踐應(yīng)用 在數(shù)據(jù)分析與統(tǒng)計學(xué)領(lǐng)域,假設(shè)檢驗是驗證研究假設(shè)、判斷數(shù)據(jù)差異是否 “ ...
2025-09-16CDA 數(shù)據(jù)分析師:掌控表格結(jié)構(gòu)數(shù)據(jù)全功能周期的專業(yè)操盤手 表格結(jié)構(gòu)數(shù)據(jù)(以 “行 - 列” 存儲的結(jié)構(gòu)化數(shù)據(jù),如 Excel 表、數(shù)據(jù) ...
2025-09-16MySQL 執(zhí)行計劃中 rows 數(shù)量的準(zhǔn)確性解析:原理、影響因素與優(yōu)化 在 MySQL SQL 調(diào)優(yōu)中,EXPLAIN執(zhí)行計劃是核心工具,而其中的row ...
2025-09-15解析 Python 中 Response 對象的 text 與 content:區(qū)別、場景與實(shí)踐指南 在 Python 進(jìn)行 HTTP 網(wǎng)絡(luò)請求開發(fā)時(如使用requests ...
2025-09-15CDA 數(shù)據(jù)分析師:激活表格結(jié)構(gòu)數(shù)據(jù)價值的核心操盤手 表格結(jié)構(gòu)數(shù)據(jù)(如 Excel 表格、數(shù)據(jù)庫表)是企業(yè)最基礎(chǔ)、最核心的數(shù)據(jù)形態(tài) ...
2025-09-15Python HTTP 請求工具對比:urllib.request 與 requests 的核心差異與選擇指南 在 Python 處理 HTTP 請求(如接口調(diào)用、數(shù)據(jù)爬取 ...
2025-09-12解決 pd.read_csv 讀取長浮點(diǎn)數(shù)據(jù)的科學(xué)計數(shù)法問題 為幫助 Python 數(shù)據(jù)從業(yè)者解決pd.read_csv讀取長浮點(diǎn)數(shù)據(jù)時的科學(xué)計數(shù)法問題 ...
2025-09-12CDA 數(shù)據(jù)分析師:業(yè)務(wù)數(shù)據(jù)分析步驟的落地者與價值優(yōu)化者 業(yè)務(wù)數(shù)據(jù)分析是企業(yè)解決日常運(yùn)營問題、提升執(zhí)行效率的核心手段,其價值 ...
2025-09-12用 SQL 驗證業(yè)務(wù)邏輯:從規(guī)則拆解到數(shù)據(jù)把關(guān)的實(shí)戰(zhàn)指南 在業(yè)務(wù)系統(tǒng)落地過程中,“業(yè)務(wù)邏輯” 是連接 “需求設(shè)計” 與 “用戶體驗 ...
2025-09-11塔吉特百貨孕婦營銷案例:數(shù)據(jù)驅(qū)動下的精準(zhǔn)零售革命與啟示 在零售行業(yè) “流量紅利見頂” 的當(dāng)下,精準(zhǔn)營銷成為企業(yè)突圍的核心方 ...
2025-09-11CDA 數(shù)據(jù)分析師與戰(zhàn)略 / 業(yè)務(wù)數(shù)據(jù)分析:概念辨析與協(xié)同價值 在數(shù)據(jù)驅(qū)動決策的體系中,“戰(zhàn)略數(shù)據(jù)分析”“業(yè)務(wù)數(shù)據(jù)分析” 是企業(yè) ...
2025-09-11Excel 數(shù)據(jù)聚類分析:從操作實(shí)踐到業(yè)務(wù)價值挖掘 在數(shù)據(jù)分析場景中,聚類分析作為 “無監(jiān)督分組” 的核心工具,能從雜亂數(shù)據(jù)中挖 ...
2025-09-10統(tǒng)計模型的核心目的:從數(shù)據(jù)解讀到?jīng)Q策支撐的價值導(dǎo)向 統(tǒng)計模型作為數(shù)據(jù)分析的核心工具,并非簡單的 “公式堆砌”,而是圍繞特定 ...
2025-09-10CDA 數(shù)據(jù)分析師:商業(yè)數(shù)據(jù)分析實(shí)踐的落地者與價值創(chuàng)造者 商業(yè)數(shù)據(jù)分析的價值,最終要在 “實(shí)踐” 中體現(xiàn) —— 脫離業(yè)務(wù)場景的分 ...
2025-09-10機(jī)器學(xué)習(xí)解決實(shí)際問題的核心關(guān)鍵:從業(yè)務(wù)到落地的全流程解析 在人工智能技術(shù)落地的浪潮中,機(jī)器學(xué)習(xí)作為核心工具,已廣泛應(yīng)用于 ...
2025-09-09SPSS 編碼狀態(tài)區(qū)域中 Unicode 的功能與價值解析 在 SPSS(Statistical Product and Service Solutions,統(tǒng)計產(chǎn)品與服務(wù)解決方案 ...
2025-09-09