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行進行操作也會被阻塞。對於這種業務沒必要設置為可串行化隔離級別。