深入瞭解MySQL,一篇簡短的總結
MySQL的基本語法
這裡作為MySQL部分模組的深入瞭解,大部分都是理論方面的筆記,不會寫具體用法。
具體用法會記錄在下面這個隨筆分類下,不過暫時還沒更新完,等過段時間會更新下事務、儲存過程、索引等用法,雖然都很簡單,就當做個完整的筆記。
https://www.cnblogs.com/lbhym/category/1493919.html
一個關係型資料庫的基本模組
以下模組也不一定是各大資料庫實際的模組,但是都差不多,只是大概瞭解一下資料庫的架構。
除了硬體,也就是儲存部分,是由磁碟組成,在軟體部分主要分為一下幾個模組:
儲存管理:用於管理資料格式,把物理資料通過邏輯的形式組織表現出來,即資料實際都是存在物理的磁碟當中,需要在軟體層面做一個邏輯上的組織管理。
快取機制:影響資料庫效能的一大問題就是IO,所以會將取出來的資料放入記憶體當中,使用時直接從記憶體返回。即使目前非常快的固態硬碟也遠遠比不上記憶體的速度。
SQL解析:將SQL解析成機器可讀的語言。
日誌管理:記錄使用者對資料庫的操作。
許可權劃分:字面意思,非常常見的一個功能,將不同的使用者分為不同的角色,操作許可權也不同。
容災機制:這個部分較為複雜,大概作用就是當資料庫發生異常災難時該怎麼恢復。
索引管理:優化資料庫查詢效率。
鎖管理:使資料庫支援併發操作。
Mysql索引的實現,B+樹
索引是優化資料庫查詢效率,普通的查詢是全表查詢,當資料量過大時會嚴重影響效能。
而索引就像一本詞典的目錄,在資料量較大時會增加查詢效率,但是如果頻繁的更新或刪除資料,同時也需要去維護索引,反而會降低效能,所以索引不宜太多。
索引實際上也是一個檔案,既然需要高效的查詢當然也需要一個好的資料結構,關於索引的實現,有B樹、二叉查詢樹等,這裡只講MySQL的B+樹。
B+樹的特點和插入刪除過程想過很多文字描述,但是總有點說不清。推薦看看這篇部落格,過程圖文表現的很清楚。
https://blog.csdn.net/login_sonata/article/details/75268075
為什麼會選擇B+樹?
B+樹的一個特點就是其葉子結點均有一個鏈指標指向下一個葉子結點,再加上其是有序的,所以我們進行範圍查詢時,比如查詢>10的資料,只需要先找到10,再直接通過葉子結點的指標就能找到其餘資料。
而其他結構還需從根節點出發接著找。
聯合索引最左匹配原則
聯合索引,有的叫組合索引、有的叫複合索引,叫法無所謂,大概是那個意思就行。
1.一張表裡有欄位A、B,當我們需要查詢where A=‘xxx’ and B='xxx',在這種場景下我們就可以使用聯合索引。
而最左匹配原則就是,當建立索引時,語句如下
alter table TABLENAME add index index_name(A,B)
其中A在左邊,那麼如果我們只查詢A時,會用到這個聯合索引,而只查詢B時,不會用到這個聯合索引。
2.還有種情況,在聯合索引中,mysql會從左往右匹配,直到遇到>、<、between、like就會停止。
比如聯合索引中有四個欄位A,B,C,D。where A=1 and B=2 and C>3 and D=4。其中ABC會用到索引,而D不會。如果在定義索引時交換C,D的位置,ABCD就都會使用索引
alter table TABLENAME add index index_name(A,B,C,D)-->alter table TABLENAME add index index_name(A,B,D,C)
所以最左匹配原則是依據定義索引時的順序,查詢時順序如何不影響(因為mysql查詢優化器會幫我們優化查詢順序)。
最左匹配原則的原理
索引的底層是B+樹,聯合索引也一樣。但是聯合索引特殊的就是有多個值,而構建B+樹只需一個值,mysql選擇最左的那一個欄位當值。
上圖是一個聯合索引下的B+樹,假如欄位分別對應(A,B),可以發現A的值是有序的(1,1,2,2,3,3),B是無序的(1,2,1,4,1,2),所以當我們直接查詢B=2時是無法通過索引找的。
因為這個B+樹是按A的值形成的,B的值完全不符合B+樹特性,所以無法單獨找到B。
那為先找到A後,就能找到B了?
大家仔細觀察這個樹,在A相等的區間內,B是有序的。
還有就是,為什麼遇到範圍查詢就停止了。範圍查詢是針對全表的,而非最左的欄位只是區間內有序。
MySQL兩種引擎:MyISAM和InnoDB
簡短地說
Myisam:是非聚集索引,不支援事務,只支援表級鎖。
InnoDB:是聚集索引,支援事務,預設是行級鎖,支援表級鎖。
下面就這三個方面一一說明。
聚集索引
定義:資料行的物理順序與列值(一般是主鍵的那一列)的邏輯順序相同,一個表中只能擁有一個聚集索引。即索引鍵值的邏輯順序決定了表中相應行的物理順序。
網上有個很好的例子,就是把聚集索引比作一本字典的拼音目錄。而資料就是字典裡面的字。拼音目錄是按照一定順序排列的,那麼字典後面的字也一定是根據拼音的順序排列的。
當我們在拼音B處插入一個新漢字,那麼B後面所有的漢字要向後移動,不可能是加在字典最後面的,因為它得按拼音順序排列。
所以聚集索引適用於:範圍查詢,比如<,>,=,between等,還有分組group by,因為B+樹是有序的,所以分組的效率也更高。
不適用於:頻繁更改的列。
非聚集索引
定義:該索引中索引的邏輯順序與磁碟上行的物理儲存順序不同,一個表中可以擁有多個非聚集索引。
即索引在一個地方,資料在一個地方,索引帶有指向資料的指標。這在物理上也體現出來了,在資料庫目錄下,索引存在.MYI檔案下,資料存在.MYD檔案下。上面的聚集索引,資料和索引在同一個檔案下.ibd。
而資料的順序和索引不一樣,所以聚集索引適用於:頻繁修改索引列。
表級鎖和行級鎖
兩種鎖即字面意思。表級鎖,mysql中最大粒度得到鎖,鎖住整張資料表。行級鎖,mysql中最小粒度的鎖,只鎖住操作的那一行,本表中其他行不鎖。
而針對不同的操作,鎖的具體類別又有所不同,為了不混淆,大家可以把表級鎖和行級鎖當作鎖的範圍。而下面說到的鎖當作具體的分類。
當Myisam查詢時:會在整張表的範圍上加上讀鎖,又叫共享鎖。當加上讀鎖,其他sql的想增刪改時就會被阻塞,必須等待查詢完畢。又叫共享鎖的原因是,可以同時在同一張表內做查詢。
當Myisam增刪改時:會在整張表的範圍上加上寫鎖,又叫排他鎖。當加上寫鎖,其他sql不論是增刪改還是查詢都會被阻塞。又叫排他鎖的原因是,即使我修改的是1-10行資料,你查詢第11行資料也會被阻塞。
上面說的是MyISAM引擎的情況,InnoDB在讀鎖、寫鎖上的邏輯也是一樣的,只是鎖範圍變成了行。
大家在mysql上實驗InnoDB的鎖時:要注意,InnoDB對select進行了優化,並未對select語句加上讀鎖,也就是非阻塞select,大家可以在select語句後面加上lock in share mode手動加上讀鎖。
具體怎麼實驗:1.往表中插入幾百萬條的資料,增刪改查時在範圍內進行,這樣就可以模擬阻塞環境了。2.InnoDB支援事務,不過其是自動提交的,還得用set autocommit=0取消自動提交。這樣在commit之前就是阻塞狀態。
事務
簡單的說,就是使多步操作具有原子性。即在事務內執行多條SQL語句,要麼全部成功,要麼全部不成功,不會存在部分執行成功,而導致資料不一致的情況。
事務具有四大特性:
- 原子性,上面說到的。
- 一致性,事務前後資料的完整性必須保持一致。
- 隔離性,多個使用者事務併發進行時,不能互相干擾。
- 永續性,一旦事務提供,其修改的結果是永久存在的。
重點說說隔離性。如果事務間沒有隔離會發生什麼情況呢。
假如有一個場景:事務A獲取到一個數據為900,此時另外一個事務B在事務A提交之前就修改了資料到800,並提示成功。
而事務A的操作資料依舊是查詢時的900,並進行+100,變成了1000。顯然結果是不對的,這就是更新丟失問題。
這個問題是不是很像多執行緒併發操作,但是沒有鎖時就會發生的問題。實際上,事務的隔離就是用鎖來實現的。
瞭解隔離級別之前需要知道幾個概念:
髒讀:事務A讀取到了事務B還未提交的資料。
不可重複讀:事務A多次查詢資料時,事務B對該資料做了修改並提交,此時事務A發現多次查詢前後結果不一樣。
在我們看來彷彿沒什麼問題,一個事務修改了資料,一個事務查詢到了修改後的結果。但有個問題就是,事務A是多次查詢,如果他沒有多次查詢,直接在第一次查詢的結果上操作,那麼是不是就會出現問題。
幻讀:事務A查詢了一段資料集,事務B修改了事務A的資料集範圍內的某些資料,導致查詢結果和實際結果不一致。
瞭解了這三個概念後就可以很好的理解幾個隔離級別:
隔離級別 | 髒讀 | 不可重複讀 | 幻讀 |
未提交讀(Read uncommitted) | 可能 | 可能 | 可能 |
已提交讀(Reda committed) | 不可能 | 可能 | 可能 |
可重複讀(Repeatable read) | 不可能 | 不可能 | 可能 |
可序列化(Serializable) | 不可能 | 不可能 | 不可能 |
隔離級別越高,安全性越高,效能也越低,所以要根據實際業務設定不同的隔離級別。
舉個例子:如果設定的是可序列化隔離級別,事務A對TableA的1-10行進行操作,事務B即使對TableA的第11行進行操作也會被阻塞。對於這種業務沒必要設定為可序列化隔離級