對於單條記錄的刪除和更新來說,在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的語法
- delete後面是支持limit關鍵字的,但僅支持單個參數,也就是[limit row_count]。
當需要用到order by排序時,必須order by + limit聯用,否則order by 就會被優化器優化掉,被認爲無意義。
使用limit的好處:
- 降低寫錯sql的代價;
- 避免長事務,delete多行時會對選中的所有行加鎖;
- delete數量大時,不加limit會導致高cpu;
疑問:
如果你要刪除一個表裏面的前 10000 行數據,有以下三種方法可以做到:
第一種,直接執行 delete from T limit 10000;
第二種,在一個連接中循環執行 20 次 delete from T limit 500;
第三種,在 20 個連接中同時執行 delete from T limit 500。
Tony Du:
方案一,事務相對較長,則佔用鎖的時間較長,會導致其他客戶端等待資源時間較長。
方案二,串行化執行,將相對長的事務分成多次相對短的事務,則每次事務佔用鎖的時間相對較短,其他客戶端在等待相應資源的時間也較短。這樣的操作,同時也意味着將資源分片使用(每次執行使用不同片段的資源),可以提高併發性。
方案三,人爲自己製造鎖競爭,加劇併發量。
方案二相對比較好,具體還要結合實際業務場景。
肉山:
不考慮數據表的訪問併發量,單純從這個三個方案來對比的話。
第一個方案,一次佔用的鎖時間較長,可能會導致其他客戶端一直在等待資源。
第二個方案,分成多次佔用鎖,串行執行,不佔有鎖的間隙其他客戶端可以工作,類似於現在多任務操作系統的時間分片調度,大家分片使用資源,不直接影響使用。
第三個方案,自己製造了鎖競爭,加劇併發。
至於選哪一種方案要結合實際場景,綜合考慮各個因素吧,比如表的大小,併發量,業務對此表的依賴程度等。
~嗡嗡:
- 直接delete 10000可能使得執行事務時間過長
- 效率慢點每次循環都是新的短事務,並且不會鎖同一條記錄,重複執行DELETE知道影響行爲0即可
- 效率雖高,但容易鎖住同一條記錄,發生死鎖的可能性比較高