版權所有,轉載請注明出處!
本篇博客主要針對有有MySQL使用經驗的讀者。
做技術就要知道技術的實現原理,如果只是停留在一個會用的層面,我覺得不是一個合格的程序員。(你肯定會說,我不要你覺得,我只要我覺得! +_+ ~~~)。
1.MySQL發展史
首先我們先看一下MySQL的發展史,如下表所示:(你們自己看就行了,反正我也是這塊內容從其他地方抄過來的。)
時間 | 里程碑 |
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語句是如何執行的?
首先上個圖,從這個流程示意圖中我們可以看出,當一個客戶端或者是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)連接失效時長
show global variables like 'interactive_timeout'; //查看當前數據庫交互式 (如數據庫工具)連接失效時長
我們可以看出數據庫默認的連接時長是28800秒,即8個小時。
這里順便說一下global和session的區別:global是基於全局的設置,而session是基於當前會話的設置。
那么數據庫應該怎樣查看已經建立的連接?我們可以使用以show status命令進行查看:
show global status like 'Thread%';
Threads_cached: 緩存中的線程連接數。
Threads_connected: 當前打開的連接數。
Threads_created:為處理連接創建的線程數。
Threads_running:非睡眠狀態的連接數,通常指並發連接數。
每產生一個連接或者一個會話,在服務端就會創建一個線程來處理。反過來,如果要殺死會話,就是 Kill 線程。
有了連接數,我們怎么知道每個連接的狀態?可以使用show processlist命令進行查看。
show processlist;
標紅線的地方這里,因為我設置了讀寫分離,所以會多出來兩個連接,這個可以忽略。
為了效果更明顯,我們后面的演示,都用Navicat Premium工具類來進行演示。
一些常見狀態說明,可以參考MySQL官方文檔給出的定義。
我們順便思考一個問題:MySQL中允許最大的連接數是多少?
在5.7的版本之后,默認允許的連接數是151,最大可設置成16384,(2^14)。
因為我裝的數據的版本是5.5版本,所以演示效果不是151,我們可以使用
select version();命令來查詢當前版本號
修改的命令為:
set global max_connections = 1000;
重啟后有效。
2.建立連接之后,首先經過的是MySQL中查詢緩存。
MySQL 內部自帶了一個緩存模塊。
緩存的作用我們應該很清楚了,把數據以 KV 的形式放到內存里面,可以加快數據的讀取速度,也可以減少服務處理的時間。但是為什么我們會對MySQL的緩存比較陌生,甚至沒有聽說過。
因為MySQL的緩存默認是關閉的。可以使用以下語句進行查詢:
默認關閉就是官方不推薦使用,為什么呢?因為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';
執行計划的查看主要用到了 explain這個命令,我們在執行SQL的時候使用這個命令可以查看到sql的執行計划明細,尤其在查看命中索引的時候,這個命令起到很大的作用。
5.存儲引擎
在 MySQL 里面,支持多種存儲引擎,他們是可以替換的,所以叫做插件式的存儲引擎。
我們怎樣查看數據庫的存儲引擎呢?
可以通過執行 show table status from `dbname`;來查看數據庫使用的存儲引擎。
我們還可以通過show engines;命令來查看當前數據庫支持的那些存儲引擎。
我們常用的兩種存儲引擎MyISAM和InnoDB這兩種,而且在MySQL數據庫中只有InnoDB存儲引擎支持事務。
那么存儲引擎是怎樣存儲數據的?
我們可以使用show variables like 'datadir';來查看數據存儲引擎的存放目錄。
任何一個存儲引擎都有一個 frm 文件,這個是表結構定義文件。
不同的存儲引擎存放數據的方式不一樣,產生的文件也不一樣,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 的操作。)
適合:只讀之類的數據分析的項目。