最近朋友小王正在找工做,而後有一個面試官問他知不知道 「查詢SQL具體的執行流程」 。小王說不知道呀,而後面試官直接對小王說:小夥子 耗子尾汁(好自爲之) ,怎麼連這麼簡單的都不知道呢?html
小王聽後脫口而出:哼!面試官你 不講武德 ,不按套路出牌呀,你應該問問索引相關的知識呀,這個我倍清楚。java
在聽完小王描述後,本身也在腦海中搜了搜這個知識點,可憐的是個人知識庫裏也沒找到相關內容,而後就去面壁思過了,隨後本文就誕生了。
注意 :本文主要以 MySql 爲例;說到了MySql了,而後再嘮叨下如今使用十分廣泛的MySql的姊妹數據庫 MariaDB 。mysql
MySql被Oracle收購後,MySql的創始人擔憂MySql數據庫發展的將來(開發緩慢、封閉、可能會被閉源),因而建立了一個分支MariaDB,默認使用全新的Maria存儲引擎,它是原來Mysql中的 MyISAM 存儲引擎的升級版。面試
①、MySql的總體架構描述;sql
②、Server層各節點描述;數據庫
③、InnoDB存儲引擎描述;apache
咱啥也先不說,先貼上一張摘抄自網上的大圖:
上面這張圖描述的清不清晰呢?不清晰,那彆着急,咱再貼一張:
經過上面的架構圖能夠得知,Server層中主要由 鏈接器、查詢緩存、解析器/分析器、優化器、執行器 幾部分組成的,下面將主要描述下這幾部分。
客戶端想要對數據庫進行操做時,前提是與數據庫創建好鏈接;而鏈接器就是用來負責跟客戶端創建鏈接、獲取權限、維持和管理鏈接的。
MySQL既支持短鏈接,也支持長鏈接。短鏈接就是操做完畢後,立刻close關掉。緩存
長鏈接能夠保持打開,減小服務端建立和釋放鏈接的消耗,後面的程序訪問的時候還可使用這個鏈接。 通常咱們會在鏈接池中使用長鏈接。服務器
客戶端與服務器創建長鏈接,默認有效時間是 8小時 ,超過8小時MySql服務器就會將鏈接斷開了,那麼客戶端再次請求的話,就會報 鏈接已斷開的問題 ;架構
而且保持長鏈接會消耗內存。長時間不活動的鏈接,MySQL服務器會斷開。那這個8小時的超時時間怎麼查看呢?
-- 非交互式超時時間,如 JDBC 程序 show global variables like 'wait_timeout'; -- 交互式超時時間,如數據庫工具 show global variables like' interactive_timeout';
執行後獲得下圖結果:默認都是28800秒,8小時 。
通常項目中使用的鏈接池中的鏈接都是長鏈接的;(例如:druid、c3p0、dbcp等)
某個朋友的公司有個管理系統,這個系統使用的時Mysql,可是他最近遇到了一個問題:就是系統明明前天是好用的,可是次日去到公司後就打不開了,只要將系統重啓就行了,一時間不知道什麼緣由,什麼鬼嘛,苦惱?
最後經過查看日誌才發現是鏈接池中的鏈接都斷開了,由於從前天到次日上班這之間隔得時間超過了8小時了。
唉,這麼個小知識點致使好幾天的困惑,實在不應呀,仍是知識掌握的不全面呀。
好了,如今也找到問題緣由了,可是它該怎麼解決呢?
①、按期斷開長鏈接。使用一段時間,或者程序裏面判斷執行過一個佔用內存的大查詢後,斷開鏈接,以後要查詢再重連。
②、若是你用的是 MySQL 5.7 或更新版本,能夠在每次執行一個比較大的操做後,經過執行 mysql_reset_connection 來從新初始化鏈接資源。這個過程不須要重連和從新作權限驗證,可是會將鏈接恢復到剛剛建立完時的狀態。
MySQL緩存是默認關閉的,也就是說不推薦使用緩存,爲何呢?
主要是因爲它的使用場景限制的:
①、先說下緩存中數據存儲格式:key(sql語句)-value(數據值);因此若是SQL語句(key)只要存在一點不一樣之處就會直接進行數據庫查詢了;
②、因爲表中的數據不是一成不變的,大多數是常常變化的,而當數據庫中的數據變化了,那麼相應的與此表相關的緩存數據就須要移除掉;
須要注意的是, MySQL 8.0 版本直接將查詢緩存的整塊功能刪掉了,也就是說8.0開始完全沒有這個功能了。
分析器的工做主要是對要執行的SQL語句進行解析,最終獲得抽象語法書,而後再使用預處理器判斷抽象語法樹中的表是否存在,若是存在的話,在接着判斷select投影列字段是否在表中存在等。
詞法分析用於將SQL拆解爲不可再分的原子符號,稱爲Token。並根據不一樣數據庫方言所提供的字典,將其歸類爲關鍵字,表達式,字面量和操做符。
語法分析就是根據詞法分析拆解出來的Token(原子符號)將SQL語句轉換爲抽象語法樹。下面就直接舉例說明,看一個SQL它的抽象語法書到底長神魔樣:
SQL語句:
SELECT id, name FROM t_user WHERE status = 'ACTIVE' AND age > 18
而後上面的SQL語句通過詞法分析、語法分析後獲得的抽象語法書以下:
圖片摘自:https://shardingsphere.apache...
注意,爲了便於理解,抽象語法樹中的關鍵字的Token用綠色表示,變量的Token用紅色表示,灰色表示須要進一步拆分。
預處理是用來對生成的 抽象語法樹 進行語義校驗,語義校驗就是對查詢的表、select投影列字段進行校驗,判斷表、字段是否存在等;
優化器的做用:
主要是將SQL通過詞法解析/語法解析後獲得的語法樹,經過MySQL的數據字典和統計信息的內容,通過 一系列運算 ,從而得出一個 執行計劃 。
①、邏輯變換:例如SQL的where條件中存在 8>9,那邏輯轉換就是將語法樹中存在的這種常量表達式直接進行化簡,化簡爲 false;除了化簡還有常量表達式計算等。
②、代價優化:就是經過付出一些數據統計分析的代價,來獲得這個SQL執行是否能夠走索引,以及走哪些索引;除此以外,在多表關聯查詢中,肯定最終表join的順序等;
在分析是否走索引查詢時,是經過進行 動態數據採樣統計分析 出來;只要是統計分析出來的,那就可能會存在分析錯誤的狀況,因此在SQL執行不走索引時,也要考慮到這方面的因素。
在執行的SQL語句前添加上 explain 關鍵字便可;
擴展: Oracle怎麼查看執行計劃? 參考此文章 Oracle經過執行計劃查看查詢語句是否使用索引
MySQL 經過分析器知道了你要作什麼,經過優化器知道了該怎麼作,因而就進入了執行器階段,開始執行語句。
開始執行的時候,要先判斷一下創建鏈接的對象對這個表有沒有執行操做的權限,若是沒有,就會返回沒有權限的錯誤;若是有,就按照生成的執行計劃進行執行。
經過文章最開始的架構圖可知,執行器下面鏈接的就是存儲引擎了,執行器就是經過調用存儲引擎提供的API接口進行調用操做數據的。
存儲引擎是對底層物理數據執行實際操做的組件,爲Server服務器層提供各類操做數據的 API。MySQL 支持插件式的存儲引擎,包括 InnoDB 、MyISAM、Memory 等。通常狀況下,MySQL默認使用的存儲引擎是 InnoDB 。
InnoDB存儲引擎深刻學習,啥也不說了,先貼上其總體架構圖:以下圖所示,InnoDB存儲引擎總體分爲內存架構(Memory Structures)和磁盤架構(Disk Structures)。
若是想深刻學習,請參考此文章 你竟然還不知道Mysql存儲引擎InnoDB分爲內存架構、磁盤架構?
若是本文對您有幫助的話,請揮動下您愛發財的小手點下贊呀,您的支持就是我不斷創做的動力,謝謝!
您能夠VX搜索【木子雷】公衆號,堅持高質量原創java技術文章,值得您關注!