CTO說了,delete後不加limit,直接滾蛋!
在業務場景要求高的資料庫中,對於單條刪除和更新操作,在 delete 和 update 後面加 limit 1 絕對是個好習慣。
比如,在刪除執行中,第一條就命中了刪除行,如果 SQL 中有 limit 1;這時就 return 了,否則還會執行完全表掃描才 return。效率不言而喻。
那麼,在日常執行 delete 時,我們是否需要養成加 limit 的習慣呢?是不是一個好習慣呢?
在日常的 SQL 編寫中,你寫 delete 語句時是否用到過以下 SQL?
delete from t where sex = 1 limit 100;
你或許沒有用過,在一般場景下,我們對 delete 後是否需要加 limit 的問題很陌生,也不知有多大區別,今天帶你來了解一下,記得 mark!
寫在前面,如果是清空表資料建議直接用 truncate,效率上 truncate 遠高於 delete,因為 truncate 不走事務,不會鎖表,也不會生產大量日誌寫入日誌檔案。
truncate table table_name 後立刻釋放磁碟空間,並重置 auto_increment 的值。delete 刪除不釋放磁碟空間,但後續 insert 會覆蓋在之前刪除的資料上。
下面只討論 delete 場景,首先,delete 後面是支援 limit 關鍵字的,但僅支援單個引數,也就是 [limit row_count],用於告知伺服器在控制命令被返回到客戶端前被刪除的行的最大值。
delete limit 語法如下:
delete [low_priority] [quick] [ignore] from tbl_name
[where ...]
[order by ...]
[limit row_count]
值得注意的是,order by 必須要和 limit 聯用,否則就會被優化掉。
加 limit 的的優點
delete from t where sex = 1;
以上面的這條 SQL 為例:
- 降低寫錯 SQL 的代價,就算刪錯了,比如 limit 500,那也就丟了 500 條資料,並不致命,通過 binlog
也可以很快恢復資料。 - 避免了長事務,delete 執行時 MySQL 會將所有涉及的行加寫鎖和 Gap 鎖(間隙鎖),所有 DML
語句執行相關行會被鎖住,如果刪除數量大,會直接影響相關業務無法使用。 - delete 資料量大時,不加 limit 容易把 CPU 打滿,導致越刪越慢。
針對上述第二點,前提是 sex 上加了索引。大家都知道,加鎖都是基於索引的,如果 sex 欄位沒索引,就會掃描到主鍵索引上,那麼就算 sex=1 的只有一條記錄,也會鎖表。
對於 delete limit 的使用,MySQL 大佬丁奇有一道題:
如果你要刪除一個表裡面的前 10000 行資料,有以下三種方法可以做到:
第一種,直接執行 delete from T limit 10000;
第二種,在一個連線中迴圈執行 20 次 delete from T limit 500;
第三種,在 20 個連線中同時執行 delete from T limit 500。
你先考慮一下,再看看幾位老鐵的回答:
回答一
方案一,事務相對較長,則佔用鎖的時間較長,會導致其他客戶端等待資源時間較長。
方案二,序列化執行,將相對長的事務分成多次相對短的事務,則每次事務佔用鎖的時間相對較短,其他客戶端在等待相應資源的時間也較短。
這樣的操作,同時也意味著將資源分片使用(每次執行使用不同片段的資源),可以提高併發性。方案三,人為自己製造鎖競爭,加劇併發量。
方案二相對比較好,具體還要結合實際業務場景。
回答二
不考慮資料表的訪問併發量,單純從這個三個方案來對比的話。
第一個方案,一次佔用的鎖時間較長,可能會導致其他客戶端一直在等待資源。第二個方案,分成多次佔用鎖,序列執行,不佔有鎖的間隙其他客戶端可以工作,類似於現在多工作業系統的時間分片排程,大家分片使用資源,不直接影響使用。第三個方案,自己製造了鎖競爭,加劇併發。
至於選哪一種方案要結合實際場景,綜合考慮各個因素吧,比如表的大小,併發量,業務對此表的依賴程度等。
回答三
①直接 delete 10000 可能使得執行事務時間過長。
②效率慢點每次迴圈都是新的短事務,並且不會鎖同一條記錄,重複執行 DELETE 知道影響行為 0 即可。
③效率雖高,但容易鎖住同一條記錄,發生死鎖的可能性比較高。
怎麼刪除表的前 10000 行。比較多的朋友都選擇了第二種方式,即:在一個連線中迴圈執行 20 次 delete from T limit 500。
確實是這樣的,第二種方式是相對較好的。
第一種方式(即:直接執行 delete from T limit 10000)裡面,單個語句佔用時間長,鎖的時間也比較長;而且大事務還會導致主從延遲。
第三種方式(即:在 20 個連線中同時執行 delete from T limit 500),會人為造成鎖衝突。
這個例子對我們實踐的指導意義就是,在刪除資料的時候儘量加 limit。這樣不僅可以控制刪除資料的條數,讓操作更安全,還可以減小加鎖的範圍。
所以,在 delete 後加 limit 是個值得養成的好習慣。
最後
感謝大家看到這裡,文章有不足,歡迎大家指出;如果你覺得寫得不錯,那就給我一個贊吧。
也歡迎大家關注我的公眾號:程式設計師麥冬,麥冬每天都會分享java相關技術文章或行業資訊,歡迎大家關注和轉發文章!
相關文章
- 老闆說了,線上再出現慢查詢,開發就滾蛋!
- 滾蛋吧,正規表示式!
- Flask-Limit使用詳細說明FlaskMIT
- 未使用 `deleteLater` 而直接使用 `delete` 導致問題delete
- 說到猝死,遊戲公司可以不加班嗎?遊戲
- 我終於知道公司前端為啥不加班了…前端
- 餓了麼CTO張雪峰:允許90後的技術人員“浮躁“一點
- DateUtils(話不多說直接上程式碼)
- 說服您的CTO使用事件溯源 -Event Store Blog事件
- 開發了幾個小程式後,說說我對小程式的看法
- gitlab上程式碼回滾把自己坑了後, 陷入思考?"bug是誰"?Gitlab
- 【UNDO】Oracle系統回滾段說明Oracle
- MySQL:關於排序order by limit值不穩定的說明(1)MySql排序MIT
- 真的加量不加價嗎?RTX SUPER都升級了什麼
- 領導:誰再用redis過期監聽實現關閉訂單,立馬滾蛋!Redis
- JS 中函式名後面加與不加括號的區別JS函式
- 面試官讓說出8種建立執行緒的方式,我只說了4種,然後掛了。。。面試執行緒
- 我後悔了,真的永遠不要在生產中直接執行Node.jsNode.js
- linux limit限制LinuxMIT
- 極限limitMIT
- Sqlserver update\delete用inner join關聯,會update\delete關鍵字後面的表關聯到的行SQLServerdelete
- 35歲老程式設計師因身體原因沒加班,老闆:不想幹就滾蛋程式設計師
- HelloGitHub 小程式上線了,蛋只有一個搜尋功能Github
- JavaScript deleteJavaScriptdelete
- URLSearchParams delete()delete
- FormData delete()ORMdelete
- 用gpt直接寫後端的感覺GPT後端
- [解決] Goland 開啟後直接崩潰GoLand
- set_time_limitMIT
- Mysql LIMIT的用法MySqlMIT
- 說說 VARCHAR 背後的那些事
- 報告老闆:中臺專案成功了,CTO也被搞走了
- Map delete() 方法delete
- WeakMap delete() 方法delete
- WeakSet delete() 方法delete
- SQL__DELETESQLdelete
- Set delete() 方法delete
- JavaScript delete用法JavaScriptdelete