(大表小技巧)有時候 2 小時的 SQL 操作,可能只要 1 分鐘
來源:yes的練級攻略
大家好,我是yes。
上篇文章 關於一張 5 億資料表之我與 DBA 的 battle 發了之後,有好幾個小夥伴來問我 SQL 是怎麼拆的。
這篇我們來簡單盤下,其實拆 SQL 是因為涉及大表刪除的問題。
比如,你現在需要刪除一張一共有 5 億資料的表裡面的 2021 年資料,假設這張表叫 yes。
我相信你腦子在 1s 內肯定會蹦出這條 SQL :
delete from yes where create_date > "2020-12-31" and create_date < "2022-01-01";
如果直接執行這條 SQL 會發生什麼問題呢?
長事務
我們需要關注到一個前提:這張表有 5 億的資料,所以它是一張超大表,因此這個 where 條件可能涉及非常多的資料,所以我們可以從離線數倉或者備庫查下資料量,然後我們發現這條 SQL 會刪除 3 億左右的資料。
那麼一次性 delete 完的方案是不行的,因為這會涉及到長事務的問題。
長事務涉及到加鎖,只會在事務執行完畢後才會釋放鎖,由於長事務鎖了很多資料,如果期間有頻繁的 DML 想要操作這些資料,那麼就會造成阻塞。
連線都阻塞住了,業務執行緒自然就阻塞了,也就是說你的服務執行緒都在等待資料庫的響應,然後可能還會影響到別的服務,可能產生雪崩,於是就 GG 了。
長事務可能會造成主從延遲,你想想主庫執行了好久,才執行完給從庫,從庫又要重放好久,期間可能有很長一段時間資料是不同步的。
還有一種情況,業務都有個特殊停機視窗,你覺得你可以為所欲為,然後開始執行長事務了,然後執行了 5 小時之後,不知道啥情況拋錯了,事務回滾了,於是浪費了 5 個小時,還得重新開始。
綜上,我們需要避免長事務的發生。
那面對可能發生長事務的 SQL 我們怎麼拆呢?
拆 SQL
我們就以上面這條 SQL 為例:
delete from yes where create_date > "2020-12-31" and create_date < "2022-01-01";
看到這條 SQL,如果要拆分,想必很多小夥伴會覺得很簡單,按日期拆不就完事了?
delete from yes where create_date > "2020-12-31" and create_date < "2021-02-01";
delete from yes where create_date >= "2021-02-01" and create_date < "2021-03-01";
......
這當然可以,恭喜你,你已經拆分成功了,沒錯就這麼簡單。
但是,如果 create_date 沒有索引怎麼辦?
沒索引的話,上面這就全表掃描了啊?
影響不大,沒有索引我們就給他創造索引條件,這個條件就是主鍵。
我們直接一個 select min(id)... 和 select max(id).... 得到這張表的主鍵最小值和最大值,假設答案是233333333 和 666666666。
然後我們就可以開始操作了:
delete from yes where (id >= 233333333 and id < 233433333) and create_date > "2020-12-31" and create_date < "2022-01-01";
delete from yes where (id >= 233433333 and id <233533333) and create_date > "2020-12-31" and create_date < "2022-01-01";
......
delete from yes where (id >= 666566666 and id <=666666666) and create_date > "2020-12-31" and create_date < "2022-01-01";
當然你也可以再精確些,透過日期篩選來得到 maxId,這影響不大(不滿足條件的 SQL 執行很快,不會耗費很多時間)。
這樣一來 SQL 就滿足了分批的操作,且用得上索引。
如果哪條語句執行出錯,只會回滾小部分資料,我們重新排查下就好了,影響不大。
而且拆分 SQL 之後還可以並行提高執行效率。
當然我之前的文章說過,並行可能有鎖競爭的情況,導致個別語句等待超時。不過影響不大,只要機器狀態好,執行的快,因為鎖競爭導致的等待並不一定會超時,如果個別 SQL 超時的話,重新執行就好了。
有時候要轉換思路
關於大表刪除有時候要轉換思路,把刪除轉成插入。
假設還是有一張 5 億的資料表,此時你需要刪除裡面 4.8 億的資料,那這時候就不要想著刪除了,要想著插入。
道理很簡單,刪除 4.8 億的資料,不如把要的 2000W 插入到新表中,我們後面業務直接用新表就好了。
這兩個資料量對比,時間效率差異不言而喻了吧?
具體操作也簡單:
建立一張新表,名為 yes_temp 將 yes 表的 2000W 資料 select into 到 yes_temp 中 將 yes 表 rename 成 yes_233 將 yes_temp 表 rename 成 yes
狸貓換太子,大功告成啦!
之前有個記錄表我們就是這樣操作的,就 select into 近一個月的資料到新表中,以前老資料就不管了,然後 rename 一下,執行的非常快。
本來預估 2 小時的 SQL 操作,1 分鐘就搞定了。
這種類似的操作是有工具的,比如 pt-online-schema-change 等,不過我沒用過,有興趣的小夥伴可以自己去看看,道理是一樣的,多了幾個觸發器,這裡不多贅述了。
最後
我們們開發還是得多學一些資料庫的操作和原理,因為好多資料庫的操作都需要你親力親為,小公司沒 DBA 的話就不說了,大公司的話我們也不知道 DBA 到底會關心到哪個程度,還是得靠自己靠譜。
我翻了翻我之前的文章,好像 MySQL 相關寫的是最多的,有興趣的可以看下這個合集:MySQL合集
不過應該有挺多沒加到這個合集的,有空我再整理整理。
最近打算換工作的可以瞭解下我的這個服務:簡歷指導和模擬面試,已經幫助幾個小夥伴拿到大廠的 offer 了。
我是yes,從一點點到億點點我們下篇見~
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70027826/viewspace-2992447/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- index有時候可能會比表大!Index
- 改寫一個要跑5小時的SQL成1分鐘SQL
- 5個平時容易讓人忽略的Excel技巧,10分鐘幫你搞定2小時的工作Excel
- 5個不起眼的Excel小技巧,只需3分鐘幫你完成以往2小時的工作量!Excel
- 體驗有獎 | 1 分鐘 Serverless 部署掌上游戲機,“一行命令”找回小時候的樂趣!Server
- js年月日小時分鐘秒動態時鐘效果JS
- crontab 每隔 1 小時 2 小時的執行 job 寫法
- JavaScript 天小時分鐘和秒倒數計時JavaScript
- javascript小時、分鐘和秒倒數計時效果JavaScript
- 如何1小時快速上手SQL?SQL
- 5分鐘掌握JavaScript小技巧JavaScript
- 小時候的螢火蟲
- 開發5分鐘,除錯2小時 - 該如何debug?除錯
- Qt時鐘介面、數字時鐘(12小時制24小時制切換、修改系統時間)QT
- 3分鐘上手,2小時起飛!教你玩轉OceanBase CloudCloud
- 1 小時 SQL 極速入門(三)SQL
- 1 小時 SQL 極速入門(一)SQL
- 1 小時 SQL 極速入門(二)SQL
- 巧用Excel的6個實用技巧,10分鐘完成別人3個小時的工作Excel
- 原生js實現的天小時分鐘和秒倒數計時效果JS
- 遊戲5分鐘,上頭2小時!畫風可愛的音樂遊戲《Like A Giraffe!》遊戲
- 3分鐘短文:無私分享!Laravel模型使用2個小技巧Laravel模型
- ORACLE計算2個時間段相差時間小時、分、秒Oracle
- iOS 獲取當前的年、月、日、小時、分鐘、秒iOS
- 不定時更新-工具類小技巧
- 年月日小時分鐘秒倒數計時效果程式碼例項
- php擷取小時和分鐘,在進行和其它時間段的比較PHP
- Pbootcms將日期時間轉換成"剛剛、幾分鐘、幾小時前"的形式boot
- JS自動生成24小時時間區間,時間跨度為60或30分鐘JS
- 按小時,分鐘,秒;統計之 round和trunc區別
- JavaScript 原生 小案例 秒殺時鐘倒數計時JavaScript
- 5個看分時圖買股票的小技巧 簡單實用
- 在升級的時候使用VNC的小竅門VNC
- 手機小技巧:小米手機時間24小時制怎麼設定
- 親愛的老闆:程式設計師的10分鐘就是3個小時程式設計師
- 10分鐘幹完2小時的活,用Python自動化辦公能有多爽?Python
- 調優: 一個SQL現在30分鐘,而原來只要2秒SQL
- postgresql 按小時分表(含觸發器)的實現方式SQL觸發器