(1)数据源层设计要点
(2)集成层关键技术选型
(3)存储层设计规范
ODS层存储规范:
- 保留原始数据镜像,不做任何清洗
- 按天分区存储,保留最近90天数据
- 使用Snappy压缩,平衡CPU与存储效率
DWD层设计原则:
- 严格遵循星型模型,禁止雪花模型
- 所有维度表必须包含代理键(Surrogate Key)
- 事实表采用分区+分桶(Bucket)双重优化
(1)价值评估矩阵
评估维度 | 权重 | POS交易 | 线上订单 | 库存周转 |
---|---|---|---|---|
数据完整性 | 30% | 95分 | 85分 | 70分 |
业务战略重要性 | 40% | 100分 | 90分 | 80分 |
技术可行性 | 30% | 90分 | 75分 | 60分 |
综合得分 | 100% | 94分 | 83分 | 69分 |
(2)典型业务过程分析
POS交易过程:
会员生命周期过程:
(1)原子粒度的重要性
(2)粒度验证技术方案
/* 粒度唯一性验证脚本 */
WITH grain_check AS (
SELECT
transaction_id,
product_id,
COUNT(*) AS record_count
FROM ods.pos_transaction_details
GROUP BY 1,2
)
SELECT
CASE
WHEN record_count > 1 THEN '粒度冲突'
ELSE '粒度合规'
END AS check_result,
COUNT(*) AS total_records
FROM grain_check
GROUP BY 1;
/* 执行结果分析:
- 合规率需>99.99%,否则需检查源系统逻辑
- 冲突记录应写入质量日志并通知业务方 */
(1)维度层次管理方案
层级结构:事业部 > 商品大类 > 中类 > 小类 > SKU
建模方案:
- 桥接表设计处理非平衡层次(如临时促销类目)
- 路径枚举法优化查询性能(如'1.2.3.5'表示完整路径)
- 物化视图预计算各层级聚合指标
(2)促销维度复杂场景处理
CREATE TABLE dim_promotion (
promotion_key INT,
promo_id STRING,
promo_type STRING, -- 满减/折扣/赠品
combo_flag BOOLEAN, -- 是否组合促销
include_products ARRAY<STRING>, -- 参与商品列表
exclude_products ARRAY<STRING>, -- 排除商品
threshold_amount DECIMAL(16,2), -- 满减门槛
discount_rate DECIMAL(5,2) -- 折扣率
)
COMMENT '促销维度表';
(3)时间维度深度扩展
示例:2023081512(年月日时)
优势:
- 避免日期维度表关联提升查询性能
- 支持按小时粒度快速分区裁剪
字段定义规范:
字段名 | 类型 | 约束 | 注释说明 |
---|---|---|---|
date_key | INT | NOT NULL | 日期代理键(YYYYMMDD) |
product_key | INT | NOT NULL | 商品代理键(Type 2 SCD) |
store_key | INT | NOT NULL | 门店代理键(Type 1 SCD) |
customer_key | INT | NULL | 会员代理键(允许匿名购买) |
transaction_id | VARCHAR(32) | NOT NULL | 交易流水号(业务主键) |
quantity | DECIMAL(16,4) | CHECK>=0 | 销售数量(支持小数如0.5KG) |
gross_sales | DECIMAL(18,2) | CHECK>=0 | 商品原价金额 |
net_sales | DECIMAL(18,2) | CHECK>=0 | 实收金额(原价-折扣) |
物理存储优化:
CREATE TABLE fact_sales
PARTITIONED BY (date_key)
CLUSTERED BY (store_key) INTO 50 BUCKETS
STORED AS PARQUET
TBLPROPERTIES (
'parquet.compression'='ZSTD',
'parquet.dictionary.enabled'='true',
'parquet.bloom.filter.columns'='product_key,store_key'
);
/* 优化说明:
- 按日期分区实现快速范围查询
- 按门店分桶提升JOIN性能
- ZSTD压缩率比Snappy高30%
- 字典编码优化低基数字段存储
- Bloom过滤加速点查 */
(1)库存每日快照表
CREATE TABLE fact_inventory_snapshot (
snapshot_date_key INT,
product_key INT,
store_key INT,
on_hand_qty DECIMAL(16,4),
reserved_qty DECIMAL(16,4),
cost DECIMAL(18,2)
)
COMMENT '每日库存快照'
PARTITIONED BY (snapshot_date_key);
/* 业务规则:
- 每天凌晨2点全量快照
- 保留最近365天数据
- 建立与事务事实表的增量差异分析 */
(2)累积快照表实现订单全生命周期
CREATE TABLE fact_order_journey (
order_id STRING,
create_date_key INT,
pay_date_key INT,
ship_date_key INT,
receive_date_key INT,
status STRING
)
COMMENT '订单旅程事实表'
STORED AS PARQUET;
/* 更新逻辑:
每次状态变更时更新对应日期键字段
例如:
- 用户支付后更新pay_date_key
- 物流发货后更新ship_date_key */
(1)渐变维度处理流程图
(2)SCD2全量更新脚本
MERGE INTO dim_product AS target
USING (
SELECT
sku_id,
product_name,
category_id,
valid_from,
COALESCE(
LEAD(valid_from) OVER (PARTITION BY sku_id ORDER BY valid_from),
'9999-12-31'
) AS valid_to
FROM (
SELECT *, ROW_NUMBER() OVER (
PARTITION BY sku_id
ORDER BY valid_from DESC
) AS rn
FROM ods.product_versions
) WHERE rn = 1
) AS source
ON target.sku_id = source.sku_id
AND target.valid_to = '9999-12-31'
WHEN MATCHED AND (
target.product_name <> source.product_name
OR target.category_id <> source.category_id
) THEN
UPDATE SET valid_to = CURRENT_DATE()
WHEN NOT MATCHED THEN
INSERT (sku_id, product_name, category_id, valid_from, valid_to)
VALUES (source.sku_id, source.product_name, source.category_id,
source.valid_from, source.valid_to);
(3)历史数据查询示例
-- 查询商品2023年Q1的历史信息
SELECT *
FROM dim_product
WHERE sku_id = 'P12345'
AND valid_from <= '2023-03-31'
AND valid_to > '2023-01-01';
(1)Z-Order优化原理
(2)索引策略对比
索引类型 | 适用场景 | 维护成本 | 查询加速效果 |
---|---|---|---|
Bloom Filter | 高基数等值查询 | 低 | 3-5倍 |
Bitmap Index | 低基数枚举字段 | 中 | 10倍+ |
MinMax Index | 数值范围查询 | 低 | 2-3倍 |
(1)动态分区裁剪示例
-- 原始查询(全表扫描)
SELECT *
FROM fact_sales
WHERE product_key IN (
SELECT product_key
FROM dim_product
WHERE category = '生鲜'
);
-- 优化后(分区裁剪)
SELECT /*+ BROADCAST(dim) */ f.*
FROM fact_sales f
JOIN dim_product dim
ON f.product_key = dim.product_key
WHERE dim.category = '生鲜';
(2)自适应查询执行(AQE)
配置参数:
spark.sql.adaptive.enabled=true
spark.sql.adaptive.coalescePartitions.enabled=true
spark.sql.adaptive.advisoryPartitionSizeInBytes=128MB
效果:
- 自动合并过小分区
- 动态调整Join策略
- 运行时优化倾斜数据
(1)完整性检查规则
CREATE TEMPORARY VIEW sales_quality AS
SELECT
'fact_sales' AS table_name,
COUNT_IF(transaction_id IS NULL) AS null_transaction_id,
COUNT_IF(amount < 0) AS negative_amount,
COUNT_IF(store_key NOT IN (SELECT store_key FROM dim_store)) AS invalid_store
FROM fact_sales;
/* 阈值设置:
- null_transaction_id < 0.001%
- negative_amount = 0
- invalid_store = 0 */
(2)一致性检查规则
WITH price_diff AS (
SELECT
f.product_key,
AVG(f.unit_price) AS fact_price,
d.standard_price AS dim_price
FROM fact_sales f
JOIN dim_product d ON f.product_key = d.product_key
GROUP BY 1,3
)
SELECT
COUNT_IF(ABS(fact_price - dim_price) > 0.1) AS price_mismatch
FROM price_diff;
(1)血缘追踪实现
-- 使用Apache Atlas的SQL扩展
CREATE TABLE fact_sales (...)
WITH (
'atlas.entity.type'='hive_table',
'atlas.owner'='retail_dw_team'
);
INSERT INTO fact_sales /*+ ATLAS_LINEAGE(source='ods.orders', process='etl_sales') */
SELECT ...;
(2)敏感数据识别
ANALYZE TABLE fact_sales COMPUTE STATISTICS
FOR COLUMNS customer_id, credit_card_no;
/* 自动识别策略:
- 字段名包含'card'、'phone'等关键词
- 数据模式匹配(如信用卡号正则校验)
- 人工打标敏感级别 */
阶段 | 关键任务 | 风险点 | 应对措施 |
---|---|---|---|
需求分析 | 业务过程优先级排序 | 业务方需求频繁变更 | 建立需求冻结机制 |
模型设计 | 维度模型评审 | 模型扩展性不足 | 预留20%冗余字段 |
ETL开发 | 历史数据迁移 | 数据一致性校验耗时 | 开发数据对比工具 |
上线切换 | 双跑验证 | 查询性能不达标 | 提前进行压力测试 |
指标类别 | 基线值 | 目标值 | 测量方法 |
---|---|---|---|
数据新鲜度 | T+1天 | 实时+15分钟延迟 | 监控面板显示数据延迟 |
查询性能 | 复杂查询>30秒 | 95%查询<5秒 | 记录Slow Query Log |
用户满意度 | 60% | 85% | 季度问卷调查 |
下期预告:《库存数仓》
互动话题:你在学习时遇到过哪些坑?欢迎评论区留言讨论!
️温馨提示:我是[随缘而动,随遇而安], 一个喜欢用生活案例讲技术的开发者。如果觉得有帮助,点赞关注不迷路