Logo

新人日誌

首頁關於我部落格

新人日誌

Logo

網站會不定期發佈技術筆記、職場心得相關的內容,歡迎關注本站!

網站
首頁關於我部落格
部落格
分類系列文

© 新人日誌. All rights reserved. 2020-present.

本文為「SQL 資料庫新手村」系列第 53 篇

跨表單查詢:JOIN 的執行順序是什麼?

最後更新:2026年2月4日資料庫

學了 JOIN 之後,你可能會好奇:JOIN 跟 WHERE 的執行順序是什麼?

例如:

SELECT 組別.名稱, 組員.名稱
FROM 組別
LEFT JOIN 組員 ON 組別.組別ID = 組員.組別ID
WHERE 組別.領域 = 'Web'

這段 SQL 裡面有三件事:JOIN(合併)、ON(合併條件)、WHERE(篩選條件)。

問題來了:這三件事的執行順序是什麼?

是先做完 JOIN 的排列組合,再用 ON 和 WHERE 篩選?

還是先用 WHERE 把資料篩小,再做 JOIN?

這個順序會影響效能嗎?

JOIN 和 ON 的執行順序

先回顧一下,前面學到的執行順序:

  1. FROM — 決定從哪張表讀資料
  2. WHERE — 篩選資料
  3. SELECT — 選取欄位

JOIN 寫在 FROM 後面,所以它跟 FROM 是同一個階段。

加上 JOIN 之後,執行順序變成:

  1. FROM + JOIN + ON — 合併兩張表,用 ON 篩選配對
  2. WHERE — 篩選合併後的資料
  3. SELECT — 選取欄位

FROM 先做,這完全沒有懸念。

但 FROM 這個階段裡面,JOIN 和 ON 的順序是什麼?

前面的文章有提到,JOIN 的運作方式是:先把兩張表做排列組合,再用 ON 條件篩選。

所以在 FROM 這個階段裡,順序是:

  1. 先做排列組合(把兩張表的每一列互相配對)
  2. 再用 ON 條件篩選(留下符合條件的配對)

這很合理,因為你還沒合併之前,根本沒辦法做篩選。

合併完之後,才進到 WHERE 階段,再做一次篩選。

整個流程是:排列組合 → ON 篩選 → WHERE 篩選。

但這個順序有一個隱憂:效能。

排列組合的效能問題

如果真的按照上面的順序,資料庫要先做完整的排列組合,再來篩選。

想像一下:組別表有 10 萬筆資料,組員表也有 10 萬筆資料。

排列組合就是 10 萬 × 10 萬 = 100 億筆。

先做出 100 億筆配對,再慢慢篩選?

這樣也太浪費了。

如果能在合併之前,先把資料篩小,效能應該會好很多。

例如我們只需要 Web 領域的組別,組別表裡可能只有 2 筆是 Web。

2 × 10 萬 = 20 萬筆,跟 100 億比起來差非常多。

所以直覺上,應該「先篩選,再合併」會比較好。

那這兩種做法寫成 SQL 會長什麼樣子?我們用一個具體的例子來比較。

先併再篩 vs 先篩再併

題目:找出 Web 領域的組別,以及這些組別底下的組員。

組別表:

組別ID名稱領域
1前端一組Web
2前端二組Web
3AI 團隊機器學習
4App 團隊App
名稱前端一組
領域Web
名稱前端二組
領域Web
名稱AI 團隊
領域機器學習
名稱App 團隊
領域App

組員表:

組員ID名稱組別ID
1Alice1
2Bob1
3Carol2
4Dave3
5Eve4
名稱Alice
組別ID1
名稱Bob
組別ID1
名稱Carol
組別ID2
名稱Dave
組別ID3
名稱Eve
組別ID4

先併再篩

先把兩張表合併,再用 WHERE 篩選:

SELECT 組別.名稱 AS 組別名稱, 組員.名稱 AS 組員名稱
FROM 組別
LEFT JOIN 組員 ON 組別.組別ID = 組員.組別ID
WHERE 組別.領域 = 'Web'

照前面說的執行順序,資料庫會:

  1. 先做排列組合(4 × 5 = 20 筆配對)
  2. 用 ON 條件篩選(留下組別ID 相符的,剩 5 筆)
  3. 用 WHERE 篩選(留下領域是 Web 的,剩 3 筆)

最終結果:

組別名稱組員名稱
前端一組Alice
前端一組Bob
前端二組Carol
組員名稱Alice
組員名稱Bob
組員名稱Carol

先篩再併

先用子查詢把組別表篩小,再做合併:

SELECT 篩選後的組別.名稱 AS 組別名稱, 組員.名稱 AS 組員名稱
FROM (
    SELECT * FROM 組別 WHERE 領域 = 'Web'
) AS 篩選後的組別
LEFT JOIN 組員 ON 篩選後的組別.組別ID = 組員.組別ID

這種做法的執行順序是:

  1. 先執行子查詢,從組別表篩出 Web 領域的(剩 2 筆)
  2. 再做排列組合(2 × 5 = 10 筆配對)
  3. 用 ON 條件篩選(留下組別ID 相符的,剩 3 筆)

最終結果:

組別名稱組員名稱
前端一組Alice
前端一組Bob
前端二組Carol
組員名稱Alice
組員名稱Bob
組員名稱Carol

兩種寫法的結果完全一樣。

比較兩種寫法

先併再篩先篩再併
寫法JOIN 之後用 WHERE 篩選用子查詢先篩選,再 JOIN
排列組合大小4 × 5 = 20 筆2 × 5 = 10 筆
可讀性簡單直覺需要寫子查詢,比較複雜
先併再篩JOIN 之後用 WHERE 篩選
先篩再併用子查詢先篩選,再 JOIN
先併再篩4 × 5 = 20 筆
先篩再併2 × 5 = 10 筆
先併再篩簡單直覺
先篩再併需要寫子查詢,比較複雜

從效能的角度來看,先篩再併的排列組合比較小,理論上比較快。

但實際上,你不需要刻意選哪一種。

資料庫會自動優化

你寫的 SQL,其實是在告訴資料庫「你想要什麼結果」,而不是「你要資料庫怎麼做」。

資料庫收到你的 SQL 之後,不會傻傻地照順序執行。

它內部有一個叫「查詢優化器」的機制,會在真正執行之前,先分析你的 SQL,找出最有效率的做法。

例如它看到 WHERE 組別.領域 = 'Web',會判斷:「這個條件只跟組別表有關,我可以先把組別表篩小,再來做 JOIN,這樣排列組合會少很多。」

所以不管你寫的是先併再篩,還是先篩再併,查詢優化器都會自動幫你調整成最有效率的順序。

也就是說,就算你寫了先併再篩:

SELECT 組別.名稱 AS 組別名稱, 組員.名稱 AS 組員名稱
FROM 組別
LEFT JOIN 組員 ON 組別.組別ID = 組員.組別ID
WHERE 組別.領域 = 'Web'

資料庫在執行的時候,會自動把 組別.領域 = 'Web' 提前做,把組別表從 4 筆縮小到 2 筆,再來做 JOIN。

效果跟你手動寫子查詢是一樣的。

如果你去看兩種寫法的執行計畫,會發現執行成本和執行時間幾乎一模一樣。

小結

這篇搞清楚了一件事:JOIN 和 WHERE 的執行順序不用擔心。

概念上的執行順序:

排列組合 → ON 篩選 → WHERE 篩選。

先合併,再篩選。

實際上的執行順序:

資料庫系統會自動優化,把能先做的篩選提前做,減少排列組合的大小。

結論:

不用刻意寫子查詢去「先篩再併」,因為資料庫已經會幫你做這件事。

怎麼方便就怎麼寫,怎麼好讀就怎麼寫。

大部分的情況下,先併再篩的寫法比較簡單乾淨,所以我們通常都用這種寫法。

上一篇跨表單查詢:用不等於(<>)當 JOIN 的 ON 條件
目前還沒有留言,成為第一個留言的人吧!

發表留言

留言將在審核後顯示。

資料庫

目錄

  • JOIN 和 ON 的執行順序
  • 排列組合的效能問題
  • 先併再篩 vs 先篩再併
  • 先併再篩
  • 先篩再併
  • 比較兩種寫法
  • 資料庫會自動優化
  • 小結