mysql知識(2)

四、mysql存儲引擎

支持多存儲引擎是mysql的特性,mysql中存儲引擎是針對表的。mysql5.5之後默認的存儲引擎由MyISAM變爲InnoDB。

InnoDB和MyISAM的區別

1.存儲文件:

InnoDB:.frm文件存儲表定義文件,.ibd文件存儲數據和索引文件

MyISAM:.frm文件存儲表定義文件,.myd文件存儲數據文件,.myi存儲索引文件

2.鎖的支持

InnoDB:支持行鎖和表鎖

MyISAM:只支持表鎖

(表鎖實在MySQL Server層實現的)

3.事務支持

InnoDB:支持事務

MyISAM:不支持事務

4.count

InnoDB:掃表計算得到

MyISAM:count值存儲在專門的地方

5.crud

InnoDB:讀寫都很好的支持

MyISAM:適用讀多場景,不適用高併發寫

另外,InnoDB和MyISAM索引結構都是B+tree。

mysql存儲引擎物理結構的文件類型分爲數據文件和日誌文件兩種。

日誌文件

只支持追加寫操作,順序io。

分爲錯誤日誌(error log),二進制日誌(bin log),通用查詢日誌(general query log),慢查詢日誌(slow query log),事務日誌(redo/undo log ,InnoDB),中繼日誌(relay log)

error log: 默認開啓,MySQL5.7之後無法關閉,記錄遇到的嚴重錯誤信息和每次啓動和關閉的詳細信息。默認存儲文件名:hostname.err

bin log: 默認關閉,配置log_bin=mysql_bin開啓,bin log記錄所有DDL和DML語句,不記錄DQL語句,並且只有事務提交了才進行記錄,可以用來做數據恢復。

general query log: 默認關閉,記錄查詢語句,不建議開啓

slow query log: 默認關閉,設置slow_query_log=on開啓,記錄執行時間超過long_query_time秒的查詢語句

redo/undo log:InnoDB特有,文件銘文ib_logfile0和ib_logfile1。默認在表空間所在目錄。還有一個名爲undo的日誌文件在ib_data目錄下

relay log:同步bin log,做主從使用

數據文件

查看數據文件:

SHOW VARIABLES LIKE ‘%datadir%’

InnoDB數據文件

 .frm**文件:主要存放與表相關的數據信息,主要包括表結構的定義信息**

 .ibd**使用獨享表空間存儲表數據和索引**信息,一張表對應一個ibd文件。

 ibdata**文件:使用共享表空間存儲表數據和索引**信息,所有表共同使用一個或者多個ibdata文件。

MyIsam數據文件

 .frm**文件:主要存放與表相關的數據信息,主要包括表結構的定義信息**

 .myd**文件:主要用來存儲表數據信息**

 .myi**文件:主要用來存儲表數據文件中任何索引的數據樹。**

五、MySQL併發控制

事務隔離級別(Transaction Isolation level)

讀未提交(read uncommit):

沒有提交的也能讀取到,一般不會用這個。會存在髒讀,即讀到其他會話未提交的數據,然後該會話回滾了,讀到的就是髒數據。

讀已提交(read commit)

也叫做不可重複讀。只能讀取已提交的數據,存在幻讀,即A會話兩次讀取可能不一致,因爲在A會話的兩次讀取之間可能會有事務提交。

可重複讀(repeatable read)

不會幻讀。在會話中讀取的是會話開始時的快照,每一次讀都一樣,所以不存在幻讀。

串行化(serializable)

退化爲基於鎖的併發控制,讀寫都加表鎖,併發性能最低。

MVCC

基於多版本的併發控制(multi-version concurrency control)

一般在mysql中,通過版本號和時間戳來進行併發控制,讀不加鎖,讀寫不衝突。讀分爲當前讀(current read)和快照讀(snapshot read)

當前讀:讀取最新版本,會加鎖。包括增刪改和一些特殊的select,如

select * from aa for update

select * from aa lock in share mode

快照讀:讀取可見版本(可能時歷史版本),不加鎖。簡單的select都是快照讀

按粒度分爲行級鎖,頁級鎖,表級鎖,全局鎖

按功能分爲共享讀鎖,排他寫鎖

按鎖的實現分爲樂觀鎖,悲觀鎖

全局鎖和表級鎖由mysql server層實現,各存儲引擎可以公用。

全局鎖:鎖整個數據庫。使用場景:數據備份時。

表級鎖:鎖整個表。開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的概率最高,併發度最低;

行級鎖:鎖的時某行,或某些行數據。由存儲引擎層實現,只有InnoDB和 xtradb實現行級鎖。開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的概率最低,併發度也最高;

頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度一般。

表級鎖有兩種,一種時表鎖,一種時元數據鎖(meta data lockMDL)。查看錶級鎖的爭用狀態可用下面的語句:

show status like 'table%'

table_locks_immediate:產生表級鎖定的次數;

table_locks_waited:出現表級鎖定爭用而發生等待的次數;

手動增加表鎖

lock table 表名稱 read/write,表名稱2 read/write,其他

查看錶鎖情況

 show open tables

釋放表鎖

unlock tables

在訪問表時會自動加上MDL鎖,增刪查改都會獲取MDL讀鎖,而DDL語句會獲取MDL寫鎖。讀鎖之間不互斥,因此可以有多個線程同時對一張表增刪改查。讀寫鎖之間、寫鎖之間是互斥的,用來保證變更表結構操作的安全性。因此,如果有兩個線程要同時給一個表加字段,其中一個要等另一個執行完才能開始執行。當sessionA獲取讀鎖,sessionB獲取寫鎖會阻塞,此時sessionC獲取讀鎖也會被阻塞。

行鎖,由存儲引擎層實現。這裏介紹的是InnoDB的行鎖。

InnoDB行鎖按照功能分爲排他鎖(X鎖)和共享鎖(S鎖)

按照鎖定範圍分爲

記錄鎖(Record Locks:鎖定索引中一條記錄。

間隙鎖Gap Locks:要麼鎖住索引記錄中間的值,要麼鎖住第一個索引記錄前面的值或者最後一個索引記錄後面

的值。

Next-Key Locks:是索引記錄上的記錄鎖和在索引記錄之前的間隙鎖的組合。

對於UPDATE、DELETE和INSERT語句,InnoDB會自動給涉及數據集加排他鎖(X);

對於普通SELECT語句,InnoDB不會加任何鎖,事務可以通過以下語句顯示給記錄集加共享鎖或排他鎖。

SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE -- 手動加共享鎖
SELECT * FROM table_name WHERE ... FOR UPDATE --手動加排他鎖

在添加行鎖之前會先添加意向鎖,意向鎖分爲意向共享鎖(IX)意向排他鎖(IS),意向鎖是InnoDB實現的表鎖,且不用用戶自己加鎖,加上意向鎖之後,其他會話就不能獲取表鎖進行表的修改。如果沒有意向鎖,那麼對錶進行修改的時候首先要判斷是不是有表鎖,在判斷每一行是不是有行鎖,這樣效率太低。在加行鎖之前先加意向鎖直接判斷是不是有意向鎖就可以,提升判斷是否可以全表更新的性能。

下面分析當執行下面這條sql語句時的加鎖情況:

delete from tb1 where aaa = 1

情況一:aaa爲主鍵,事務隔離級別爲RC(讀已提交):

會在aaa=1這條記錄的主鍵索引上加X鎖(此時其他會話只能讀取歷史版本)。

情況二:aaa爲唯一索引,事務隔離級別爲RC:

在aaa=1這條唯一索引上加X鎖,然後在aaa=1的索引對應的主鍵索引上加X鎖。

情況三:aaa爲非唯一索引,事務隔離級別爲RC:

在aaa=1的對應的多條索引上加X鎖,然後在這幾條索引對應的主鍵索引上加X鎖。

情況四:aaa上沒有索引,事務隔離級別爲RC:

會進行全表掃描,對每條記錄添加X鎖,加鎖之後如果不符合條件會立刻釋放鎖,如果符合條件就會不會釋放這條主鍵索引上的X鎖。

情況五:aaa爲主鍵,事務隔離級別爲RR(可重複讀):同情況一

情況六:aaa爲唯一索引,事務隔離級別爲RR:同情況二

情況七:aaa爲非唯一索引,事務隔離級別爲RR:

假設有5條數據,aaa分別爲0,1, 1, 2,3,那麼會在aaa爲1的兩條非唯一上加X鎖並在0-1,1-1, 1-2 之間加Gap鎖(間隙鎖),從而保證不能再添加aaa爲1的數據,解決了幻讀。然後在aaa爲1的兩條索引對應的主鍵索引上加X鎖。

情況八:aaa無索引,事務隔離級別爲RR:

類似與情況四,並在主鍵索引之間加間隙鎖。

死鎖可能的情況:

情況1:

session1:delete from tb where id = 1;

session2:delete from tb where id = 2;

session1:delete from tb where id = 2;

session2:delete from tb where id = 1;

session1:commit;

session1:commit;

情況二:

session1:delete from tb where name = aaa;

session2:  delete from tb where age = 10

age和name都是非唯一索引,name=aaa對應id=1和id=2兩條主鍵索引,age=10對應id=2和id=1兩條記錄,session1對id=1加上了X鎖申請對id=2的X鎖,session2對id=2加上了X鎖申請對id=1的X鎖,導致死鎖。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章