Mysql-由淺入深論行鎖

對於mysql innodb的各種鎖,這裏不採用堆文字的講解方式,我們來從現象到本質,先看現象,再來說明其中的道理。

我使用的是mysql 5.5,默認隔離別-可重複讀。

建了一張表,如下圖:
在這裏插入圖片描述

id爲主鍵,student_num上有唯一索引,score分數上有普通索引,nameage沒有索引。

建表語句如下:

CREATE TABLE `student` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `name` varchar(100) NOT NULL,
  `student_num` varchar(100) NOT NULL,
  `age` int(10) NOT NULL COMMENT '年齡',
  `score` int(10) NOT NULL COMMENT '分數',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_stu_num` (`student_num`) USING BTREE,
  KEY `idx_score` (`score`) USING BTREE
) ENGINE=InnoDB

行鎖

現象1
在這裏插入圖片描述
如上圖,左側執行了一條更新語句,但是事物還未提交。
現在,如果執行紅框中的sql,會出現鎖等待,需要等待左側的事物提交,否則,他會等待到超時。
這就是行鎖。

行鎖,鎖的是索引鍵

現象2
在這裏插入圖片描述
如上圖,儘管查詢的不是同一行,但是紅框內sql執行的時候還是會出現鎖等待,原因就是他們使用了相同的索引鍵。innodb在實現行鎖的時候,並不是在記錄行上加的鎖,而是在索引上加的。
如下兩條sql:

update student set score = 60 where id=1;
update student set score = 60 where id=1 and student_num="X001";

由於都使用了id=1的主鍵索引鍵,所以會出現鎖等待。

如果沒有索引,變成表鎖

現象3
在這裏插入圖片描述

age列沒有索引,innodb會直接使用表鎖(表鎖即鎖住所有行)。所以即使查詢的不是相同的列,還是會鎖等待。

即使有索引,也可能變成表鎖

現象4
在這裏插入圖片描述
如上圖,student表中加了一個性別字段sex,並且sex加了一個索引。然後表中一共有4條數據,3男1女,然而當執行紅框中的sql還是會出現鎖等待,why???

另外,如果你將3個男的記錄中的任意兩條刪掉,再做上面的實驗,你會驚喜的發現,不會等鎖了。

原因在於innodb有個優化器,當你的索引區分度不大的時候,他會直接走全表掃描,根本不走索引。
所以上面的例子就是全表掃秒,導致成了表鎖。當你刪除,兩條男的數據之後,sex的區分度又好了,成了行鎖。

優化器不使用索引選擇全表掃描

比如一張order表中有聯合索引(order_id, goods_id),在此例子上來說明這個問題是從兩個方面來說:

查詢字段在索引中 select order_id from order where order_id > 1000,
如果查看其執行計劃的話,發現是用use index condition,走的是索引覆蓋。

查詢字段不在索引中 select * from order where order_id > 1000,
此條語句查詢的是該表所有字段,有一部分字段並未在此聯合索引中,因此走聯合索引查詢會走兩步,首先通過聯合索引確定符合條件的主鍵id,然後利用這些主鍵id再去聚簇索引中去查詢,然後得到所有記錄,利用主鍵id在聚簇索引中查詢記錄的過程是無序的,在磁盤上就變成了離散讀取的操作,假如當讀取的記錄很多時(一般是整個表的20%左右),這個時候優化器會選擇直接使用聚簇索引,也就是掃全表,因爲順序讀取要快於離散讀取,這也就是爲何一般不用區分度不大的字段單獨做索引,注意是單獨因爲利用此字段查出來的數據會很多,有很大概率走全表掃描。
https://www.cnblogs.com/163yun/p/8892324.html

總而言之,加了索引,但是sql執行的時候並沒有走索引,所以就變成了表鎖。

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