sql新增自增id 一次資料落地的sql設計

2021-10-14 07:33:47 字數 4067 閱讀 3877

本文是最近公司有一項很簡單的需求,只是為了方便日常的bi統計資料,以及日常的問題排查,將一些資料落地到sql中(有些冗餘)。

我先講一下大背景,首先是業務中需要客戶做一些資訊的填寫和認證,對於未完成的專案(暫且叫做item吧),在前端頁面中顯示,但是這些底層的資料卻是依賴於集團的另乙個子公司的服務,所以我們專案中的資料並不是實時的,對於查詢的時候發現是未完成的需要請求子公司的服務,而這對於bi來說,統計使用者到底完成了那些資訊的登記,是乙個很不方便的事情,於是就有了這樣乙個需求,那就是每次去查詢後把已經完成的項落地到我們的資料庫中,顯然這樣資料有一定的冗餘。但是為了方便我們的查詢。設計後的查詢架構如下:

當然,拿到這樣的乙個需求,其實很簡單,就是建乙個資料表,在查詢的時候將需要寫入的資料落地。但是這卻有不同的設計方式。

因為需求就是客戶的某些資訊是否完整,資料庫只需記錄對應使用者的對應的資訊是否存在,首先想到的最原始的版本,資料庫設計如下:

create table user_info ( id bigint auto_increment comment '自增主鍵', info_no varchar(50) not null comment '記錄編號', user_no varchar(50) not null comment '使用者編號', info_1 tinyint not null default 0 comment '使用者狀態1資訊, 0不完善,1完善', info_2 tinyint not null default 0 comment '使用者狀態2資訊, 0不完善,1完善', info_3 tinyint not null default 0 comment '使用者狀態3資訊, 0不完善,1完善', info_4 tinyint not null default 0 comment '使用者狀態4資訊, 0不完善,1完善', remark varchar(200) comment '備註資訊', create_time datetime comment '建立時間', update_time datetime comment '更新時間', primary key (`id`), unique key uniq_info(`info_no`), key idx_user(`user_no`))engine=innodb
而儲存的資料根式如下圖:

很顯然,這種設計方案的擴充套件性非常的差,當我們需要吸收使用者的其他資訊的時候,就需要更新資料表的結構,增加`info_5`字段,每次需要新增資訊的時候都需要修改資料表結構,除了修改資料表的結構外,這中間有兩個比較讓筆者不喜歡的地方:

綜上, 對於這種設計還是有很大的需要優化空間。

首先宣告,沒有鄙視同事的意思,同事大概也是沒想太多,認為功能很簡單。

同事拿到需求後直接就開始問我都有哪些資訊需要儲存,每個客戶需要儲存多少,這樣他要設計資料**中字段的最大長度,一聽我很鬱悶,就問他是打算怎麼設計的,大概是這樣設計的表:

create table user_info ( id bigint auto_increment comment '自增主鍵', info_no varchar(50) not null comment '記錄編號', user_no varchar(50) not null comment '使用者編號', value varchar(2000) not null comment '使用者狀態資訊', remark varchar(200) comment '備註資訊', create_time datetime comment '建立時間', update_time datetime comment '更新時間', primary key (`id`), unique key uniq_info(`info_no`), key idx_user(`user_no`))engine=innodb
同事的方案解決了原始版方案新增使用者資料字段的弊端,將info_ns以json字串的格式儲存在value欄位中。儲存的資料格式如下圖:

這種方案在新增資訊型別的時候,不用新增字段,對於擴充套件性有一定的提公升,但是有乙個致命的缺陷就是會導致單條記錄占用空間過大,當使用者的資訊型別較多時,比如info_n(n = 100),那麼假設單個資訊的key.length = 6, value.length = 1,加上記錄之間的逗號和分號,大概需要(6+1+1+1)* 100 -1 = 899。所以在儲存空間上有很大的優化空間。

對於同事的方案,除了記錄字段本身最大長度的限度之外,當資料量比較大的時候對空間的浪費也很多,所以我們這個優化版方案主要是為了盡可能的減少記錄的長度。首先是建立乙個字典表:

create table info_type (id int auto_increment comment '自增主鍵',type_name varchar(50) not null comment '型別名稱',type_key tinyint not null comment '型別的key',remark varchar(50) comment '備註資訊',primary key (`id`),unique key uniq_type_name(`type_name`),unique key uniq_type_key(`type_key`))engine=innodb
字典儲存格式:

業務資料的儲存格式:

這樣在value欄位中就可以將本來的`info_1:1,info_2:0,info_3:0`儲存為`1:1,2:0,3:0`,明顯降低了value欄位的長度,在節省了儲存空間的同時,還增加了value欄位最大可擴充套件字段數量。這裡說明下,可能info_type表會增加部門的儲存,但是這種字典型別的資料,畢竟是不會很多,非常有限,而當真正的業務記錄比較多的時候,節省的空間遠遠比字典表占用的空間要多。這裡還有乙個問題,就是對應的type_key要在程式(**)中轉換為業務需要的字段。

為了提高擴充套件性,設計出如下的高擴充套件版(理論上可以無限的擴充套件)。這裡就直接復用上面的info_type資料,同時設計業務記錄表為:

create table user_info (id bigint auto_increment comment '自增主鍵',id bigint auto_increment comment '自增主鍵',info_no varchar(50) not null comment '記錄編號',user_no varchar(50) not null comment '使用者編號',info_key tinyint not null comment '記錄的key',info_value tinyint not null comment '記錄的值',remark varchar(200) comment '備註資訊',create_time datetime comment '建立時間',update_time datetime comment '更新時間',primary key (`id`),unique key uniq_info(`info_no`),unique key uniq_user_key(`user_no`, `info_key`))engine=innodb
儲存的**如下圖所示:

顯然這種方案,不用擔心記錄行的最大長度限制,同時對於擴充套件,可以任意的新增資訊字段,理論上可以無限的增加,好處很明顯,唯一一點缺點就是前面的版本只用記錄一次user_no,這種方案可能需要記錄很多次,浪費了一定的儲存空間。但是這種方案擴充套件性非常好,同時當資料量大的時候還可以使用分庫分表的方式擴充套件(應該達不到這個數量級)。

希望本文對您在設計業務需求設計sql階段有所幫助或者啟發。

限於筆者知識有限,如果不足之處請幫忙指正,不喜勿噴!

sql新增自增id 如何理解SQL中的自連線?

說起自連線,想必小夥伴們都聽說過。在進行資料處理時經常會使用到自連線,特別是像一些連續性的問題中使用的比較多。瘋狂暗示 sql如何求解連續性的問題?自連線是什麼 那我們如何理解自連線呢?自連線說白了其實就是兩張表結構和資料內容完全一樣的表,在做資料處理的時候,我們通常會給它們分別重新命名來加以區分 ...

SQL語句 插入資料的同時,返回ID值 (自增)

2000中,有三個比較類似的功能 他們分別是 scope identity ident current 和 identity,它們都返回插入到 identity 列中的值。ident current 返回為任何會話和任何作用域中的特定表最後生成的標識值。ident current 不受作用域和會話的...

Redis一次資料丟失

一台redis伺服器,4核,16g記憶體且沒有任何硬體上的問題。持續高壓執行了大約3個月,儲存了大約14g的資料,設定了比較完備的s e引數。而就是這台主機,在一次重起之後,丟失了大量的資料,14g的資料最終只恢復了幾百兆而已。正常情況下,像redis這樣定期回寫磁碟的記憶體資料庫,丟失幾個資料也是...