前言
Mysql作為目前互聯網工作的主流數據庫,有著其不容撼動的地位,之前面試過一些公司,對于程序員來說,企業對于Mysql的技能要求還是比較高的。所以有必要系統深入研究下Mysql。于是乎就有了這一系列博客的誕生。這些博客內容主要是結合我自己工作中所用的的東西,以及《高性能Myql》這本書的讀書筆記。
購買地址,請支持正版圖書。
1.1、Mysql邏輯結構
-
Mysql是三層的邏輯架構,如下圖
- 第一層:服務層(為客戶端服務):為請求做連接處理,授權認證,安全等。
- 第二層:Mysql核心服務層:主要提供,查詢解析、分析、優化、緩存以及內置函數,跨存儲引擎功能(存儲過程、視圖、觸發器)
- 第三層:存儲引擎層,負責數據的存儲和提取
1.1.1、連接管理與安全性
這里有第一層處理,每個客戶端的連接都會在服務器進程中擁有一個線程,連接的查詢在這個線程中單獨進行。
1.1.2、優化與執行
此處由第二層,中間層處理,該處的優化器負責創建內部數據結構,然后優化,包括重寫查詢,決定表的讀取順序,以及選擇合適的索引。
1.2、并發控制
并發是個老生常談的問題,不管在java還是mysql以及oracle中,都需要保證并發時數據的一致性。面對并發問題,不可避免的都需要用到鎖,并發的優化很多時候也就是鎖的優化。
1.2.1、讀寫鎖
- 讀鎖:共享,互不阻塞,即多用戶同一時刻讀統一資源,互不干擾。
- 寫鎖:排他,一個寫鎖會阻塞其他的讀和寫,安全策略只有這樣才能保證同一時刻只有一個用戶能寫入,并防止其他用戶讀取正在寫入的同一資源,避免臟讀。
1.2.2、鎖力度
一種優化的策略,對于不同的鎖提供不同的力度,讓鎖定對象更有選擇性。當然加鎖的操作也增加系統的開銷。包括(獲得鎖,檢查鎖是否解除,是否鎖)。下面介紹兩種最重要的鎖力度
- 表鎖(table lock)
顧名思義就是將整張表鎖定,Mysql中最基本的鎖策略,并且是開銷最小的策略,加鎖之后,整個表數據受到影響,不利于并發,寫鎖優先級高于讀鎖,因此一個寫鎖請求可能會被插入到讀鎖的隊列前面。服務器也會使用ALTER TABLE之類的語句使用表鎖。 - 行級鎖(row lock)
支持高并發,同事帶來最大的鎖開銷。只有存儲引擎實現,第二層不會實現。
1.3、事務
事務也是數據庫中一個老生常談的問題,我們常常口頭說的ACID,或者可以說是一個獨立的工作單元,對外只有成功和失敗的結果,不會出現部分成功或者失敗。也即提交(commit)或者回退(rollback)兩種操作。
- A(Atomicity-原子性):不可分割的單元,要么成功,要么失敗。
- C(Consistency-一致性):主要強調的是,如果在執行事務之前數據庫是一致的,那么在執行事務之后數據庫也還是一致的
- I(Isolation-隔離性):事務彼此之間沒有影響,即在最終提交前對其他事務不可見
- D(Durability-持久性):一旦事務提交,其修改會永久保存到數據庫中。
不是所有的數據庫都支持事務,像現在大火的nosql大多都不支持事務,而mysql不同的引擎對事務的支持也不一樣,像默認的InnoDB是支持事務的,而Myisam這一的引擎就不支持事務。這個需要根據業務去做相應的選擇
1.3.1、隔離級別
- 數據庫提供了四種事務隔離級別, 不同的隔離級別采用不同的鎖類開來實現.
隔離級別 | 臟讀可能性 | 不可重復讀可能性 | 幻讀可能性 | 加鎖讀 |
---|---|---|---|---|
READ UNCOMMITTED | YES | YES | YES | NO |
READ COMMITED | NO | YES | YES | NO |
REPEATABLE READ | NO | NO | YES | NO |
SERIALIZABLE | NO | NO | NO | YES |
相關概念
-
臟讀
:事務中的修改,即使未提交,對其他事務也是課件的。事務可以讀取未提交的數據。 -
不可重復讀
:在同一個事務中,再次讀取數據時,所讀取的數據,和第1次讀取的數據,不一樣了 -
幻讀
:幻讀的重點在于新增或者刪除,同樣的條件, 第1次和第2次讀出來的記錄數不一樣。
幻讀是指當一個事務在讀取某個范圍內的數據時,另一個事務在這個范圍內插入了一行記錄并提交,于是當前一個事務再次讀取該范圍內的數據時,發現多出了一行,即幻行。
臟讀、不可重復讀、幻讀的級別高低是:
臟讀 < 不可重復讀 < 幻讀
所以,設置了最高級別的SERIALIZABLE_READ就不用在設置REPEATABLE_READ和READ_COMMITTED了
- READ UNCOMMITTED(未提交讀):數據庫中幾乎不用這種事務。
- READ COMMITED(已提交讀):大多數數據庫的默認隔離級別(MySQL不是)。這個級別代表事務開始后,只能讀到其他事務提交后的修改,未提交的修改是不可見的。顯然這樣就解決了臟讀的問題。但是還是會遇到不可重復讀的問題。
- REPEATABLE READ(可重復讀):Mysql的默認隔離級別,該級別保證了同一個事務中多次讀取同樣記錄的結果是一致的。
- SERIALIZABLE(可序列化讀):最高的隔離級別,通過強制事務串行執行,避免了前面說的幻讀問題。該級別會在讀取的每一行上都加鎖,所以可能導致大量的超時和鎖爭用問題。
1.3.2、死鎖
兩個活多個事務在同一資源上相互占用,并請求鎖定對方占用的資源,從而導致惡性循環的現象。
為解決這種問題,數據庫都是些了各種死鎖檢測和死鎖超時機制。
- 如InnoDB若檢測到死鎖循環依賴,就立即返回一個錯誤。
- 當查詢時間到鎖等待超時的設定后放棄鎖清秋。
InnoDB的處理方式是,將持有最少行級排他鎖的事務進行回滾。
1.4、事務日志
由于事務日志的寫入是順序I/O操作,會比隨機I/O快的多。(因為機械硬盤讀寫最費時間的就是磁頭的定位和移動過程)
當數據持久化到事務日志以后,再慢慢地刷寫回真正的數據庫。即使途中服務器掛了,重啟后還是可以根據事務日志來恢復數據。
1.5、MySQL中的事務
MySQL提供了兩種事務的存儲引擎:InnoDB和NDB cluster。另外還有一些第三方的事務,比較知名的有XtraDB和PBXT。
- 自動提交(AutoCommit):Mysql默認是自動提交模式。如果你不顯式地開始一個事務,那么每次查詢都當做一個事務。
可通過以下方式查詢活修改自動提交模式
SHOW VARIABLES LIKE 'AUTOCOMMIT';
SET AUTOCOMMIT = 0;--1表示啟用,0表示禁用
- 設置隔離級別:可以配置文件中修改整個數據庫的隔離級別,也可以只改變當前會話的隔離
mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
1.6、多版本并發控制(MVCC)
不同的存儲引擎MVCC實現不同,典型的有樂觀并發和悲觀并發控制。下面結合InnoDB說明下。
InnoDB的MVCC,通過在每行記錄后面保存兩個隱藏列實現,這兩個列一個保存行的創建時間,一個保存過期(刪除時間),當然這里存儲的創建時間不是真正的時間,而是系統版本號。
- REPEATABLE READ級別下,MVCC操作如下:
- select :InnoDB只查找版本早于當前事務版本的數據行(即創建版本號《=當前事務版本號),這樣保證事務讀取的行是早于事務開始前就已經存在的。刪除版本號》當前事務版本號,保證事情讀取到的行在事務開始前未被刪除。
- insert:插入新行的時候,將事務分配到的版本號賦給創建版本號那個列屬性。
- delete:為刪除的每一行保存當前系統版本號為行刪除標識,即將該版本號存入刪除版本號的那個列屬性
- update:實際上是新插入一條記錄,然后將事務分配到的版本號賦給舊記錄的刪除版本號列以及新記錄的創建版本號列。
MVCC只在REPEATABLE READ和READ COMMITTED兩個隔離級別下工作。
1.7、MySQL存儲引擎
查詢表相關信息,命令如下
mysql> show table status like 'city' \G
*************************** 1. row ***************************
Name: city //表名
Engine: InnoDB//引擎名
Version: 10
Row_format: Compact//行的格式
Rows: 600//行數,對于InnoDB,該行是估計值,其他引擎為準確值
Avg_row_length: 81//平均每行字節數
Data_length: 49152//表數據大小,byte為單位
Max_data_length: 0//
Index_length: 16384
Data_free: 0
Auto_increment: 601
Create_time: 2017-10-09 19:59:23
Update_time: NULL
Check_time: NULL
Collation: utf8_general_ci
Checksum: NULL
Create_options:
Comment:
1 row in set (0.00 sec)
修改表的引擎采用如下語句:
ALTER TABLE city ENGINE = InnoDB;
下面簡單介紹下相關存儲引擎的優缺點
1.7.1、InnoDB
優點:Mysql當前的默認引擎,事務型引擎,用MVCC支持高并發,通過間隙鎖在REPEATABLE READ級別下就能防止幻讀。支持熱備份。
缺點:非常復雜,性能較一些簡單的引擎要差一點兒。空間占用比較多。
1.7.2、MyISAM:
優點:Mysql 5.1之前版本的默認引擎。全文索引、壓縮、空間函數(GIS)、并發插入、某些場景下性能很好
缺點:非事務型、不支持行鎖、崩潰后數據不容易修復
1.7.3、Archive:
優點:支持高并發插入,解決不可重復讀,針對高速插入和壓縮做了優化的簡單引擎
缺點:只支持查詢和插入操作,非事務型,僅適合日志和數據采集的應用場景
1.7.4、CSV引擎:
優點:有效支持CSV格式文件的導入導出。
缺點:作者沒說
1.7.5、Memory引擎:
優點:用來快速地訪問數據的,比MyISAM快一個數量級。支持Hash索引,因此查詢操作非常快。
缺點:所有數據保存在內存里,重啟只留下表結構。只支持表級鎖,并發能力低下。不支持BLOB或TEXT類型的列。且行長度固定,容易導致內存浪費。
1.7.6、NDB集群引擎:
作者沒有細講,后文會細講的吧,總之就是支持建立集群。
1.7.7、XtraDB和PBXT等OLTP類引擎:
優點:可完全替代InnoDB,或者高度相似。還額外提供了一些性能優化、可測量性、操作靈活性
缺點:第三方的引擎,社區支持的存儲引擎,可能不能保證質量
其實最常用的是InnoDB和MyISAM
- 相關參數對比
特性 | InnoDB | MyISAM | MEMORY | ARCHIVE |
---|---|---|---|---|
存儲限制(Storage limits) | 64TB | No | YES | No |
支持事物(Transactions) | Yes | No | No | No |
鎖機制(Locking granularity) | 行鎖 | 表鎖 | 表鎖 | 行鎖 |
B樹索引(B-tree indexes) | Yes | Yes | Yes | No |
T樹索引(T-tree indexes) | No | No | No | No |
哈希索引(Hash indexes) | Yes | No | Yes | No |
全文索引(Full-text indexes) | Yes | Yes | No | No |
集群索引(Clustered indexes) | Yes | No | No | No |
數據緩存(Data caches) | Yes | No | N/A | No |
索引緩存(Index caches) | Yes | Yes | N/A | No |
數據可壓縮(Compressed data) | Yes | Yes | No | Yes |
加密傳輸(Encrypted data[1]) | Yes | Yes | Yes | Yes |
集群數據庫支持(Cluster databases support) | No | No | No | No |
復制支持(Replication support[2]) | Yes | No | No | Yes |
外鍵支持(Foreign key support) | Yes | No | No | No |
存儲空間消耗(Storage Cost) | 高 | 低 | N/A | 非常低 |
內存消耗(Memory Cost) | 高 | 低 | N/A | 低 |
數據字典更新(Update statistics for data dictionary) | Yes | Yes | Yes | Yes |
備份/時間點恢復(backup/point-in-time recovery[3]) | Yes | Yes | Yes | Yes |
多版本并發控制(Multi-Version Concurrency Control/MVCC) | Yes | No | No | No |
批量數據寫入效率(Bulk insert speed) | 慢 | 快 | 快 | 非常快 |
地理信息數據類型(Geospatial datatype support) | Yes | Yes | No | Yes |
地理信息索引(Geospatial indexing support[4]) | Yes | Yes | No | Yes |
- 在服務器中實現(通過加密功能)。在其他表空間加密數據在MySQL 5.7或更高版本兼容。
- 在服務中實現的,而不是在存儲引擎中實現的。
- 在服務中實現的,而不是在存儲引擎中實現的。
- 地理位置索引,InnoDB支持可mysql5.7.5或更高版本兼容
下一章開始MySQL基準測試,當然前幾章相關的內容會相對少,這些主要是相關的介紹,讓大家大致有個了解。