1. 程式人生 > >深入瞭解MySQL,一篇簡短的總結

深入瞭解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行進行操作也會被阻塞。對於這種業務沒必要設定為可序列化隔離級