2023-07-10 16:18:28來(lái)源:一樹(shù)一溪
這篇文章依然源于一位讀者的提問(wèn):explain 顯示 count(*) 使用了索引,optimizer trace 卻顯示為全表掃描,這是為什么?
還記得當(dāng)時(shí)調(diào)試源碼的過(guò)程中,如果 explain 顯示會(huì)使用二級(jí)索引進(jìn)行全索引掃描,執(zhí)行時(shí)也確實(shí)只會(huì)從二級(jí)索引中讀取記錄,不會(huì)進(jìn)行全表掃描。
【資料圖】
不過(guò),那會(huì)沒(méi)有關(guān)注過(guò) optimizer trace 是怎么顯示的。
既然不能從記憶里找到答案,那就只能從源碼里找答案了。
擼完源碼發(fā)現(xiàn):和 5.7.35 版本相比,8.0.32 的count(*)實(shí)現(xiàn)邏輯,確實(shí)有了一些變化。
接下來(lái),我們一起來(lái)看看。
1、準(zhǔn)備工作本文基于 MySQL 8.0.32 源碼,存儲(chǔ)引擎為 InnoDB。如需轉(zhuǎn)載,請(qǐng)聯(lián)系『一樹(shù)一溪』公眾號(hào)作者。
創(chuàng)建測(cè)試表:
CREATE TABLE `t1` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `i1` int DEFAULT "0", PRIMARY KEY (`id`) USING BTREE, KEY `idx_i1` (`i1`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3
插入數(shù)據(jù):
INSERT INTO `t1`(`id`, `i1`)VALUES (10, 101), (20, 201), (30, 301);
2、問(wèn)題重現(xiàn)及分析explain 查看執(zhí)行計(jì)劃:
EXPLAIN SELECT COUNT(*) FROM `t1`;
結(jié)果如下(只截取了部分字段):
圖片
再來(lái)看看 optimizer trace 描述的執(zhí)行計(jì)劃,依次執(zhí)行以下 3 條 SQL:
-- 開(kāi)啟 optimizer traceSET optimizer_trace = "enabled=on";-- 執(zhí)行 SELECT 語(yǔ)句SELECT COUNT(*) FROM `t1`;-- 獲取 optimizer traceSELECT * FROM information_schema.optimizer_trace;
結(jié)果如下(只截取了部分內(nèi)容):
{ "considered_execution_plans": [ { "plan_prefix": [ ], "table": "`t1`", "best_access_path": { "considered_access_paths": [ { "rows_to_scan": 3, "access_type": "scan", "resulting_rows": 3, "cost": 0.55, "chosen": true } ] }, "condition_filtering_pct": 100, "rows_for_plan": 3, "cost_for_plan": 0.55, "chosen": true } ]}
我們來(lái)對(duì)比下 explain 和 optimizer trace 的結(jié)果:
explain 輸出結(jié)果中,type 字段值為index、key 字段值為idx_i1,表示會(huì)使用 idx_i1 作為覆蓋索引執(zhí)行 select 語(yǔ)句。由于沒(méi)有 where 條件,select 語(yǔ)句會(huì)對(duì)二級(jí)索引idx_i1進(jìn)行全索引掃描,以獲取t1表的記錄數(shù)量。optimizer trace 輸出結(jié)果中,沒(méi)有顯示會(huì)使用索引idx_i1,而且,access_type 為scan,看起來(lái)像是會(huì)進(jìn)行全表掃描。我在 5.7.35 中調(diào)試了這條 SQL:
SELECT COUNT(*) FROM `t1`
可以證實(shí),select 語(yǔ)句執(zhí)行過(guò)程中,確實(shí)對(duì)idx_i1進(jìn)行了全索引掃描,和 explain 輸出的執(zhí)行計(jì)劃一致。
同時(shí)也確認(rèn)了:不管是對(duì)主鍵索引進(jìn)行全索引掃描(也就是全表掃描),還是對(duì)二級(jí)索引進(jìn)行全索引掃描,optimizer trace 的輸出結(jié)果中,access_type字段值都是scan。
我又在 8.0.32 中調(diào)試了上面的 SQL,發(fā)現(xiàn)了新情況:InnoDB 對(duì)不包含 where 條件的select count(*) from table語(yǔ)句進(jìn)行了特殊處理。
跟隨調(diào)試過(guò)程,我們一起來(lái)看看 InnoDB 做了什么特殊處理。
程序執(zhí)行到ha_records()方法時(shí),我們可以看到,index參數(shù)的值是1,這就是執(zhí)行計(jì)劃確定要使用的索引 ID。
圖片
我們?cè)谡{(diào)試控制臺(tái)打印索引名字,可以看到 ID = 1 的索引就idx_i1:
圖片
ha_records()會(huì)調(diào)用records_from_index(),代碼如下:
圖片
從以上代碼可以看到,ha_records() 把索引idx_i1的 ID 傳給了 records_from_index() 的第 2 個(gè)參數(shù),但是,該方法的第 2 個(gè)參數(shù),只有類型(uint),沒(méi)有名字,這說(shuō)明第 2 個(gè)參數(shù)不能被使用。
也就是說(shuō),雖然執(zhí)行計(jì)劃確定了要使用索引idx_i1來(lái)統(tǒng)計(jì)t1表的記錄數(shù)量,records_from_index()卻沒(méi)有真正使用 idx_i1。
從代碼注釋也可以看到:在實(shí)現(xiàn)二級(jí)索引的并行掃描之前,records_from_index() 會(huì)強(qiáng)制使用主鍵索引來(lái)統(tǒng)計(jì)表中的記錄數(shù)量。
在 github 中追溯代碼提交歷史,發(fā)現(xiàn)records_from_index()是8.0.17版本新加的。
從這個(gè)版本開(kāi)始,到最新的8.0.33,對(duì)于不包含 where 條件的select count(*) from table語(yǔ)句,都會(huì)強(qiáng)制使用主鍵索引(也就是會(huì)進(jìn)行全表掃描)。
之所以這么做,是為了使用多個(gè)線程對(duì)主鍵索引進(jìn)行并行掃描,以提升執(zhí)行速度。
3、總結(jié)雖然本文內(nèi)容比較短,但是本著完整的原則,還是進(jìn)行個(gè)簡(jiǎn)單的總結(jié):
8.0.16(含)版本之前,對(duì)于select count(*) from table語(yǔ)句,如果表中有二級(jí)索引,InnoDB 會(huì)選擇對(duì)某個(gè)二級(jí)索引進(jìn)行全索引掃描,以獲取表中的記錄數(shù)量。從 8.0.17(含)版本開(kāi)始,直到目前的最新版本(8.0.33),如果表中有二級(jí)索引,explain 輸出的執(zhí)行計(jì)劃也表示會(huì)使用二級(jí)索引,然而,實(shí)際執(zhí)行過(guò)程中,InnoDB 卻會(huì)強(qiáng)制進(jìn)行全表掃描,以使用主鍵索引的并行掃描能力。optimizer trace 的結(jié)果中,對(duì)于select count(*) from table語(yǔ)句,二級(jí)索引的全索引掃描和全表掃描同等對(duì)待,執(zhí)行計(jì)劃的access_type字段值都是scan。關(guān)鍵詞:
這篇文章依然源于一位讀者的提問(wèn):explain顯示count(*)使用了索引,opt
相信大家對(duì)樓下衛(wèi)生間漏水一定是樓上的原因嗎,衛(wèi)生間反堿會(huì)漏水嗎的問(wèn)
7月8日,在巴東縣神農(nóng)新區(qū)的巴東廣場(chǎng)上,居民及游客正在休閑散步、運(yùn)動(dòng)
不用贅述,大家都知道,最近半年ChatGPT是有多么火爆。隨著ChatGPT的全
DHCP出現(xiàn)電腦或手機(jī)需要IP地址才能上網(wǎng)。大劉有兩臺(tái)電腦和兩臺(tái)手機(jī),小
近年來(lái),云的采用率急劇增加。事實(shí)上,幾乎所有組織都在云中留下了某種
跟上最新的趨勢(shì)是成為一個(gè)精通網(wǎng)絡(luò)的專業(yè)人士的必要條件。在這樣一個(gè)快
預(yù)測(cè)到2028年,全球企業(yè)在專用網(wǎng)絡(luò)上的支出將從2023年的10億美元增加到
一、前言?對(duì)于普通用戶來(lái)說(shuō),13代intel處理器的性能表現(xiàn)已經(jīng)足夠強(qiáng)悍
證券時(shí)報(bào)e公司訊,宇信科技消息,7月5日,2023全球數(shù)字經(jīng)濟(jì)大會(huì)“數(shù)字
考慮云遷移的企業(yè)必須了解可用的云部署模型,以便做出最佳的業(yè)務(wù)決策。
人工是幾年來(lái)的流行語(yǔ),直到科技營(yíng)銷人員開(kāi)始利用人工智能的潛力。無(wú)論
在Pandas2 0發(fā)布以后,我們發(fā)布過(guò)一些評(píng)測(cè)的文章,這次我們看看,除了P
VR游戲「VRosty」的設(shè)計(jì)理念既富有創(chuàng)意又拋出問(wèn)題:為什么玩家不能采用
csgo是一款熱門(mén)的第一人稱射擊游戲,游戲中有各式各樣精美的皮膚,玩家