成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

慢 SQL 打爆監控!億級數據表的刪除問題

數據庫 其他數據庫
type 由于沒有索引放在 SQL 中是巨大瓶頸,必須得去掉!datachange_lasttime 也可以從 SQL 中拿出來,查出來之后在內存中再做 type 和 datachange_lasttime 的篩選(也就是在 Java 代碼中寫這個邏輯),然后再根據 id 批量刪除。

背景

簡單抽象下業務場景,有一張 MySQL 表用來存儲用戶的操作日志,需要依賴這個日志來做一些業務邏輯的判斷,并且每個用戶可以存在多條日志,所以可想而知,隨著時間的推移,這張表肯定是會越來越大的,必須要做治理。

秉持著最簡原則,我們暫時不考慮分庫分表,數據能刪則刪,因為表中數據其實并不是每一條都有用,梳理了下業務之后,我們最終的治理方向就是:

  1. Job 每個月定時執行一次來刪除數據
  2. 保留近 3 個月的數據,之前的數據可以刪除
  3. 刪除并不是無腦刪除,每條日志有一個對應的類型 type(取值固定,假設是 a、b、c、d、e 吧),當 type = c 的時候該條日志不能刪除(忽略這個奇怪的邏輯,純屬業務需求)

我們可以抽象出這樣一張表就命名為 log 吧,它有如下字段:

  • id(主鍵)
  • type(無索引)
  • datachange_lasttime(時間,有索引)

type 沒有索引并且也不適合做索引。

刪除數據的條件:

  1. datachange_lasttime <= 當前時間 - 3 個月
  2. type != c

以上就是背景,應該比較清楚了

早期方案

首先大表刪除的基本方針一定是批量刪除,即分批查,分批刪。

最基本的方案就是把 datachange_lasttime 和 type 的要求都放在 SQL 中,直接通過 SQL 找到我們要刪的數據:

select id from log
where 
    datachange_lasttime <= '2023-06-17 00:00:00' 
    and type != 'c'
limit #{limit}

查一次就根據 id 批量刪除一次,每次查 limit 條,停止條件就是查不出來數據了

失敗的優化方案

早期方案在數據量級幾千萬的時候還是沒問題的,因為我們這個刪除只需要離線運行,所以用定時 job 跑就可以,對業務基本沒啥影響。

但隨著表越來越大,上億之后,這條 SQL 直接卡住,慢查詢告警猛增,已經沒有辦法正常完成刪除了。

type 由于沒有索引放在 SQL 中是巨大瓶頸,必須得去掉!datachange_lasttime 也可以從 SQL 中拿出來,查出來之后在內存中再做 type 和 datachange_lasttime 的篩選(也就是在 Java 代碼中寫這個邏輯),然后再根據 id 批量刪除。

查詢 SQL 如下:

select id from log
from t_user_pop_log
order by id
limit #{offset}, #{limit}

分頁查詢圖方便我直接用的 MyBatis PageHelper,但是很快我就為此付出代價,就是總是有臟數據沒刪干凈,我們舉個例子分析下:

  1. 假設表中總數據 300 條
  2. 第一次查詢:select * from log limit 0,100; 查出了 100 條數據,但是經過我們 type != c 的過濾后,最終只刪除了 50 條數據,那么表中還剩余 250 條數據
  3. 第二次查詢,表中有 250 條數據,select * from log limit 101,200; 查出了 100 條數據,但是經過我們 type != c 的過濾后,最終只刪除了 60 條數據,那么表中還剩余 190 條數據
  4. 第三次查詢,表中有 190 條數據,select * from log limit 201,300; 這次查詢就出問題了,因為表中只有 190 條數據了,offset = 201 是查不出來數據的,所以這就導致總有一部分數據是沒有經過處理的

想到的解決方案是一直查第一頁(也就是 offset = 0),直到第一頁沒數據,那就停止查詢

但是很明顯這個停止查詢的條件存在問題,如果恰好這一頁的所有數據全都是 “type=c”,也就是這一頁的數據都是不能刪的數據,那么循環就會卡在這一頁,因為這一頁的數據永遠不會發生變化

成功的優化方案

我們看失敗方案,其實可以發現失敗的最根本原因是 MyBatis Pagehelper 的 offset 的計算不對,考慮我們自己做分頁,不用 MyBatis Pagehelper,這樣就改成如下方式來分批查詢:

select *
from t_user_pop_log
where id >= #{startId}
order by id
limit #{limit}

這條 SQL 中只涉及主鍵 id,速度是非常快的:

  1. startId 從 1 開始,一次查詢 limit 條,根據 id 升序查
  2. 對查詢出來的記錄做 type != c & datachange_lasttime <= 當前時間 - 3 個月的篩選,從而篩選出需要刪除的 id
  3. 根據篩選出來的 id 進行批量刪除
  4. 更新下一次查詢的 startId = 本次查詢結果中最大的 id + 1
  5. 停止條件:如果本次查詢結果的第一條記錄的 datachange_lasttime > 當前時間 - 3 個月,后面的數據就不需要刪除了

上述方案很容易想到一個點,那就是 startId 可以不需要每次都從 1 開始。

每個月刪除一次,那其實除了第一次,后續的刪除只需要刪除一個月的數據,只有第一次刪除是需要掃描三個月前的所有數據。舉個例子:

  1. 5.1 執行第一次刪除,保留近三個月即 2.1 之后的數據,2.1 之前的數據要全部掃描并刪除
  2. 6.1 執行第二次刪除,保留近三個月即 3.1 之后的數據,2.1 之前的數據已經被刪除了,所以這次刪除其實只需要刪除 從 2.1 開始到 3.1 這一個月的數據就可以了

那么 startId 的初始取值邏輯就是:

  1. 首次刪除:startId = 1
  2. 非首次刪除:startId = datachange_lastime >=【當前時間 - 3 個月 - 1 個月】的最小 id(還可以給這個時間加一點容錯空間,多掃描幾天的數據也無妨,比如 15 天,startId = datachange_lastime >=【當前時間 - 3 個月 - 1 個月 - 15 天】的最小 id)

以上,在首次刪除的時候,掃描的數據量非常大,可以考慮加一點 sleep,防止 DB 進程被打滿。

責任編輯:武曉燕 來源: 飛天小牛肉
相關推薦

2021-06-29 08:12:22

MySQL數據分頁數據庫

2020-08-20 14:49:22

數據查詢數據庫

2024-08-22 14:16:08

2019-05-27 09:56:00

數據庫高可用架構

2011-03-03 10:32:07

Mongodb億級數據量

2009-09-07 16:13:14

LINQ to SQL

2019-05-28 09:31:05

Elasticsear億級數據ES

2010-09-16 16:06:01

sql server表

2019-03-05 10:16:54

數據分區表SQLserver

2018-04-19 09:10:17

數據分析列式存儲

2021-03-16 07:41:00

數據分頁優化

2021-03-11 10:55:41

MySQL數據庫索引

2025-05-22 00:05:10

2024-02-19 00:06:06

數據分析系統Doris

2010-07-22 10:30:36

SQL Server數

2010-09-01 16:14:21

SQL刪除數據

2022-05-12 14:34:14

京東數據

2024-04-07 00:00:00

億級數據ES

2019-08-28 07:45:45

數據存儲層多線程

2010-07-16 09:06:51

SQL Server數
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久国产欧美一区二区三区精品 | 天堂中文字幕av | 99在线资源| 成人小视频在线观看 | 久草视频在线播放 | 国产精品一区二区不卡 | 国产日韩久久 | 国产在线精品一区二区三区 | 国产中文 | 伦理一区二区 | 色综合99| a级免费观看视频 | 三级视频网站 | 久久久蜜桃一区二区人 | 一区中文字幕 | 羞羞视频在线网站观看 | 羞羞色视频 | 欧美一区二区三区久久精品 | 黄色香蕉视频在线观看 | 综合激情久久 | 日本三级在线 | 欧美美乳 | 精品欧美一区二区精品久久 | 国内自拍视频在线观看 | 欧美日韩精品一区 | 日韩视频―中文字幕 | 麻豆视频国产在线观看 | 亚洲高清一区二区三区 | 国产午夜精品一区二区三区嫩草 | 欧美精品久久久久久久久久 | 久草视频在线播放 | 亚洲中午字幕 | 久久精品欧美一区二区三区麻豆 | 国产美女一区二区 | 欧美区在线 | av日韩高清| 午夜精品一区二区三区在线 | 美女天堂 | 911影院 | 国产精品69毛片高清亚洲 | 亚洲一区日韩 |