SQL是如何在數據庫中執行的?

對不少開發者來講,數據庫就是個黑盒子,你會寫 SQL,會用數據庫,但不知道盒子裏面究竟是怎麼一回事兒,這樣你只能機械地去記住別人告訴你的那些優化規則,殊不知道爲何要遵循這些規則,也就談不上靈活運用。數據庫

數據庫的服務端,能夠劃分爲執行器 (Execution Engine) 和存儲引擎 (Storage Engine) 兩部分。編程

  • 執行器負責解析 SQL 執行查詢
  • 存儲引擎負責保存數據。

SQL是如何在執行器中執行的 ?

咱們經過一個例子來看一下,執行器是如何來解析執行一條 SQL 的。編程語言

  • 這個 SQL 語義是,查詢用戶 ID 大於 50 的用戶的全部訂單,這是很簡單的一個聯查,須要查詢 users 和 orders 兩張表,WHERE 條件就是,用戶 ID 大於 50。

SQL是如何在數據庫中執行的?

數據庫收到查詢請求後,須要先解析 SQL 語句,把這一串文本解析成便於程序處理的結構化數據:函數

  • 轉換後的結構化數據,就是一棵樹,這個樹的名字叫抽象語法樹(AST,Abstract Syntax Tree)。上面這個 SQL,它的 AST 大概是這樣的:

SQL是如何在數據庫中執行的?

這個樹太複雜,我只畫了主要的部分,你大體看一下,能理解這個 SQL 的語法樹長什麼樣就好了。執行器解析這個 AST 以後,會生成一個邏輯執行計劃。所謂的執行計劃,能夠簡單理解爲如何一步一步地執行查詢和計算,最終獲得執行結果的一個分步驟的計劃。這個邏輯執行計劃是這樣的:性能

SQL是如何在數據庫中執行的?

和 SQL、AST 不一樣的是,這個邏輯執行計劃已經很像能夠執行的程序代碼了。你看上面這個執行計劃,很像咱們編程語言的函數調用棧,外層的方法調用內層的方法。因此,要理解這個執行計劃,得從內往外看。優化

  1. 最內層的 2 個 LogicalTableScan 的含義是,把 USERS 和 ORDERS 這兩個表的數據都讀出來。
  2. 而後拿這兩個表全部數據作一個 LogicalJoin,JOIN 的條件就是第 0 列 (u.id) 等於第 6 列 (o.user_id)。
  3. 而後再執行一個 LogicalFilter 過濾器,過濾條件是第 0 列 (u.id) 大於 50。
  4. 最後,作一個 LogicalProject 投影,只保留第 0(user_id)、1(user_name)、5(order_id) 三列。這裏「投影 (Project)」的意思是,把不須要的列過濾掉。

把這個邏輯執行計劃翻譯成代碼,而後按照順序執行,就能夠正確地查詢出數據了。可是,按照上面那個執行計劃,須要執行 2 個全表掃描,而後再把 2 個表的全部數據作一個 JOIN 操做,這個性能是很是很是差的。spa

優化的整體思路是,在執行計劃中,儘早地減小必須處理的數據量。也就是說,儘可能在執行計劃的最內層減小須要處理的數據量。看一下簡單優化後的邏輯執行計劃:翻譯

SQL是如何在數據庫中執行的?

對比原始的邏輯執行計劃,這裏咱們作了兩點簡單的優化:blog

  • 儘早地執行投影,去除不須要的列;
  • 儘早地執行數據過濾,去除不須要的行。

到這裏,執行器只是在邏輯層面分析 SQL,優化查詢的執行邏輯,咱們執行計劃中操做的數據,仍然是表、行和列。在數據庫中,表、行、列都是邏輯概念,因此,這個執行計劃叫「邏輯執行計劃」。執行查詢接下來的部分,就須要涉及到數據庫的物理存儲結構了。索引

轉SQL是如何存在存儲引擎中執行的?

數據真正存儲的時候,不管在磁盤裏,仍是在內存中,都無法直接存儲這種帶有行列的二維表。數據庫中的二維表,其實是怎麼存儲的呢?這就是存儲引擎負責解決的問題,存儲引擎主要功能就是把邏輯的錶行列,用合適的物理存儲結構保存到文件中。不一樣的數據庫,它們的物理存儲結構是徹底不同的,這也是各類數據庫之間巨大性能差距的根本緣由。

在 InnoDB 中,數據表的物理存儲結構是以主鍵爲關鍵字的 B+ 樹,每一行數據直接就保存在 B+ 樹的葉子節點上。好比,上面的訂單表組織成 B+ 樹,是這個樣的:

SQL是如何在數據庫中執行的?

  • 在 InnoDB 中,表的索引也是以 B+ 樹的方式來存儲的,和存儲數據的 B+ 樹的區別是,在索引樹中,葉子節點保存的不是行數據,而是行的主鍵值。
  • 若是經過索引來檢索一條記錄,須要前後查詢索引樹和數據樹這兩棵樹:先在索引樹中檢索到行記錄的主鍵值,而後再用主鍵值去數據樹中去查找這一行數據。

優化後的邏輯執行計劃將會被轉換成物理執行計劃,物理執行計劃是和數據的物理存儲結構相關的。仍是用 InnoDB 來舉例,直接將邏輯執行計劃轉換爲物理執行計劃:

SQL是如何在數據庫中執行的?

物理執行計劃一樣能夠根據數據的物理存儲結構、是否存在索引以及數據多少等各類因素進行優化。這一起的優化規則一樣是很是複雜的,好比,咱們能夠把對用戶樹的全樹掃描再按照主鍵過濾這兩個步驟,優化爲對樹的範圍查找

SQL是如何在數據庫中執行的?

最終,按照優化後的物理執行計劃,一步一步地去執行查找和計算,就能夠獲得 SQL 的查詢結果了。

理解數據庫執行 SQL 的過程,以及不一樣存儲引擎中的數據和索引的物理存儲結構,對於正確使用和優化 SQL 很是有幫助:

  • 爲何主鍵不能太長?

由於表的每一個索引保存的都是主鍵的值,過長的主鍵會致使每個索引都很大。

  • 有的時候明明有索引卻不能命中的緣由是?

數據庫在對物理執行計劃優化的時候,評估發現不走索引,直接全表掃描是更優的選擇。

image

相關文章
相關標籤/搜索