摘要:新的數(shù)據(jù)表關(guān)系數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)類似于這樣子大碼中碼小碼這個表結(jié)構(gòu)的說明是避免對于關(guān)系鏈的數(shù)據(jù)邏輯不理解做的一個示例。
最近幾天一直在糾結(jié)于一個大數(shù)據(jù)批量導入的問題,經(jīng)過幾天思考,發(fā)現(xiàn)基于小數(shù)據(jù)情況,原本的數(shù)據(jù)結(jié)構(gòu)設(shè)計是沒有問題的,但是在大量數(shù)據(jù)導入,問題就很大了。我之前一直在強調(diào)“程序=數(shù)據(jù)結(jié)構(gòu)+算法”,但在這此卻鉆了牛角尖,最后去仔細看了之前別人設(shè)計的數(shù)據(jù)表才突然靈光一現(xiàn),發(fā)現(xiàn)了mysql層面要以空間換時間的具體設(shè)計思路。
基于這種情況,先說一下經(jīng)過這個過程后的感悟。
感悟后續(xù)的程序邏輯如果出現(xiàn)算法復雜的問題,不要延續(xù)之前的程序設(shè)計,同樣不要延續(xù)之前的數(shù)據(jù)表結(jié)構(gòu)設(shè)計,要多方面思考。
隨著業(yè)務(wù)的變更,不僅僅是程序上的變更,還有數(shù)據(jù)結(jié)構(gòu)上的變更,大量數(shù)據(jù)的處理方式與常規(guī)處理數(shù)據(jù)思維不太一樣。
產(chǎn)品需求這次的具體問題,我先從產(chǎn)品需求說起,并從頭聊我踩過的坑。
用戶撒碼可以根據(jù)這個碼知道商品流向,系統(tǒng)有幾層代理商,在商品到達用戶手中之后,用戶可以根據(jù)掃碼查詢整個商品的流向,經(jīng)過了哪些代理商手中;
代理商掃碼可以進行發(fā)貨,根據(jù)這個追溯碼標記商品發(fā)貨狀態(tài),同時存儲代理商發(fā)貨狀態(tài)。
追溯碼有三個碼類,分為大碼、中碼、小碼,類似于一個大碼對應(yīng)一箱貨物,一個中碼對應(yīng)一箱貨物中的一盒,一個小碼對應(yīng)一盒貨物中的某一件具體貨物;也就是說大碼涵蓋中碼,中碼涵蓋小碼,需要通過上層的追溯碼找到整個關(guān)系鏈。
商戶根據(jù)需要,進行追溯碼導入,一次性導入的數(shù)據(jù)條數(shù)大約為10萬條左右,也可能更多,也可能更少。
踩坑 原本的數(shù)據(jù)表結(jié)構(gòu)設(shè)計admin_id #商戶ID product_id #商品ID security_code #追溯碼 code_type #追溯碼類型:1大碼,2中碼,3小碼 parent_id #當前追溯碼的上級ID,如小碼對應(yīng)的上級中碼ID top_id #頂級ID,對應(yīng)的為大碼的ID,中碼和小碼都要村粗 is_use #此追溯碼是否已使用 is_sell_out #是否已經(jīng)售出 created_time #創(chuàng)建時間 updated_time #更新時間 is_deleted #是否刪除原程序設(shè)計思想
整套數(shù)據(jù)表結(jié)構(gòu)的設(shè)計邏輯是以 parent_id 來進行關(guān)系關(guān)聯(lián),然后通過code_type來標明追溯碼的類型,在導入的時候,先必須村粗父級,然后再存儲子級,層層遍歷導入。
此設(shè)計產(chǎn)生的問題由于必須層層遍歷導入,就會造成導入相當緩慢,必須先插入富級ID,然后再插入子級ID,因為子級ID關(guān)聯(lián)了父級ID。這樣也就不能采用mysql的
INSERT INTO table(field1,field2) VALUES("a", 1), ("b", 1), ("c", 1);
這種批量插入的方式進行插入,這樣的話,數(shù)據(jù)插入就會很緩慢。
經(jīng)過我后面的思考,把最后一級,也就是小碼采用了批量插入,但是發(fā)現(xiàn)效率還是并不高,就算把小碼改為批量插入,一次性批量插入的數(shù)據(jù)也僅有20條左右,對效率提高并不大。
新表設(shè)計方式新的設(shè)計,我把整個表拆分成了兩個表,一個表存儲關(guān)系鏈,一個表用來做追溯標記和查詢,大致如下:
關(guān)系表
admin_id #商戶ID product_id #商品ID code_max # 大碼 code_middle #中碼 code_min #小碼
追溯碼標記表
admin_id #商戶ID product_id #商品ID code #追溯碼,不管大碼中碼還是小碼都會建一條數(shù)據(jù)存放在此字段 is_use # 是否使用 is_sell_out #是否出售 create_time #創(chuàng)建時間 update_time # 更新時間 is_delete #是否已刪除新的邏輯說明
首先,在關(guān)系表里存儲的是關(guān)系,大碼、中碼、小碼都完整的村粗,可以通過大碼ID查詢到下面的所有中碼、小碼;
追溯碼標記表,這個表專門管查詢和標記追溯碼狀態(tài)等。
新的設(shè)計方式,會增加數(shù)據(jù)表數(shù)據(jù)的管理成本,也會增加數(shù)據(jù)量大小。
新的數(shù)據(jù)表關(guān)系數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)類似于這樣子:
大碼 | 中碼 | 小碼 |
---|---|---|
1 | 11 | 111 |
1 | 11 | 112 |
1 | 12 | 123 |
1 | 12 | 124 |
2 | 21 | 211 |
2 | 21 | 212 |
2 | 22 | 221 |
2 | 22 | 222 |
這個表結(jié)構(gòu)的說明是避免對于關(guān)系鏈的數(shù)據(jù)邏輯不理解做的一個示例。
整個表經(jīng)過這樣的重新設(shè)計和梳理了之后,每次同時插入兩個表,并且可以用MySQL的批量插入操作進行插入,插入速度具有非常大的提升。
數(shù)據(jù)重復對比在這套產(chǎn)品設(shè)計之中,整套的追溯碼是不能重復的,經(jīng)過了多方面思考,最后采用了in查詢機制,整套思路大致如下:
每次遍歷要導入的數(shù)據(jù)中的100條,然后用mysql的in去查詢,如果取到數(shù)據(jù),則遍歷數(shù)據(jù)標記哪一條重復。不斷的循環(huán)遍歷去取,然后標記輸出到CSV中,遍歷結(jié)束后,把標記重復的文檔返回給用戶,讓用戶修改好后再進行上傳。
不過關(guān)于這個數(shù)據(jù)對比的,我沒有更好的思路了,測試了18W條導入數(shù)據(jù)和數(shù)據(jù)表中的25W條數(shù)據(jù)對比,花的時間大約為13秒左右,就我的預估對比次數(shù)應(yīng)該為18W*25W,如果誰在這方面有更好的數(shù)據(jù)對比算法,請留言告訴我,不勝感激。
僅以此文紀念自己踩過的坑,也同樣希望后人看到這篇文章后能得到一些解決思路。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/22845.html
閱讀 3036·2023-04-25 20:22
閱讀 3350·2019-08-30 11:14
閱讀 2602·2019-08-29 13:03
閱讀 3190·2019-08-26 13:47
閱讀 3234·2019-08-26 10:22
閱讀 1279·2019-08-23 18:26
閱讀 628·2019-08-23 17:16
閱讀 1923·2019-08-23 17:01