一。Mysql內部整個結構和執行流程
MySQL簡易模塊圖:
簡易圖:1.連接/線程處理:主要負責連接和線程處理、授權認證、安全。
當客戶端連接到mysql服務器時,服務器需要對其進行認證,認證基於用戶名,原始主機信息和密 碼。
2.查詢緩存/解析器:功能有解析,分析,優化,緩存,內置函數。
mysql解析查詢並創建內部數據結構(解析樹),然後對其優化,包括重寫查詢、決定表的讀取順序,以及選 擇合適的索引。優化器會請求存儲引起提供容量或某個具體的開銷信息,以及表數據的統計信息等。
3.存儲引擎:負責Mysql中數據存儲和提取。
數據庫範式
第一範式:字段列不可分,如:【聯繫人】(姓名,性別,電話),一個聯繫人有家庭電話和公司電話,不符合 1NF;
第二範式:有主鍵,非主鍵字段完全依賴主鍵。如:訂單明細表【OrderDetail】(OrderID,ProductID,UnitPrice,Discount,Quantity,ProductName),Discount(折扣),Quantity(數量)完全依賴(取決)於主鍵(OderID,ProductID),而 UnitPrice,ProductName 只依賴於 ProductID,不符合2NF;
第三範式:非主鍵字段不能相互依賴(如:非主鍵列 A 依賴於非主鍵列 B,非主鍵列 B 依賴於主鍵的情況),
每列都與主鍵有直接關係,不存在傳遞依賴。如:訂單表【Order】(OrderID,OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity)主鍵是(OrderID),CustomerName,CustomerAddr,CustomerCity 直接依賴的是 CustomerID(非主鍵列),而不是直接依賴於主鍵,它是通過傳遞才依賴於主鍵,所以不符合 3NF。
1)鎖
處理併發讀或寫時,可以通過實現一個由兩種類型的鎖組成的鎖系統拉埃解決。
也就是共享鎖(shared lock)和排他鎖(exclusive lock),也叫讀鎖 和寫鎖。
讀鎖 :是共享的,多個客戶端在同一時刻可以同時讀取同一個資源,互不干擾。
寫鎖:是排他的只有一個用戶(客戶端)能執行寫入,並防止其他用戶讀取正在寫入的同一資源。
儘量只鎖定修改的部分數據,而不是所有資源,來提供共享資源的
Mysql各存儲引起使用了三種類型(級別)的鎖定機制:行級鎖定,頁級鎖定和表級鎖定
表鎖:與行鎖相反,最大顆粒度鎖定機制,實現邏輯簡單,系統開銷負面影響小,獲取鎖和釋放鎖速度快,會鎖定整張表,一個用 戶在對錶進行寫操作(插入、刪除、更新等)前,需要先獲得寫鎖,會阻塞其他用戶對該表讀寫操作。 讀鎖之間是不 相互阻塞的。
---------》主要使用該鎖的是: MyISAM,Memory,CSV等一些非事務性存儲引擎,
行鎖: 最大特點,鎖定對象顆粒度很小,每次獲取鎖和釋放鎖需要做很多事情,所以開銷消耗比較大,行鎖頁最容易發生死 鎖,在InnoDB和XtraDB,以及其他的一些存儲 引擎中實現了行級鎖。
--------》主要使用該鎖的是:Innodb存儲引擎和NDB存儲引擎,
------>InnoDB的行鎖是基於索引的,也就是如果那個表那一行沒有索引,行鎖是無效的。
頁鎖:特點是鎖定顆粒度介於行級鎖定與表級鎖定之間,會發生死鎖,併發處理能力也介於兩者之間。
----------》主要使用該鎖的是:BerkeleyDB存儲引擎的鎖定方式。
InnoDB的鎖定機制和Oracle有很多相似之處,InnoDB的行級鎖定分爲兩種類型,共享鎖和排他鎖。
InnoDB:使用意向鎖(表級鎖定)的概念,分爲了意向共享鎖和意向排他鎖。
意向鎖的作用就是當一個事務在需要獲取資源鎖定的時候,如果遇到自己需要的資源已經被排他鎖佔用的時候,該事務可以需要鎖定行的表上面添加一個合適的意向鎖。如果需要一個共享鎖,那麼就在表上添加一個意向共享鎖。如果某行添加了排他鎖,那麼就在表上添加一個意向排他鎖。意向共享鎖可以有多個,意向排他鎖只能有一個。
InnoDB鎖定模式分爲:共享鎖,排他鎖,意向共享鎖,意向排他鎖。
Oracle鎖定是通過需要鎖定的某行記錄所在的物理block上的事務槽上表級鎖定信息。
Innodb鎖定是通過在指向數據記錄的第一個索引鍵之前和最後一個索引鍵之後的空域空間上標記鎖定信息而實現的。這種鎖定實現方式稱爲:"NEXT-KEY locking"(間隙鎖)。(如果是通過範圍查詢數據的話,會鎖定整個範圍的所有的索引鍵值)
間隙鎖的致命弱點:當鎖定一個範圍鍵值之後,即使不存在也會被鎖定,而造成在鎖定的時候無法插入鎖定範圍內的任何數據。
在某些場景下有危害,而Innodb給出的解釋是爲了阻止出現幻讀,所以選擇間隙鎖。
通過索引實現鎖定的方式(行鎖)存在的隱患:
1、當Query無法利用索引的時候,Innodb會放棄行鎖而改用表級鎖定,造成併發性能降低。
2、當Query使用索引不包括所有過濾條件的時候,數據檢索使用到的索引鍵所獲取的數據可能有不屬於該Query的結果集的行列,但是也會被鎖定
3、當Query使用索引,定位數據的時候,如果使用的索引鍵一樣,但訪問數據行不同,數據都會被鎖定。
死鎖:如果兩個事務都執行了第一條update語句,更新了一行數據,同時也鎖定了該行數據,接着每個事務都嘗試去執行第二條update語句,卻發現該行已被對方鎖定,然後兩個事務都等待對方釋放鎖,同時又持有對方需要的鎖,則陷入死循環,死鎖。
爲了解決死鎖,數據庫系統實現了各種死鎖檢測和死鎖超時機制。如:InnoDB存儲引擎,檢測到死鎖的循環依賴,並立即返回一個錯誤。InnoDB目前處理死鎖的方法時,將持有最少行級排他鎖的事務進行回滾。
InnoDB檢測到系統中產生死鎖後,InnoDB會通過相應的判斷來選擇較小事務的進行回滾。而讓較大事務的成功順利執行。mysql官方手冊中提到:InnoDB發現死鎖後,會計算出兩個事務各自插入、更新或者刪除的數據量來判斷兩個事務的大小,也就是那個事務鎖改變的記錄條數越多,在死鎖中就不會被回滾。當死鎖涉及不止存儲引擎,InnoDB就沒辦法檢測到死鎖了。
對於非常容易產生死鎖的業務部分,可以嘗試通過表級鎖定來減少死鎖的產生概率。
MyISAM表鎖優化:
1、縮短鎖定時間; 減少複雜的Query(查詢),複雜的Query(查詢)分拆成幾個小的查詢
建立高效的索引,控制字段類型,優化MyISAM文件
2、並行操作:併發插入(Concurrent Insert)功能參數concurrent_insert
3、合理利用讀寫優先級。
Innodb行鎖優化:
1、儘可能讓所有數據檢索都通過索引完成,避免Innodb因爲無法通過索引鍵枷鎖而升級爲表級鎖定,
2、合理設計索引
3、減少基於範圍的數據檢索過濾條件。
4、控制事務大小,減少鎖定的資源量
InnoDB 顯示鎖定 -->
SELECT ...LOCK IN SHARE MODE
SELECT ...FOR UPDATE
這兩個語句不屬於 範式。
2)事務
事務:事務就是一組原子性的SQL查詢,或者說一個獨立的工作單元。
事務的元素 :ACID 表示原子性(Atomicity)、一致性(consistency)、隔離性(isolation)和持久性(durability).
原子性:整個事務中的所有操作要麼全部成功,要不全部失敗,不可能只執行其中的一部分。
一致性:事務開始前和結束後,數據庫的完整性約束沒有被破壞 。比如A向B轉賬,不可能A扣了錢,B卻沒收到。
隔離性:一個事務所做的修改在提交前,對其他事務是不可見的,不同的事務之間彼此沒有任何干擾。比如A正在從一張銀行卡中取錢,在A取錢的過程結束前,B不能向這張卡轉賬。
持久性:事務完成後,事務對數據庫的所有更新將被保存到數據庫,不能回滾。
3)隔離級別
四種隔離級別:
1. READ UNCOMMITTED(未提交讀)
事務中的修改,即使沒有提交,對其他事務也是可見的。 對應--》髒讀
髒讀:事務可以讀取未提交的數據-->這也被稱爲髒讀。
如:事務A讀取了事務B更新的數據,然後B回滾操作,那麼A讀取到的數據是髒數據
2.READ COMMITTED(提交讀)
一個事務開始時,只能“看見”已經提交的事務所做的修改。對應--》不可重複讀
不可重複讀:指在一個事務內,多次讀取同一個數據,在這個事務還沒有結束 ,另一個事務也訪問該同一數據, 但是由於第二個事務的修改,那麼第一個事務兩次讀取的數據可能不一樣。
如:事務 A 多次讀取同一數據,事務 B 在事務A多次讀取的過程中,對數據作了更新並提交,導致事務A 多次讀取同一數據時,結果不一致。
3.REPEATABLE READ(可重複讀)
解決了髒讀,保證在同一事務中多次讀取同樣記錄結果是一樣的。--》出現了幻讀
幻讀 :指的是當某個事務在讀取某個範圍內的記錄時,另外一個事務又在該範圍內插入了新的記錄,當之前的 事務再次讀取該範圍的記錄時,會產生幻行。
InnoDB和XtraDB存儲引擎通過多版本併發控制(MVCC)解決了幻讀的問題。
4.SERIALIZABLE(可串行化)
最高的隔離級別,通過強制事務串行執行,避免了幻讀,讀取每一行的數據上都加鎖,可能導致大量的超時和鎖競爭,實際很少用到。在要求確保數據的強一致性且可以接受沒有併發的情形下才採用。
不可重複讀側重於修改,幻讀側重於新增或刪除。
事務隔離級別 | 髒讀 | 不可重複讀 | 幻讀 |
讀未提交(read-uncommitted) | 是 | 是 | 是 |
不可重複讀(read-committed) | 否 | 是 | 是 |
可重複讀(repeatable-read) | 否 | 否 | 是 |
串行化(serializable) | 否 | 否 | 否 |
4)多版本併發控制 (MVCC ,Multiversion Concurrency Control )
mysql的大多數事務型存儲引起都實現了多版本併發控制(基於併發控制的考慮),
mysql,oracle,PostgreSQL等其他數據庫系統也實現了MVCC.
MVCC 實現由樂觀併發和悲觀併發控制,也就是樂觀鎖和悲觀鎖。
InnoDB的MVCC,是通過在每行記錄後面保存兩個隱藏的列實現的。這兩個列,一個保存了行的創建時間,一個保存行的過期時間(或刪除時間)。存儲的不是實際時間而是系統版本號。每開始一個新的事務,系統版本號都會自動遞增。事務開始時刻的系統版本號會作爲事務的版本號,用來和查詢到的每行記錄的版本號進行比較。
在 可重複讀的隔離級別下,MVCC具體操作。
SELECT :-->InnoDB會根據以下兩個條件檢查每行記錄:
a、InnoDB只查找版本早於當前事務版本的數據行(也就是行的系統版本號小於或等於事務的系統版本號)。
這樣可以確保事務讀取的行,要麼是在事務開始前已經存在的,要麼事務自身插入或者修改過的。
b、行的刪除版本要麼未定義,要麼大於當前事務版本號。這可以確保事務讀取到的行,在事務開始之前未 被刪除。
INSERT :-->InnoDB爲新插入的每一行保存當前系統版本號作爲行版本號。
DELETE:--->爲刪除的每一行保存當前系統版本號作爲行刪除標識。
UPDATE--->InnoDB爲插入一行新記錄,保存當前系統版本號作爲行版本號,同時保存當前系統版本號到原來的行作爲行 刪除標識。
MVCC只在可重複讀和提交讀兩個級別下工作。其他兩個隔離級別和MVCC不兼容。未提交讀總是讀取最新的數據行。
5)存儲引擎
在文件系統中,mysql將每個數據庫(也可以稱爲schema) 保存爲數據目錄下的一個子目錄。
創建表時,mysql會在數據庫子目錄下創建一個和表同名的.frm文件保存表的定義。
如創建一個名爲mytable的表,mysql會在mytable.frm文件中保存該表的定義。
InnoDB : 是Mysql默認的事務型存儲引擎。
InnoDB的數據存儲在表空間(tablespace)中,表空間由一系列的數據文件組成。
InnoDB採用MVCC來支持高併發,實現了四個標準的隔離級別。其默認級別是可重複讀。
通過間隙鎖(next-key locking) 策略防止幻讀的出現。
間隙鎖使得InnoDB不僅鎖定查詢設計的行,還會對索引中的間隙進行鎖定,以防止幻影行的插入。
InnoDB表時基於聚族索引建立的,聚族索引對主鍵查詢有很高的性能,不過它的二級索引(非主鍵索引)中必須 包含主鍵列。所以如果主鍵列很大的話,其他的索引也會很大。如果索引列很大,主鍵列應儘可能小。
MyISAM :在 MySQL5.1及之前的版本,MyISAM是默認的存儲引擎。MyISAM提供了大量的特性,包括全文索引,壓 縮,空間函數(GIS)等。 MyISAM 不支持事務和行級鎖。 缺陷 是崩潰後無法安全恢復。
MyISAM會將表存儲在兩個文件中:數據文件和索引文件,分別以.MYD和.MYI爲擴展名。
MyISAM表可以包含動態或者靜態(長度固定)行。Mysql會根據表的定義來決定採用何種行格式。
MyISAM表可以存儲的行記錄數,一般受限於可用的磁盤空間或者操作系統中單個文件的最大尺寸。
特性: 加鎖與併發-》 MyISAM對整張表加鎖,而不是針對行,讀取的時候會對需要讀到的所有表加共享鎖,寫 入時則對錶加排他鎖。但是在表有讀取查詢的同時,也可以往表中插入新的記錄。
修復-》check TABLE mytable檢查表錯誤,有錯誤通過REPAIR TABLE mytable修復,工具修復 myisamchk工具。
Archive引擎:只支持INSERT 和SELECT操作 ,支持行級鎖和專用的 緩衝區。可以實現高併發的插入。
Blackhole引擎:沒有實現任何存儲機制,會丟失所有插入數據,不保存,會記錄Blackhole日誌。
CSV引擎:將普通的CSV文件作爲mysql的表來處理,不支持索引。
Federated引擎:返回其他mysql服務器的一個代理,會創建一個到遠程mysql服務器的客服端連接,並將查詢傳輸到遠程服務器執行,然後提取或者發送需要的數據。
Memery引擎:比MyISAM表要快一個數量級,所有數據都保存在內存中,不需要進行磁盤I/O.Memory表的結構在重啓之後會保留,但數據會丟失。Memery表用於查找或者映射表(郵編),用於保存數據分析產生的中間數據,支持hash索引,是表級鎖,併發性能低。
Merge引擎:是MyISAM的一個變種,Merge表是由多個MyISAM表合併而來的虛擬表。
NDB集羣引擎:mysql服務器,ndb集羣存儲引擎,以及分佈式,share-nothing,容災的,高可用的ndb數據庫的組合稱爲Mysql集羣。
6)優化數據類型
儘量選擇最小的數據類型,佔用更少的內存,磁盤和cpu資源,
整型比字符操作代價更低,因爲字符集和校對規則使字符比整型更加複雜。
儘量避免null,通常情況下最好指定列爲NOT NULL,可爲null的列會使用更多的存儲空間,爲NULL的列使得索引、索引統計和值都比較複雜,當可爲NULL的列被索引時,每個索引記錄需要一個額外的字節,在MYISAM裏可能導致固定大小的索引變成可變大小的索引。通常把 可爲NULL的列改爲NOT NULL帶來的性能提升比較小。除非確實會導致問題纔去改。