資料庫表設計 備份記錄的表設計優化

2021-09-07 12:36:12 字數 4208 閱讀 7515

需求場景:

由於mysql沒有類似於sql server那樣的系統表來存放備份記錄,且大規模的mysql伺服器需要集中管理和檢視。

伺服器出現效能問題或複製延遲時,需要先判斷是否由資料備份引起。

第一版按照需求,考慮到需要記錄的備份資訊有備份伺服器資訊、備份開始結束時間、備份是否成功等訊息,於是設計出第一版表:

create

table

full_backup_log

( id

bigint auto_increment primary

key, ## 自增主鍵,業務無關

host_ip

varchar(50

), ## 備份機ip

host_port

int, ## 備份機埠

backup_type

varchar(50

), ## 備份型別,mysqldump和xtrabackup

start_time

datetime

, ## 備份開始時間

end_time

datetime

, ## 備份結束時間

is_success

int, ## 備份是否成功

backup_message

varchar(5000

), ## 備份訊息

check_time

datetime

##寫入或更新記錄的時間

);

第二版將backup_message弄得比較大, 主要是先把備份過程中的一些資訊寫進去,但仔細想想,該錶不能很好地記錄備份過程中的每一步,將所有資訊放入到backup_message列中不利於檢視,於是新增乙個詳細資訊表:

create

table

full_backup_log_detail

( id

bigint auto_increment primary

key, ## 自增主鍵,業務無關

full_backup_log_id

bigint

, ##關聯full_backup_log表主鍵

host_ip

varchar(50

), ## 備份機ip

host_port

int, ## 備份機埠

backup_type

varchar(50

), ## 備份型別,mysqldump和xtrabackup

backup_message

varchar(5000

), ## 備份訊息

check_time

datetime

##寫入或更新記錄的時間

);

雖然full_backup_log表中存放有備份機和備份型別資料,可以通過full_backup_log_id關聯來獲取到,但是考慮full_backup_log_detail表資料資料日誌性資料,寫入後不會發生變化,因此通過冗餘來減少關聯,僅查詢full_backup_log_detail即可看某台伺服器的備份詳情。

第三版通常dba關心每個資料庫最後一次備份成功時間,而表full_backup_log中存有is_success欄位用來標識備份成功,可以通過以下sql來獲取:

select t1.*

from full_backup_log as

t1inner

join

(select host_ip,host_port,max(id) as max_id from

full_backup_log

where is_success=

1group

byhost_ip,host_port

) as t2 on t1.id=t2.max_id

如果full_backup_log表資料量較大時,比如存放幾千個例項的幾年資料,表中資料幾百萬上千萬時,上面查詢即使有合適索引也不能高效執行。

由於dba並不關心早前資料,可以通過資料結轉來實現,但如果偶爾查詢早前資料則需要當前表和歷史表進行union,程式實現上還得判斷資料是否結轉,於是新增一表來存放最後一次成功備份記錄:

## full_backup_info用來存放備份機最後一次成功備份的記錄

create

table

full_backup_info

( id

bigint auto_increment primary

key, ## 自增主鍵,業務無關

host_ip

varchar(50

), ## 備份機ip

host_port

int, ## 備份機埠

backup_type

varchar(50

), ## 備份型別,mysqldump和xtrabackup

start_time

datetime

, ## 備份開始時間

end_time

datetime

, ## 備份結束時間

backup_message

varchar(5000

), ## 備份訊息

check_time

datetime

##寫入或更新記錄的時間

);

同樣資料容易來減少表關聯,雖然最後一次成功的備份記錄肯定和full_backup_log表中的備份記錄對應,但是因為儲存資料已經全部冗餘,就無需在表full_backup_info中增加欄位與表full_backup_log進行關聯

第四版當備份程序過度使用cpu和io資源導致效能問題並報警後,dba需要第一時間判斷報警伺服器是否處於備份過程中,需要檢視那些伺服器正在進行備份:

方法1:通過full_backup_log表的start_time和end_time來獲取當前正在備份的伺服器,需要對end_time來建索引,如果end_time預設為null,則where end_time is null or end_time >now, 效能很容易因or而受影響,可以考慮給end_time設定乙個預設值如2199-01-01啥的,將查詢改為 where end_time >now

方法2:將full_backup_log表中is_success列擴充套件來標識備份狀態,如果1表示成功0表示失敗-1表示正在備份,查詢條件為where is_success=-1,需要為is_success列建索引,但是is_success列選擇性太低,而mysql又不支援過濾索引,容易生成不高效的執行計畫。

解決辦法:

## full_backup_in_process用來存放正在備份的伺服器資訊

create

table

full_backup_in_process

( id

bigint auto_increment primary

key, ## 自增主鍵,業務無關

host_ip

varchar(50

), ## 備份機ip

host_port

int, ## 備份機埠

backup_type

varchar(50

), ## 備份型別,mysqldump和xtrabackup

start_time

datetime

, ## 備份開始時間

check_time

datetime

##寫入或更新記錄的時間

);

總結:部分研發同事在進行設計時,隨著需求變化不停地修改表,通過在原表上新增欄位來解決新需求,導致表字段過多,同一表處理不同需求,或通過複雜的sql來實現,逼著dba去優化sql或建立一堆的低效索引,且美名其曰「業務需求」。但很多需求其實可以曲線處理,往往優化業務需求和優化實現方式才能最終解決效能問題。

曾經有研發同事讓幫其優化sql,發現其業務需求是對幾千萬資料進行排序分頁然後取top,幾十秒都無法返回結果,建議其去除排序,被告知部分資料需要優先處理,而這部分需要優先處理的資料極少極少,最終解決辦法是將優先處理的資料分拆出來讓單獨的程式進行處理,其他普通資料不排序查詢正常處理,完美解決。

雖然開個拖拉機,可以拉貨,可以耕田,也能代步,家裡沒電還能當個發電機,但是人生不能乙個拖拉機就解決了吧!

依舊是妹子鎮壓帖子!

推女郎艾栗栗,拿走不謝!

資料庫表設計

在軟體的開發中,資料庫表的設計是十分基礎和重要的工作。資料庫表是軟體具體實現的基石,如果表設計的不合規範就會出現資料冗餘,跟業務脫節等問題,等出現問題後再做大的調整相應的依賴表的編碼測試等工作也會進行大的調整這樣就會造成極大的資源消耗。因此在專案一開始設計表的時候就要注意表設計的規範性問題。資料庫 ...

資料庫表設計

什麼是設計三正規化 1.1 設計表的依據 按照這個三正規化設計的表不會出現資料冗餘 三正規化都有哪些 第一正規化 任何一張表都有乙個主鍵,並且每乙個字段原子性不可以再分 例子不滿足第一正規化 學生標號 學生姓名 001jaden zjl 123.com,13029199039 002haoyue w...

資料庫表設計

1 資料型別要合理 1 對於數字和日期型別,一般不要採用 varchar 型別,這個陷阱很容易被接受 1 容易帶來隱式型別轉換,導致索引失效,例如 where a 123 a 是varchar 列,實際儲存數字型別值 2 容易帶來資料質量的下降,例如日期型別 2019 01 23 2019 23 0...