风哥教程参考DB2官方文档Spatial Extender、XML Extender等内容,详细介绍物流系统库在DB2上的设计、位置服务、XML处理、跟踪查询。更多视频教程www.fgedu.net.cn
目录大纲
Part01-物流系统特点
1.1 物流业务特点
物流系统具有以下特点:
- 数据量大:订单、运单、跟踪数据量大
- 实时性强:位置跟踪、状态更新要求实时
- 查询复杂:多维度、多条件组合查询
- 地理位置:需要处理位置数据、路径规划
- 历史追溯:完整的物流轨迹记录
- 高并发:多个网点同时操作
1.2 数据模型分类
- 基础数据:网点、仓库、车辆、司机
- 业务数据:订单、运单、调度单
- 跟踪数据:位置、状态、时间戳
- 结算数据:费用、账单、支付
- 统计数据:报表、KPI、分析
Part02-核心表结构设计
2.1 基础信息表
CREATE TABLE SITE (
SITE_ID VARCHAR(20) NOT NULL,
SITE_NAME VARCHAR(100) NOT NULL,
SITE_TYPE VARCHAR(20) NOT NULL,
ADDRESS VARCHAR(200),
CITY VARCHAR(50),
PROVINCE VARCHAR(50),
POSTAL_CODE VARCHAR(10),
CONTACT_PERSON VARCHAR(50),
CONTACT_PHONE VARCHAR(20),
LATITUDE DECIMAL(10, 6),
LONGITUDE DECIMAL(10, 6),
SITE_STATUS VARCHAR(10) NOT NULL,
CREATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
UPDATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
CONSTRAINT PK_SITE PRIMARY KEY (SITE_ID)
) ORGANIZE BY ROW;
# 车辆表
CREATE TABLE VEHICLE (
VEHICLE_ID VARCHAR(20) NOT NULL,
PLATE_NUMBER VARCHAR(20) NOT NULL,
VEHICLE_TYPE VARCHAR(20) NOT NULL,
BRAND VARCHAR(50),
MODEL VARCHAR(50),
CAPACITY DECIMAL(10, 2),
LOAD_WEIGHT DECIMAL(10, 2),
CURRENT_SITE_ID VARCHAR(20),
VEHICLE_STATUS VARCHAR(10) NOT NULL,
CREATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
UPDATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
CONSTRAINT PK_VEHICLE PRIMARY KEY (VEHICLE_ID)
) ORGANIZE BY ROW;
# 司机表
CREATE TABLE DRIVER (
DRIVER_ID VARCHAR(20) NOT NULL,
DRIVER_NAME VARCHAR(50) NOT NULL,
ID_CARD VARCHAR(20) NOT NULL,
PHONE VARCHAR(20),
LICENSE_TYPE VARCHAR(20),
LICENSE_NUMBER VARCHAR(50),
CURRENT_SITE_ID VARCHAR(20),
DRIVER_STATUS VARCHAR(10) NOT NULL,
CREATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
UPDATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
CONSTRAINT PK_DRIVER PRIMARY KEY (DRIVER_ID)
) ORGANIZE BY ROW;
# 创建索引
CREATE INDEX IDX_SITE_CITY ON SITE(CITY, SITE_STATUS);
CREATE INDEX IDX_VEHICLE_SITE ON VEHICLE(CURRENT_SITE_ID, VEHICLE_STATUS);
CREATE INDEX IDX_DRIVER_SITE ON DRIVER(CURRENT_SITE_ID, DRIVER_STATUS);
2.2 运单表设计
CREATE TABLE WAYBILL (
WAYBILL_NO VARCHAR(32) NOT NULL,
ORDER_NO VARCHAR(32),
SENDER_NAME VARCHAR(100),
SENDER_PHONE VARCHAR(20),
SENDER_ADDRESS VARCHAR(200),
SENDER_CITY VARCHAR(50),
RECEIVER_NAME VARCHAR(100),
RECEIVER_PHONE VARCHAR(20),
RECEIVER_ADDRESS VARCHAR(200),
RECEIVER_CITY VARCHAR(50),
GOODS_NAME VARCHAR(200),
GOODS_WEIGHT DECIMAL(10, 2),
GOODS_VOLUME DECIMAL(10, 2),
GOODS_QUANTITY INTEGER,
SHIPPING_TYPE VARCHAR(20),
TOTAL_FEE DECIMAL(10, 2),
PAYMENT_TYPE VARCHAR(20),
WAYBILL_STATUS VARCHAR(20) NOT NULL,
CREATE_SITE_ID VARCHAR(20),
CURRENT_SITE_ID VARCHAR(20),
CREATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
UPDATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
CONSTRAINT PK_WAYBILL PRIMARY KEY (WAYBILL_NO)
) ORGANIZE BY ROW;
# 运单状态轨迹表
CREATE TABLE WAYBILL_TRACK (
TRACK_ID BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY,
WAYBILL_NO VARCHAR(32) NOT NULL,
STATUS VARCHAR(20) NOT NULL,
STATUS_DESC VARCHAR(200),
SITE_ID VARCHAR(20),
OPERATOR_ID VARCHAR(20),
OPERATOR_NAME VARCHAR(50),
LATITUDE DECIMAL(10, 6),
LONGITUDE DECIMAL(10, 6),
TRACK_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
CONSTRAINT PK_WAYBILL_TRACK PRIMARY KEY (TRACK_ID)
) PARTITION BY RANGE (TRACK_TIME)
(
STARTING ‘2026-01-01-00.00.00.000000’
ENDING ‘2026-12-31-23.59.59.999999’
EVERY 1 MONTH
);
# 创建索引
CREATE UNIQUE INDEX IDX_WAYBILL_NO ON WAYBILL(WAYBILL_NO);
CREATE INDEX IDX_WAYBILL_STATUS ON WAYBILL(WAYBILL_STATUS, UPDATE_TIME DESC);
CREATE INDEX IDX_WAYBILL_CURRENT_SITE ON WAYBILL(CURRENT_SITE_ID, WAYBILL_STATUS);
CREATE INDEX IDX_WAYBILL_TRACK_WAYBILL ON WAYBILL_TRACK(WAYBILL_NO, TRACK_TIME DESC) PARTITIONED;
CREATE INDEX IDX_WAYBILL_TRACK_SITE ON WAYBILL_TRACK(SITE_ID, TRACK_TIME) PARTITIONED;
2.3 调度表设计
CREATE TABLE DISPATCH (
DISPATCH_ID VARCHAR(32) NOT NULL,
VEHICLE_ID VARCHAR(20) NOT NULL,
DRIVER_ID VARCHAR(20),
FROM_SITE_ID VARCHAR(20) NOT NULL,
TO_SITE_ID VARCHAR(20) NOT NULL,
PLAN_DEPART_TIME TIMESTAMP,
PLAN_ARRIVE_TIME TIMESTAMP,
ACTUAL_DEPART_TIME TIMESTAMP,
ACTUAL_ARRIVE_TIME TIMESTAMP,
DISPATCH_STATUS VARCHAR(20) NOT NULL,
CREATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
UPDATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
CONSTRAINT PK_DISPATCH PRIMARY KEY (DISPATCH_ID)
) ORGANIZE BY ROW;
# 调度明细表
CREATE TABLE DISPATCH_DETAIL (
DETAIL_ID BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY,
DISPATCH_ID VARCHAR(32) NOT NULL,
WAYBILL_NO VARCHAR(32) NOT NULL,
LOAD_ORDER INTEGER,
CREATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
CONSTRAINT PK_DISPATCH_DETAIL PRIMARY KEY (DETAIL_ID)
) ORGANIZE BY ROW;
# 车辆位置轨迹表
CREATE TABLE VEHICLE_TRACK (
TRACK_ID BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY,
VEHICLE_ID VARCHAR(20) NOT NULL,
LATITUDE DECIMAL(10, 6) NOT NULL,
LONGITUDE DECIMAL(10, 6) NOT NULL,
SPEED DECIMAL(5, 2),
DIRECTION INTEGER,
TRACK_TIME TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
CONSTRAINT PK_VEHICLE_TRACK PRIMARY KEY (TRACK_ID)
) PARTITION BY RANGE (TRACK_TIME)
(
STARTING ‘2026-01-01-00.00.00.000000’
ENDING ‘2026-12-31-23.59.59.999999’
EVERY 1 DAY
);
# 创建索引
CREATE INDEX IDX_DISPATCH_VEHICLE ON DISPATCH(VEHICLE_ID, DISPATCH_STATUS);
CREATE INDEX IDX_DISPATCH_SITES ON DISPATCH(FROM_SITE_ID, TO_SITE_ID, DISPATCH_STATUS);
CREATE INDEX IDX_DISPATCH_DETAIL_DISPATCH ON DISPATCH_DETAIL(DISPATCH_ID);
CREATE INDEX IDX_VEHICLE_TRACK_VEHICLE ON VEHICLE_TRACK(VEHICLE_ID, TRACK_TIME DESC) PARTITIONED;
Part03-空间数据与位置服务
3.1 空间表设计
ALTER TABLE SITE ADD COLUMN LOCATION DB2GSE.ST_POINT;
# 更新位置数据
UPDATE SITE SET
LOCATION = DB2GSE.ST_POINT(LONGITUDE, LATITUDE, 1)
WHERE LONGITUDE IS NOT NULL AND LATITUDE IS NOT NULL;
# 创建空间索引
CREATE INDEX IDX_SITE_LOCATION ON SITE(LOCATION)
EXTEND USING DB2GSE.SPATIAL_INDEX;
# 车辆位置空间表
ALTER TABLE VEHICLE_TRACK ADD COLUMN LOCATION DB2GSE.ST_POINT;
UPDATE VEHICLE_TRACK SET
LOCATION = DB2GSE.ST_POINT(LONGITUDE, LATITUDE, 1);
CREATE INDEX IDX_VEHICLE_TRACK_LOCATION ON VEHICLE_TRACK(LOCATION)
EXTEND USING DB2GSE.SPATIAL_INDEX PARTITIONED;
3.2 空间查询
SELECT
SITE_ID,
SITE_NAME,
ADDRESS,
DB2GSE.ST_DISTANCE(LOCATION, DB2GSE.ST_POINT(116.404, 39.915, 1)) AS DISTANCE_METERS
FROM SITE
WHERE DB2GSE.ST_WITHIN_DISTANCE(
LOCATION,
DB2GSE.ST_POINT(116.404, 39.915, 1),
5000,
‘METERS’
) = 1
ORDER BY DISTANCE_METERS;
# 查找区域内车辆
SELECT
v.VEHICLE_ID,
v.PLATE_NUMBER,
vt.TRACK_TIME,
vt.LATITUDE,
vt.LONGITUDE
FROM VEHICLE v
INNER JOIN (
SELECT
VEHICLE_ID,
LATITUDE,
LONGITUDE,
TRACK_TIME,
ROW_NUMBER() OVER (PARTITION BY VEHICLE_ID ORDER BY TRACK_TIME DESC) AS RN
FROM VEHICLE_TRACK
WHERE TRACK_TIME > CURRENT TIMESTAMP – 1 HOUR
) vt ON v.VEHICLE_ID = vt.VEHICLE_ID AND vt.RN = 1
WHERE DB2GSE.ST_WITHIN(
vt.LOCATION,
DB2GSE.ST_POLYGON(
‘POLYGON((116.0 39.5, 116.0 40.0, 116.8 40.0, 116.8 39.5, 116.0 39.5))’,
1
)
) = 1;
# 计算两点间距离
SELECT
DB2GSE.ST_DISTANCE(
DB2GSE.ST_POINT(116.404, 39.915, 1),
DB2GSE.ST_POINT(121.473, 31.230, 1),
‘KILOMETERS’
) AS DISTANCE_KM
FROM SYSIBM.SYSDUMMY1;
Part04-跟踪与查询优化
4.1 运单跟踪查询
CREATE OR REPLACE VIEW V_WAYBILL_TRACK AS
SELECT
w.WAYBILL_NO,
w.ORDER_NO,
w.SENDER_NAME,
w.RECEIVER_NAME,
w.WAYBILL_STATUS,
t.STATUS,
t.STATUS_DESC,
t.SITE_ID,
s.SITE_NAME,
t.OPERATOR_NAME,
t.LATITUDE,
t.LONGITUDE,
t.TRACK_TIME
FROM WAYBILL w
LEFT JOIN WAYBILL_TRACK t ON w.WAYBILL_NO = t.WAYBILL_NO
LEFT JOIN SITE s ON t.SITE_ID = s.SITE_ID;
# 运单跟踪查询
SELECT * FROM V_WAYBILL_TRACK
WHERE WAYBILL_NO = ‘WB2026040800001’
ORDER BY TRACK_TIME DESC;
# 创建存储过程
CREATE OR REPLACE PROCEDURE SP_GET_WAYBILL_TRACK(
IN p_waybill_no VARCHAR(32),
OUT p_result_code VARCHAR(10),
OUT p_result_msg VARCHAR(200)
)
RESULT SETS 1
LANGUAGE SQL
BEGIN
DECLARE v_count INTEGER;
SET p_result_code = ‘SUCCESS’;
SET p_result_msg = ‘查询成功’;
SELECT COUNT(*) INTO v_count FROM WAYBILL WHERE WAYBILL_NO = p_waybill_no;
IF v_count = 0 THEN
SET p_result_code = ‘FAIL’;
SET p_result_msg = ‘运单不存在’;
RETURN;
END IF;
BEGIN
DECLARE c1 CURSOR WITH RETURN FOR
SELECT
t.TRACK_ID,
t.STATUS,
t.STATUS_DESC,
t.SITE_ID,
s.SITE_NAME,
t.OPERATOR_NAME,
t.LATITUDE,
t.LONGITUDE,
t.TRACK_TIME
FROM WAYBILL_TRACK t
LEFT JOIN SITE s ON t.SITE_ID = s.SITE_ID
WHERE t.WAYBILL_NO = p_waybill_no
ORDER BY t.TRACK_TIME DESC;
OPEN c1;
END;
END;
# 调用存储过程
CALL SP_GET_WAYBILL_TRACK(‘WB2026040800001’, ?, ?);
4.2 物化查询表优化
CREATE TABLE MQT_WAYBILL_STAT AS (
SELECT
CURRENT_SITE_ID,
WAYBILL_STATUS,
COUNT(*) AS COUNT,
SUM(TOTAL_FEE) AS TOTAL_FEE_SUM
FROM WAYBILL
GROUP BY CURRENT_SITE_ID, WAYBILL_STATUS
) DATA INITIALLY DEFERRED REFRESH DEFERRED;
REFRESH TABLE MQT_WAYBILL_STAT;
# 创建索引
CREATE INDEX IDX_MQT_WAYBILL_SITE ON MQT_WAYBILL_STAT(CURRENT_SITE_ID, WAYBILL_STATUS);
# 按时间统计MQT
CREATE TABLE MQT_WAYBILL_DAILY AS (
SELECT
DATE(CREATE_TIME) AS CREATE_DATE,
CREATE_SITE_ID,
COUNT(*) AS COUNT,
SUM(TOTAL_FEE) AS TOTAL_FEE_SUM
FROM WAYBILL
GROUP BY DATE(CREATE_TIME), CREATE_SITE_ID
) DATA INITIALLY DEFERRED REFRESH DEFERRED;
REFRESH TABLE MQT_WAYBILL_DAILY;
# 自动刷新MQT
CREATE OR REPLACE PROCEDURE SP_REFRESH_MQTS()
LANGUAGE SQL
BEGIN
REFRESH TABLE MQT_WAYBILL_STAT;
REFRESH TABLE MQT_WAYBILL_DAILY;
END;
Part05-风哥经验总结与分享
5.1 物流库设计要点
- 运单表按时间分区,便于归档
- 跟踪表按时间分区,提高查询效率
- 合理使用空间索引优化位置查询
- 使用MQT预计算统计数据
- 运单轨迹使用合适的索引
- 状态变更要有完整的记录
5.2 性能优化建议
| 场景 | 优化方案 |
|---|---|
| 运单查询 | 运单号索引,状态+时间索引 |
| 位置查询 | 空间索引,最近位置查询优化 |
| 统计报表 | MQT预计算,定期刷新 |
| 轨迹查询 | 分区表,复合索引 |
5.3 运维要点
- 定期归档历史跟踪数据
- 监控分区使用情况,及时添加新分区
- 定期刷新MQT
- 定期RUNSTATS和REORG
- 监控空间索引使用情况
- 建立备份恢复策略
学习交流加群风哥微信: itpux-com
风哥Oracle/MySQL/PostgreSQL/Greenplum/DB2/Redis等数据库培训课程,10年一线实战经验,企业级培训,真正掌握数据库核心技术!
本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html
