近期二刷了極客時(shí)間的MySQL實(shí)戰(zhàn)45講,對部分知識點(diǎn)進(jìn)行簡單的記錄
檢測delete不刪除磁盤表數(shù)據(jù)
1梯皿,為了方便直接win安裝了mysql工碾;
2渊额,通過SHOW VARIABLES LIKE 'datadir';命令找到數(shù)據(jù)所在文件夾
3旬迹,通過存儲函數(shù)為test庫創(chuàng)建20000條數(shù)據(jù)
CREATE PROCEDURE proc()
BEGIN
declare var int;
set var=0;
while var <= 10000 do
insert into term values(var,'');
set var = var + 1;
end while;
END;
data
4尸疆,此時(shí)執(zhí)行delete語句寿弱,delete from term where 1=1症革;文件大小并沒有發(fā)生改變
5噪矛,重現(xiàn)執(zhí)行步驟三残炮,執(zhí)行truncate語句吉殃,truncate term瓦灶;ibd文件只剩下96KB
因此批量刪除數(shù)據(jù)時(shí)建議用truncate贼陶,不僅釋放磁盤空間烘贴,而且row格式的binlog日志中也是這么一條語句老翘;
缺點(diǎn)铺峭,刪除無法進(jìn)行數(shù)據(jù)恢復(fù);
MDL鎖
用于解決或者保證DDL操作與DML操作之間的一致性;
DML操作需要MDL讀鎖,DDL操作需要MDL寫鎖;
讀寫互斥呢袱,讀讀不互斥;
如圖開啟兩個事務(wù)通過show processlist命令可以看見MDL鎖
MySQL 5.6 版本開始引入的 Online DDL;具體理解就是在更改表結(jié)構(gòu)的時(shí)候可以同時(shí)進(jìn)行DML操作张峰;
那還是否有MDL寫鎖棒旗?
當(dāng)然,只是寫鎖時(shí)間縮短;ALTER語句在啟動的時(shí)候需要獲取 MDL 寫鎖俱两,但是這個寫鎖在真正拷貝數(shù)據(jù)之前就退化成讀鎖了休讳。
死鎖產(chǎn)生與處理
死鎖出現(xiàn)的原因是資源的相互等待(例子來源于mysql實(shí)戰(zhàn)45講第7,21章)
首先表只事務(wù)的隔離級別是可重復(fù)讀(擁有間隙鎖)
CREATE TABLEt
(
id
int(11) NOT NULL,
c
int(11) DEFAULT NULL,
d
int(11) DEFAULT NULL,
PRIMARY KEY (id
),
KEYc
(c
)
) ENGINE=InnoDB;
insert into t values(0,0,0),(5,5,5),
(10,10,10),(15,15,15),(20,20,20),(25,25,25);
Deadlock
當(dāng)執(zhí)行sessionA,B后可發(fā)現(xiàn)出現(xiàn)了死鎖
1纳猫,session A 啟動事務(wù)后執(zhí)行查詢語句加 lock in share mode侵续,在索引 c 上加了 next-key lock(5,10] 和間隙鎖 (10,15)状蜗;
2需五,session B 的 update 語句也要在索引 c 上加 next-key lock(5,10] ,進(jìn)入鎖等待轧坎;
3宏邮,然后 session A 要再插入 (8,8,8) 這一行,被 session B 的間隙鎖鎖住缸血。由于出現(xiàn)了死鎖蜜氨,InnoDB 讓 session B 回滾。
期間還需注意sessionB block了為什么還能添加間隙鎖捎泻?
由于加鎖的步驟是分兩步的飒炎,先是間隙鎖,后是行鎖笆豁。間隙鎖加成功郎汪,而update語句的行鎖被block了
當(dāng)出現(xiàn)死鎖以后,有兩種策略:
一種策略是闯狱,直接進(jìn)入等待煞赢,直到超時(shí)。這個超時(shí)時(shí)間可以通過參數(shù) innodb_lock_wait_timeout來設(shè)置扩氢。
另一種策略是耕驰,發(fā)起死鎖檢測,發(fā)現(xiàn)死鎖后录豺,主動回滾死鎖鏈條中的某一個事務(wù)朦肘,讓其他事 務(wù)得以繼續(xù)執(zhí)行。將參數(shù)innodb_deadlock_detect設(shè)置為on双饥,表示開啟這個邏輯媒抠。
innodb_lock_wait_timeout在InnoDB中,innodb_lock_wait_timeout的默認(rèn)值是50s咏花,意味著如果采用第一個策略趴生,當(dāng)出現(xiàn) 死鎖以后,第一個被鎖住的線程要過50s才會超時(shí)退出昏翰,然后其他線程才有可能繼續(xù)執(zhí)行苍匆。對于 在線服務(wù)來說,這個等待時(shí)間往往是無法接受的棚菊。
但是浸踩,我們又不可能直接把這個時(shí)間設(shè)置成一個很小的值,比如1s统求。這樣當(dāng)出現(xiàn)死鎖的時(shí)候检碗,確 實(shí)很快就可以解開,但如果不是死鎖码邻,而是簡單的鎖等待呢折剃?所以,超時(shí)時(shí)間設(shè)置太短的話像屋,會 出現(xiàn)很多誤傷怕犁。
所以,正常情況下我們還是要采用第二種策略己莺,即:主動死鎖檢測因苹,而且 innodb_deadlock_detect的默認(rèn)值本身就是on。主動死鎖檢測在發(fā)生死鎖的時(shí)候篇恒,是能夠快速發(fā) 現(xiàn)并進(jìn)行處理的扶檐,但是它也是有額外負(fù)擔(dān)的。
每個新來的被堵住的線程胁艰,都要判斷會不會由于自己的加入導(dǎo)致了死鎖款筑,這是一個時(shí)間復(fù)雜度是 O(n)的操作。假設(shè)有1000個并發(fā)線程要同時(shí)更新同一行腾么,那么死鎖檢測操作就是100萬這個量級 的奈梳。雖然最終檢測的結(jié)果是沒有死鎖,但是這期間要消耗大量的CPU資源解虱。因此攘须,你就會看到 CPU利用率很高,但是每秒?yún)s執(zhí)行不了幾個事務(wù)
Deadlock.png