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

