mysql條件下推的實(shí)現(xiàn)
在日常 Java 開(kāi)發(fā)中,我們常寫(xiě)各種復(fù)雜的 SQL:嵌套查詢、視圖、分頁(yè)、聚合……而當(dāng)查詢語(yǔ)句一旦嵌套了子查詢或視圖,性能就可能撲街。
于是,一個(gè)非常重要的優(yōu)化技術(shù)就顯得格外關(guān)鍵:條件下推(Predicate Pushdown) 。
今天我們不說(shuō)虛的,從實(shí)際例子出發(fā),一口氣把這招講透!
?? 條件下推到底是啥?
通俗地說(shuō):
條件下推是一種優(yōu)化器層面的 SQL 優(yōu)化策略,
把原本在外層執(zhí)行的 WHERE 條件,盡可能提前“下推”到子查詢或視圖中執(zhí)行,
這樣能更早過(guò)濾無(wú)用數(shù)據(jù),減少中間結(jié)果量,提高執(zhí)行效率。
?? 來(lái)個(gè)例子看不下推 vs 下推的區(qū)別
表結(jié)構(gòu)
CREATE TABLE employees ( id INT PRIMARY KEY, name VARCHAR(50), department_id INT, salary INT );
我們寫(xiě)了個(gè)看似合理的 SQL ??:
SELECT * FROM ( SELECT * FROM employees WHERE department_id = 10 ) AS e WHERE salary > 10000;
?? 沒(méi)有條件下推的情況下
執(zhí)行順序:
- 先執(zhí)行子查詢:
SELECT * FROM employees WHERE department_id = 10 - 得到一個(gè)臨時(shí)表
e - 外層再?gòu)?e 中篩選:
salary > 10000
?? 問(wèn)題:如果 department_id = 10 的人很多,哪怕 salary > 10000 的人很少,也會(huì)先把大堆人“查出來(lái)”,再過(guò)濾。
? 啟用條件下推的情況下
MySQL 優(yōu)化器會(huì)聰明地把 salary > 10000 也放到子查詢中一起執(zhí)行!
變成 ??:
SELECT * FROM employees WHERE department_id = 10 AND salary > 10000;
這才是我們想要的效果:查詢更早過(guò)濾數(shù)據(jù),避免生成大中間表,臨時(shí)表都不用建了!
?? 實(shí)戰(zhàn)分析:用 EXPLAIN 看下推效果
EXPLAIN SELECT * FROM ( SELECT * FROM employees WHERE department_id = 10 ) AS e WHERE salary > 10000;
觀察:
- 是否只看到子查詢一步(說(shuō)明優(yōu)化器已下推)
filtered百分比是否變小- 如果啟用了臨時(shí)表/Using temporary,說(shuō)明沒(méi)下推成功
更直觀方式是:和這條語(yǔ)句的 EXPLAIN 結(jié)果對(duì)比:
EXPLAIN SELECT * FROM employees WHERE department_id = 10 AND salary > 10000;
如果兩者執(zhí)行計(jì)劃幾乎一致,說(shuō)明優(yōu)化器下推成功了 ?
?? 條件下推最常見(jiàn)的應(yīng)用場(chǎng)景
| 場(chǎng)景類(lèi)型 | 是否支持條件下推 | 說(shuō)明 |
|---|---|---|
| 子查詢 | ? 是 | 經(jīng)典用途 |
| 視圖 | ? 是 | View 是語(yǔ)法糖,本質(zhì)是子查詢 |
| 分區(qū)表 | ? 是 | 與分區(qū)裁剪結(jié)合效果更佳 |
| JOIN | ?? 有限支持 | 復(fù)雜 JOIN 條件不一定能下推 |
| 外部數(shù)據(jù)源 | ? 是 | 如 Hive、ClickHouse 外部表 |
?? 注意:不是所有情況都能下推!
這些情況容易讓優(yōu)化器“放棄下推”:
| 情況 | 影響 |
|---|---|
| 外層用了函數(shù)包裝字段 | 無(wú)法識(shí)別可下推條件 |
| 外層字段是表達(dá)式或別名 | 不能反向推導(dǎo)條件 |
| 使用了 GROUP BY 或 HAVING | 聚合后無(wú)法再細(xì)化過(guò)濾條件 |
| 子查詢用了 LIMIT、DISTINCT | 限制了優(yōu)化器自由度 |
例子:
SELECT * FROM ( SELECT salary * 1.1 AS new_salary FROM employees ) AS e WHERE new_salary > 10000;
?? 這種就無(wú)法下推,因?yàn)?new_salary > 10000 沒(méi)法“還原”到底層字段。
?? 實(shí)戰(zhàn)建議 for Java 技術(shù)棧開(kāi)發(fā)者
- 避免在子查詢中 return 表達(dá)式字段(別名 + 運(yùn)算)
- 多用
EXPLAIN驗(yàn)證優(yōu)化效果,確認(rèn)是否用了Using where - 大型系統(tǒng)中使用視圖時(shí),建議WHERE 條件不要都放在外層
- 合理使用 MyBatis XML + 動(dòng)態(tài) SQL,讓條件直接拼入子查詢中
? 總結(jié)口訣
??
“能早篩選,就別晚過(guò)濾;條件不下推,優(yōu)化全白費(fèi)。”
?? 彩蛋擴(kuò)展:條件下推 VS 索引下推
| 項(xiàng)目 | 條件下推(Predicate Pushdown) | 索引下推(Index Condition Pushdown) |
|---|---|---|
| 執(zhí)行階段 | 優(yōu)化器邏輯階段 | 存儲(chǔ)引擎執(zhí)行階段 |
| 目標(biāo) | 提前過(guò)濾,減少中間表 | 減少回表次數(shù) |
| 作用位置 | 子查詢 / 視圖 / 分區(qū)等 | InnoDB 索引掃描過(guò)程中 |
| 是否依賴索引 | 否 | 是 |
?? 它們是兩種不同層級(jí)的優(yōu)化技術(shù),可以協(xié)同作戰(zhàn)。
??♂? 最后一句話:
想寫(xiě)出高性能 SQL,別只盯著索引,學(xué)會(huì)引導(dǎo)優(yōu)化器聰明地下推條件,才是真正的大師手筆。
到此這篇關(guān)于mysql條件下推的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)mysql條件下推內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一文學(xué)會(huì)Mysql數(shù)據(jù)庫(kù)備份與恢復(fù)
數(shù)據(jù)庫(kù)備份是在數(shù)據(jù)丟失的情況下能及時(shí)恢復(fù)重要數(shù)據(jù),防止數(shù)據(jù)丟失的一種重要手段,下面這篇文章主要給大家介紹了關(guān)于Mysql數(shù)據(jù)庫(kù)備份與恢復(fù)的相關(guān)資料,需要的朋友可以參考下2022-05-05
MySQL中觸發(fā)器的基礎(chǔ)學(xué)習(xí)教程
這篇文章主要介紹了MySQL中觸發(fā)器的基礎(chǔ)學(xué)習(xí)教程,包括對(duì)觸發(fā)器的創(chuàng)建和管理等基本知識(shí),著力推薦!需要的朋友可以參考下2015-12-12
mysql8.0及以上my.cnf設(shè)置lower_case_table_names=1無(wú)法啟動(dòng)問(wèn)題
這篇文章主要介紹了mysql8.0及以上my.cnf設(shè)置lower_case_table_names=1無(wú)法啟動(dòng)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11
MySQL中distinct語(yǔ)句的基本原理及其與group by的比較
這篇文章主要介紹了MySQL中distinct語(yǔ)句的基本原理及其與group by的比較,一般情況下來(lái)說(shuō)group by和distinct的實(shí)現(xiàn)原理相近且性能稍好,需要的朋友可以參考下2016-01-01
安裝mysql 8.0.17并配置遠(yuǎn)程訪問(wèn)的方法

