PostgreSQLFOR快遞公司快件跟蹤表設計思考
快遞隨著電商的崛起逐漸火爆, 特別是電商搞大促銷的階段, 快遞更是達到爆倉的狀態.
如果全國電商1天生成100億比交易的話, 快遞公司的IT是怎麼完成這些無紙化操作的呢, 比如資料錄入, 快件的狀態跟蹤, 使用者通過網站查詢快遞等等.
我沒在快遞公司的IT部門幹過, 也沒和快遞公司的DBA或者架構師交流過, 以下純屬個人扯淡.
最近買了點東西, 早上查了一下快遞單, 甚至一天查好幾次, 我估計大多數人和我一樣, 沒電腦的人也可能通過打電話去查詢.
突發奇想, 快遞的資料庫怎麼支撐使用者的查詢和快遞公司內部業務系統的更新和查詢呢?
我假象的快遞資料庫的特點.
1. 一堆的字典表, 比如快遞公司的組織結構字典表. 這種查詢多, 更新少.
要體現層次結構的話, 可以參考pg的異構資料查詢舉例
還有一個PG的外掛型別, ltree, 也可以體現組織結構.
2. 應該會有類似的GIS系統, 計算最優路徑.
3. 快遞單的屬性表, 包括重量, 起點終點, 保價否, 寄件人屬性, 收件人屬性, 價格等.
4. 快件跟蹤表應該是最大的, 可以按時間分割槽, 老的快件跟蹤記錄基本上不會被查詢到了. 只用作留檔.
快件跟蹤表記錄快遞的實時狀態, 並且這些狀態要串起來.
例如我查詢的一個快遞狀態如下
快 件 跟 蹤
2013/12/13 7:50:38
快件狀態 >>
快遞單號 | 日期時間 | 快件狀態 |
---|---|---|
3393108415 | 2013-12-12 17:37:27 | 安徽省合肥市蜀山區包河三部公司 已收件 |
3393108415 | 2013-12-12 19:30:59 | 安徽省合肥市蜀山區包河三部公司 已發出 |
3393108415 | 2013-12-12 20:09:50 | 安徽省合肥市公司 已收入 |
3393108415 | 2013-12-12 21:47:46 | 安徽省合肥市公司 已打包 |
3393108415 | 2013-12-12 22:01:08 | 合肥轉運中心公司 已收入 |
3393108415 | 2013-12-12 22:05:09 | 合肥轉運中心公司 已發出 |
3393108415 | 2013-12-13 05:11:55 | 杭州轉運中心公司 已收入 |
3393108415 | 2013-12-13 05:43:59 | 杭州轉運中心公司 已發出 |
有些快遞公司提供一次查詢多個快遞單號.
快遞的狀態表的特點, 我假象它是更新少, 查詢多的一個特點.
並且更新不應該出現衝突, 即多個執行緒同時更新同一條記錄.
那麼查詢多, 更新少的話, 我的建議是在跟蹤表中, 一個快遞單子一條記錄.
這樣做的好處是, 查詢時很快, 只需要掃描2個塊左右 , 1個索引塊, 1個HEAP塊.
但是如果一個快遞單子多條記錄, 即每個狀態插入一條, 這樣的帶來的是大量的資料塊的掃描, 基本上每條記錄都會分佈在不同的資料塊上. 假設平均一個快遞單的跟蹤記錄是15條, 資料塊的掃描要多14個.
那麼1條記錄怎麼儲存呢?
快遞單+複合型別陣列(節點時間+節點ID+狀態)+rec插入時間+rec更新時間
當然, 這裡不用陣列也行, 只要程式能根據儲存的資訊分隔每個節點狀態即可, 這樣做的好處是結構更加鬆散, 適合非結構話資料, 比方說在快遞結束的地方會出現派件人, 派件人的電話等, 結構和前面不一樣.
對應我這個例子是:
3393108415, [(2013-12-12 17:37:27,安徽合肥市蜀山區包河三部公司字典表裡的ID,收件狀態ID), (下一個狀態的複合型別…), ()], 記錄插入時間, 記錄的更新時間
新的狀態錄入時, 用array_append往陣列後面追加資料即可.
我們舉一個實際的例子(本例省去字典表, 只為體現單行和多行的查詢效能) :
為了使生成速度快點, 我們使用NOLOGGING表, 同時關閉 autovacuum.
digoal=# create unlogged table kuaidi_log1(id int8, crt_time timestamp, nodeid text, stat text);
CREATE TABLE
digoal=# create unlogged table kuaidi_log2(id int8, comp text);
CREATE TABLE
假設每天有500W個訂單, 平均每個訂單20條資料的話, 需要1億條測試資料.
pg93@db-172-16-3-150-> vi test.sql
setrandom id 1 5000000
insert into kuaidi_log1 values (:id, now(), `浙江省圓通快遞杭州分公司`, `已收件`);
開啟16個連線使用pgbench進行插入.
pg93@db-172-16-3-150-> pgbench -M prepared -n -r -f ./test.sql -c 16 -j 4 -t 6250000
transaction type: Custom query
scaling factor: 1
query mode: prepared
number of clients: 16
number of threads: 4
number of transactions per client: 6250000
number of transactions actually processed: 100000000/100000000
tps = 79215.655001 (including connections establishing)
tps = 79216.552965 (excluding connections establishing)
statement latencies in milliseconds:
0.001938 setrandom id 1 5000000
0.194045 insert into kuaidi_log1 values (:id, now(), `浙江省圓通快遞杭州分公司`, `已收件`);
剛好1億記錄.
插入完後建立快遞單的索引.
digoal=# create index idx_kuaidi_log1_1 on kuaidi_log1 (id);
kuaidi_log1表和索引的大小
digoal=# dt+ kuaidi_log1
List of relations
Schema | Name | Type | Owner | Size | Description
----------+-------------+-------+----------+---------+-------------
postgres | kuaidi_log1 | table | postgres | 8880 MB |
(1 row)
digoal=# di+ idx_kuaidi_log1_1
List of relations
Schema | Name | Type | Owner | Table | Size | Description
----------+-------------------+-------+----------+-------------+---------+-------------
postgres | idx_kuaidi_log1_1 | index | postgres | kuaidi_log1 | 2142 MB |
(1 row)
把這些記錄合併到kuaidi_log2表, 每個快遞單1條.
insert into kuaidi_log2 select id, string_agg(crt_time::text||`,`||nodeid||`,`||stat, `;` order by crt_time) from kuaidi_log1 group by id;
INSERT 0 5000000
建立kuaidi_log2表的快遞單號索引.
digoal=# create index idx_kuaidi_log2_1 on kuaidi_log2 (id);
kuaidi_log2表和索引大小, 索引變小了20倍, 因為只有500萬條記錄.
digoal=# dt+ kuaidi_log2
List of relations
Schema | Name | Type | Owner | Size | Description
----------+-------------+-------+----------+---------+-------------
postgres | kuaidi_log2 | table | postgres | 7172 MB |
(1 row)
digoal=# di+ idx_kuaidi_log2_1
List of relations
Schema | Name | Type | Owner | Table | Size | Description
----------+-------------------+-------+----------+-------------+--------+-------------
postgres | idx_kuaidi_log2_1 | index | postgres | kuaidi_log2 | 107 MB |
(1 row)
資料對比 :
digoal=# select * from kuaidi_log1 where id=1;
id | crt_time | nodeid | stat
----+----------------------------+--------------------------+--------
1 | 2013-12-13 08:40:21.116411 | 浙江省圓通快遞杭州分公司 | 已收件
1 | 2013-12-13 08:41:22.298613 | 浙江省圓通快遞杭州分公司 | 已收件
1 | 2013-12-13 08:42:38.141089 | 浙江省圓通快遞杭州分公司 | 已收件
1 | 2013-12-13 08:43:10.396533 | 浙江省圓通快遞杭州分公司 | 已收件
1 | 2013-12-13 08:43:14.961726 | 浙江省圓通快遞杭州分公司 | 已收件
1 | 2013-12-13 08:44:22.036227 | 浙江省圓通快遞杭州分公司 | 已收件
1 | 2013-12-13 08:46:24.767686 | 浙江省圓通快遞杭州分公司 | 已收件
1 | 2013-12-13 08:46:41.418713 | 浙江省圓通快遞杭州分公司 | 已收件
1 | 2013-12-13 08:46:48.03819 | 浙江省圓通快遞杭州分公司 | 已收件
1 | 2013-12-13 08:47:32.8119 | 浙江省圓通快遞杭州分公司 | 已收件
1 | 2013-12-13 08:47:48.996097 | 浙江省圓通快遞杭州分公司 | 已收件
1 | 2013-12-13 08:50:54.001399 | 浙江省圓通快遞杭州分公司 | 已收件
1 | 2013-12-13 08:52:00.678307 | 浙江省圓通快遞杭州分公司 | 已收件
1 | 2013-12-13 08:52:14.56005 | 浙江省圓通快遞杭州分公司 | 已收件
1 | 2013-12-13 08:56:45.806082 | 浙江省圓通快遞杭州分公司 | 已收件
(15 rows)
digoal=# select * from kuaidi_log2 where id=1;
id |
comp
----+-------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------
1 | 2013-12-13 08:40:21.116411,浙江省圓通快遞杭州分公司,已收件;2013-12-13 08:41:22.298613,浙江省圓通快遞杭州分公司,已收件;2013-12-
13 08:42:38.141089,浙江省圓通快遞杭州分公司,已收件;2013-12-13 08:43:10.396533,浙江省圓通快遞杭州分公司,已收件;2013-12-13 08:43:14.96
1726,浙江省圓通快遞杭州分公司,已收件;2013-12-13 08:44:22.036227,浙江省圓通快遞杭州分公司,已收件;2013-12-13 08:46:24.767686,浙江省圓
快遞杭州分公司,已收件;2013-12-13 08:46:41.418713,浙江省圓通快遞杭州分公司,已收件;2013-12-13 08:46:48.03819,浙江省圓通快遞杭州分公司,
已收件;2013-12-13 08:47:32.8119,浙江省圓通快遞杭州分公司,已收件;2013-12-13 08:47:48.996097,浙江省圓通快遞杭州分公司,已收件;2013-12-1
3 08:50:54.001399,浙江省圓通快遞杭州分公司,已收件;2013-12-13 08:52:00.678307,浙江省圓通快遞杭州分公司,已收件;2013-12-13 08:52:14.560
05,浙江省圓通快遞杭州分公司,已收件;2013-12-13 08:56:45.806082,浙江省圓通快遞杭州分公司,已收件
(1 row)
測試kuaidi_log1的查詢效能
vi test.sql
setrandom id 1 5000000
select * from kuaidi_log1 where id=:id order by crt_time;
pgbench -M prepared -n -r -f ./test.sql -c 16 -j 4 -T 30
pg93@db-172-16-3-150-> pgbench -M prepared -n -r -f ./test.sql -c 16 -j 4 -T 30
transaction type: Custom query
scaling factor: 1
query mode: prepared
number of clients: 16
number of threads: 4
duration: 30 s
number of transactions actually processed: 349163
tps = 11635.992258 (including connections establishing)
tps = 11641.693582 (excluding connections establishing)
statement latencies in milliseconds:
0.003351 setrandom id 1 5000000
1.368531 select * from kuaidi_log1 where id=:id order by crt_time;
測試kuaidi_log2的查詢效能, 流水已按時間排序, 所以不需要再次排序.
vi test.sql
setrandom id 1 5000000
select * from kuaidi_log2 where id=:id;
pgbench -M prepared -n -r -f ./test.sql -c 16 -j 4 -T 30
pg93@db-172-16-3-150-> pgbench -M prepared -n -r -f ./test.sql -c 16 -j 4 -T 30
transaction type: Custom query
scaling factor: 1
query mode: prepared
number of clients: 16
number of threads: 4
duration: 30 s
number of transactions actually processed: 1880690
tps = 62681.334228 (including connections establishing)
tps = 62711.904831 (excluding connections establishing)
statement latencies in milliseconds:
0.002509 setrandom id 1 5000000
0.251047 select * from kuaidi_log2 where id=:id;
查詢效能相差5倍.
這種設計方式適合寫少讀多的場景, 並且寫的場景不會產生鎖衝突. 否則不要使用這種設計.
相關文章
- 春節快遞停運時間 天天快遞:提供快件收寄、查詢服務
- 拼多多商家批次查詢跟蹤快遞的簡單教程
- 演算法分析__遞迴跟蹤演算法遞迴
- 第三方物流快遞單號查詢跟蹤api介面對接API
- 教你批次查詢快遞並篩選出快遞公司
- 10g 新特性 快改變跟蹤
- ORACLE 10046 設定跟蹤事件後無跟蹤檔案Oracle事件
- 教你如何用Python追蹤快遞資訊!Python
- [zt] oracle跟蹤檔案與跟蹤事件Oracle事件
- oracle跟蹤檔案與跟蹤事件(zt)Oracle事件
- oracle跟蹤檔案和跟蹤事件(zt)Oracle事件
- 批次查快遞單號的軟體有哪些,追蹤快遞什麼軟體好用
- 耐克公司的WingTips分散式跟蹤系統分散式
- 設定跟蹤事件不起作用。事件
- 利用行SCN實現表變化跟蹤
- 專案計劃與跟蹤(轉)
- 全球快遞追蹤技術支援(Global Parcel Tracker Support)
- [Q]如果設定自動跟蹤 zt
- 快取遞迴計算快取遞迴
- sqlnet跟蹤SQL
- ORACLE 跟蹤工具Oracle
- 近期關於快取設計的一些思考快取
- 40 歲+ 程式設計師被裁員,快遞都不收。。程式設計師
- 【專案管理】推薦:簡易專案跟蹤表專案管理
- 快遞行業大變局:4家知名快遞公司接連倒下,京東物流有多牛?行業
- 基於行跟蹤的ROWDEPENDENCIES實現資訊變化跟蹤
- 【Longkin】ASP.NET應用程式跟蹤---(一)跟蹤頁面ASP.NET
- 一鍵批量查詢極兔快遞並設定快遞引數
- 反跟蹤技術
- 【TRACE】Oracle跟蹤事件Oracle事件
- Oracle跟蹤會話Oracle會話
- Oracle 跟蹤事件【轉】Oracle事件
- Oracle跟蹤檔案Oracle
- 主力跟蹤戰法
- PHP快遞代取系統跑腿系統(畢業設計)PHP
- 表單互動設計之必選項思考
- 表單互動設計之二:校驗思考
- sp_trace_setfilter sqlserver篩選跟蹤或跟蹤過濾FilterSQLServer