【推薦】在delete或update後加limit

對於單條記錄的刪除和更新來說,在delete或update後加limit是一個好習慣。其作用等同於select後加limit。若查詢到記錄直接返回,不會繼續查詢。

若是一般的場景中(刪除多條),delete後加limit是否合適?

加鎖是基於索引的,如果delete的where條件沒有索引,就會掃描到主鍵索引上,就算只有一條記錄,也會鎖表。

在where條件上無索引的情況下,delete會鎖整個表的記錄,但是delete後加[limit row_count],則是隻鎖[1-滿足刪除條數所在行]這些行。

此時stu_num字段無索引。

+----+--------------------------------+--------------------+---------+
| id | name                           | address            | stu_num |
+----+--------------------------------+--------------------+---------+
|  3 | 衡水中學                   | 河北省衡水市 |    1000 |
|  4 | 海淀中學                   | 北京市海淀區 |    2000 |
|  5 | 海南中學                   | 海南省          |    2000 |
|  6 | 天津大學附屬第一中學 | 天津市和平區 |    1000 |
|  7 | 北京大學附屬第一中學 | 北京市海淀區 |    1500 |
|  8 | 寧夏中學                   | 寧夏省          |     400 |
| 15 | 內蒙古中學                | 內蒙古省       |     400 |
| 19 | 陝西第一小學             | 陝西省          |    1400 |
| 22 | 陝西第二中學             | 陝西省          |    1400 |
| 23 | 陝西第三中學             | 陝西省          |    1400 |
+----+--------------------------------+--------------------+---------+
10 rows in set (0.00 sec)

A事務:此時滿足條件的主鍵id最大爲15。

mysql> begin;
Query OK, 0 rows affected (0.00 sec)
 
mysql> delete from t_school where stu_num =400 limit 2;
Query OK, 1 row affected (0.00 sec)

B事務查詢:即A事務對1-15行加鎖,可以看到,加鎖查詢id=22時沒有問題,但是加鎖查詢id=5時記錄被鎖了。

mysql> select * from t_school where id =22 for update;
+----+--------------------+-----------+---------+
| id | name               | address   | stu_num |
+----+--------------------+-----------+---------+
| 22 | 陝西第二中學 | 陝西省 |    1400 |
+----+--------------------+-----------+---------+
1 row in set (0.00 sec)
 
mysql> select * from t_school where id =5 for update;
mysql> 2013 - Lost connection to MySQL server during query
mysql> 

當然不推薦delete後的條件沒有索引的情況,極易造成死鎖。

使用limit的語法

  1. delete後面是支持limit關鍵字的,但僅支持單個參數,也就是[limit row_count]。

當需要用到order by排序時,必須order by + limit聯用,否則order by 就會被優化器優化掉,被認爲無意義。

使用limit的好處:

  1. 降低寫錯sql的代價;
  2. 避免長事務,delete多行時會對選中的所有行加鎖;
  3. delete數量大時,不加limit會導致高cpu;

疑問:

如果你要刪除一個表裏面的前 10000 行數據,有以下三種方法可以做到:
第一種,直接執行 delete from T limit 10000;
第二種,在一個連接中循環執行 20 次 delete from T limit 500;
第三種,在 20 個連接中同時執行 delete from T limit 500。


Tony Du:

方案一,事務相對較長,則佔用鎖的時間較長,會導致其他客戶端等待資源時間較長。
方案二,串行化執行,將相對長的事務分成多次相對短的事務,則每次事務佔用鎖的時間相對較短,其他客戶端在等待相應資源的時間也較短。這樣的操作,同時也意味着將資源分片使用(每次執行使用不同片段的資源),可以提高併發性。
方案三,人爲自己製造鎖競爭,加劇併發量。
方案二相對比較好,具體還要結合實際業務場景。


肉山:
不考慮數據表的訪問併發量,單純從這個三個方案來對比的話。

第一個方案,一次佔用的鎖時間較長,可能會導致其他客戶端一直在等待資源。
第二個方案,分成多次佔用鎖,串行執行,不佔有鎖的間隙其他客戶端可以工作,類似於現在多任務操作系統的時間分片調度,大家分片使用資源,不直接影響使用。
第三個方案,自己製造了鎖競爭,加劇併發。
至於選哪一種方案要結合實際場景,綜合考慮各個因素吧,比如表的大小,併發量,業務對此表的依賴程度等。


~嗡嗡:

  1. 直接delete 10000可能使得執行事務時間過長
  2. 效率慢點每次循環都是新的短事務,並且不會鎖同一條記錄,重複執行DELETE知道影響行爲0即可
  3. 效率雖高,但容易鎖住同一條記錄,發生死鎖的可能性比較高

推薦閱讀

delete後加 limit是個好習慣麼

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