MySQL架構與SQL執行流程(一)


版權所有,轉載請注明出處!

本篇博客主要針對有有MySQL使用經驗的讀者。

做技術就要知道技術的實現原理,如果只是停留在一個會用的層面,我覺得不是一個合格的程序員。(你肯定會說,我不要你覺得,我只要我覺得! +_+  ~~~)。

1.MySQL發展史

首先我們先看一下MySQL的發展史,如下表所示:(你們自己看就行了,反正我也是這塊內容從其他地方抄過來的。Winking smile

時間 里程碑
1996年

MySQL 1.0 發布。它的歷史可以追溯到 1979 年,作者 Monty 用 BASIC 設計 的一個報表工具。

1996年10月

3.11.1 發布。MySQL 沒有 2.x 版本。

2000年

ISAM 升級成 MyISAM 引擎。MySQL 開源。

2003年

MySQL 4.0 發布,集成 InnoDB 存儲引擎。

2005年

MySQL 5.0 版本發布,提供了視圖、存儲過程等功能。

2008年

MySQL AB 公司被 Sun 公司收購,進入 Sun MySQL 時代。

2009 年

Oracle 收購 Sun 公司,進入 Oracle MySQL 時代。

2010年

MySQL 5.5 發布,InnoDB 成為默認的存儲引擎。

2016年

發布 8.0.0 版本。為什么沒有 6、7?5.6 可以當成 6.x,5.7 可以當 成 7.x。

 

常用的版本應該是5.X和現在的8.X,至於8.X的一些新特性,就不做太多的介紹,大家可以自行百度一下。

2.一條查詢SQL語句是如何執行的?

image

首先上個圖,從這個流程示意圖中我們可以看出,當一個客戶端或者是APP向MySQL數據庫發送一條查詢語句的時候(整個過程我們使用問答的形式進行闡述。):

1.首先與MySQL建立連接,連接必然涉及到通信協議,那么MySQL支持哪些協議呢?

在MySQL給出的官方文檔中,有寫到MySQL主要支持的協議有:

①Unix Socket

②TCP/IP

另外還有命名管道(Named Pipes)和內存共享(Share Memory)的方式,這兩種通信方式只能在 Windows 上面使用,一般用得比較少。這里不做過多介紹,因為不是重點。

當連接建立之后,如果長時間不進行操作,MySQL會通過設置的連接斷開時間終止已經建立的連接。

使用以下命令可以查詢MySQL設置的默認連接失效時間:

(因為我使用的是客戶端的博客園所以代碼沒辦法格式化,涉及到代碼部分就用藍色字體表示吧。)

show global variables like 'wait_timeout';  //查看當前數據庫非交互式 (如JDBC)連接失效時長 

    

image

show global variables like 'interactive_timeout'; //查看當前數據庫交互式 (如數據庫工具)連接失效時長 

  image

我們可以看出數據庫默認的連接時長是28800秒,即8個小時。

這里順便說一下global和session的區別:global是基於全局的設置,而session是基於當前會話的設置。

那么數據庫應該怎樣查看已經建立的連接?我們可以使用以show status命令進行查看:

show global status like 'Thread%';

image

Threads_cached: 緩存中的線程連接數。

Threads_connected: 當前打開的連接數。

Threads_created:為處理連接創建的線程數。

Threads_running:非睡眠狀態的連接數,通常指並發連接數。

每產生一個連接或者一個會話,在服務端就會創建一個線程來處理。反過來,如果要殺死會話,就是 Kill 線程。

有了連接數,我們怎么知道每個連接的狀態?可以使用show processlist命令進行查看。

show processlist;

image

標紅線的地方這里,因為我設置了讀寫分離,所以會多出來兩個連接,這個可以忽略。

為了效果更明顯,我們后面的演示,都用Navicat Premium工具類來進行演示。

image

一些常見狀態說明,可以參考MySQL官方文檔給出的定義。

image

我們順便思考一個問題:MySQL中允許最大的連接數是多少?

在5.7的版本之后,默認允許的連接數是151,最大可設置成16384,(2^14)。

因為我裝的數據的版本是5.5版本,所以演示效果不是151,我們可以使用

select version();命令來查詢當前版本號

image

修改的命令為:

set global max_connections = 1000;

重啟后有效。

2.建立連接之后,首先經過的是MySQL中查詢緩存。

MySQL 內部自帶了一個緩存模塊。

緩存的作用我們應該很清楚了,把數據以 KV 的形式放到內存里面,可以加快數據的讀取速度,也可以減少服務處理的時間。但是為什么我們會對MySQL的緩存比較陌生,甚至沒有聽說過。

因為MySQL的緩存默認是關閉的。可以使用以下語句進行查詢:

image

默認關閉就是官方不推薦使用,為什么呢?因為MySQL的緩存對SQL的拼寫相似度要求比較高,比如多一個空格或者少一個空格,查詢緩存都會失敗。我們可以基於ORM框架或者是redis進行數據的緩存。

當然最新的MySQL8已經把查詢緩存這塊內容移除掉了。

3.語法解析和預處理

我們會有一個疑問,為什么我的一條SQL能被識別?加入我隨便執行一個字符串,MySQL去報錯了呢?MySQL是怎樣知道我們輸入的內容是錯的?

這里就涉及到了MySQL的Parser解析器和Preprocessor預處理模塊。

這里主要是對語句進行SQL語法進行詞法和語法分析和語義解析。

這塊內容不做過多講解,因為我對這塊東西也不是特別感興趣,大概就是一個套用正則解析的過程。

詞法分析就是把一個完整的 SQL 語句打碎成一個個的單詞。

第二步就是語法分析,語法分析會對 SQL 做一些語法檢查,比如單引號有沒有閉合,

然后根據 MySQL 定義的語法規則,根據 SQL 語句生成一個數據結構。這個數據結構我

們把它叫做解析樹(select_lex)。

 

解析器可以分析語法,但是它怎么知道數據庫里面有什么表,表里面有什么字段呢?

實際上還是在解析的時候報錯,解析 SQL 的環節里面有個預處理器。

它會檢查生成的解析樹,解決解析器無法解析的語義。比如,它會檢查表和列名是

否存在,檢查名字和別名,保證沒有歧義。

預處理之后得到一個新的解析樹。

4.查詢優化與查詢執行計划

得到解析樹之后,是不是執行 SQL 語句了呢?

這里我們有一個問題,一條 SQL 語句是不是只有一種執行方式?或者說數據庫最終執行的 SQL 是不是就是我們發送的 SQL?

這個答案是否定的。一條 SQL 語句是可以有很多種執行方式的,最終返回相同的結果,他們是等價的。但是如果有這么多種執行方式,這些執行方式怎么得到的?最終選

擇哪一種去執行?根據什么判斷標准去選擇?

這個就是 MySQL 的查詢優化器的模塊(Optimizer)。

查詢優化器的目的就是根據解析樹生成不同的執行計划(Execution Plan),然后選擇一種最優的執行計划,MySQL 里面使用的是基於開銷(cost)的優化器,那種執行計

划開銷最小,就用哪種。

可以使用這個命令查看內存的開銷:

show status like 'Last_query_cost';

1578667041(1)

執行計划的查看主要用到了 explain這個命令,我們在執行SQL的時候使用這個命令可以查看到sql的執行計划明細,尤其在查看命中索引的時候,這個命令起到很大的作用。

5.存儲引擎

在 MySQL 里面,支持多種存儲引擎,他們是可以替換的,所以叫做插件式的存儲引擎。

我們怎樣查看數據庫的存儲引擎呢?

可以通過執行  show table status from `dbname`;來查看數據庫使用的存儲引擎。

image

我們還可以通過show engines;命令來查看當前數據庫支持的那些存儲引擎。

image

我們常用的兩種存儲引擎MyISAM和InnoDB這兩種,而且在MySQL數據庫中只有InnoDB存儲引擎支持事務。

那么存儲引擎是怎樣存儲數據的?

我們可以使用show variables like 'datadir';來查看數據存儲引擎的存放目錄。

image

任何一個存儲引擎都有一個 frm 文件,這個是表結構定義文件。

image

不同的存儲引擎存放數據的方式不一樣,產生的文件也不一樣,innodb 是 1 個, memory 沒有,myisam 是兩個。

MyISAM和InnoDB存儲引擎有什么區別呢?

InnoDB: mysql 5.7 中的默認存儲引擎。InnoDB 是一個事務安全(與 ACID 兼容)的 MySQL存儲引擎,它具有提交、回滾和崩潰恢復功能來保護用戶數據。InnoDB 行級鎖(不升級為更粗粒度的鎖)和 Oracle 風格的一致非鎖讀提高了多用戶並發性和性能。InnoDB 將用戶數據存儲在聚集索引中,以減少基於主鍵的常見查詢的 I/O。為了保持數據完整性,InnoDB 還支持外鍵引用完整性約束。

特點:

支持事務,支持外鍵,因此數據的完整性、一致性更高。

支持行級別的鎖和表級別的鎖。

支持讀寫並發,寫不阻塞讀(MVCC)。

特殊的索引存放方式,可以減少 IO,提升查詢效率。

適合:經常更新的表,存在並發讀寫或者有事務處理的業務系統。

MyISAM:應用范圍比較小。表級鎖定限制了讀/寫的性能,因此在 Web 和數據倉庫配置中,它通常用於只讀或以讀為主的工作。

特點:

支持表級別的鎖(插入和更新會鎖表)。不支持事務。

擁有較高的插入(insert)和查詢(select)速度。

存儲了表的行數(count 速度更快)。

(怎么快速向數據庫插入 100 萬條數據?我們有一種先用 MyISAM 插入數據,然后修改存儲引擎為 InnoDB 的操作。)

適合:只讀之類的數據分析的項目。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM