37-学习笔记尚硅谷数仓搭建-ADS层分析并以各品牌商品下单统计为例

目录

一、ADS层概述与应用场景

[1.1 ADS层定位](#1.1 ADS层定位)

[1.2 设计特点](#1.2 设计特点)

二、建表语句深度解析

[2.1 完整建表语句](#2.1 完整建表语句)

[2.2 字段设计解析](#2.2 字段设计解析)

三、数据装载策略详解

[3.1 整体装载逻辑](#3.1 整体装载逻辑)

设计原因分析:

[3.2 UNION vs UNION ALL选择](#3.2 UNION vs UNION ALL选择)

四、核心SQL代码逐行解析

[4.1 最近1天数据处理](#4.1 最近1天数据处理)

关键函数解析:

[4.2 最近7天和30天数据处理](#4.2 最近7天和30天数据处理)

高级函数详解:

[1. LATERAL VIEW EXPLODE()](#1. LATERAL VIEW EXPLODE())

[2. CASE WHEN表达式](#2. CASE WHEN表达式)

[3. COUNT(DISTINCT IF())](#3. COUNT(DISTINCT IF()))

[4.3 GROUP BY分组原理](#4.3 GROUP BY分组原理)

五、性能优化与最佳实践

[5.1 存储优化](#5.1 存储优化)

[5.2 查询优化技巧](#5.2 查询优化技巧)

六、扩展思考与改进建议

[6.1 可能的问题与解决方案](#6.1 可能的问题与解决方案)

[6.2 监控与维护](#6.2 监控与维护)

七、总结


一、ADS层概述与应用场景

1.1 ADS层定位

ADS(Application Data Store)层是数据仓库的最后层,直接面向业务应用。它存储经过深度聚合和分析的数据,为报表、数据可视化、API服务等提供直接可用的数据。

1.2 设计特点

sql 复制代码
-- 核心设计原则:
-- 1. 行式存储(TSV格式):便于数据导出到MySQL等关系型数据库
-- 2. GZIP压缩:在数据量不大时保证压缩效率
-- 3. 非分区设计:分析结果数据量通常较小
-- 4. 按需建表:客户需要什么字段就创建什么字段

二、建表语句深度解析

2.1 完整建表语句

sql 复制代码
DROP TABLE IF EXISTS ads_order_stats_by_tm;
-- 使用EXTERNAL TABLE确保数据安全,删除表时不删除HDFS数据
CREATE EXTERNAL TABLE ads_order_stats_by_tm
(
    `dt`                      STRING COMMENT '统计日期',
    `recent_days`             BIGINT COMMENT '最近天数,1:最近1天,7:最近7天,30:最近30天',
    `tm_id`                   STRING COMMENT '品牌ID',
    `tm_name`                 STRING COMMENT '品牌名称',
    `order_count`             BIGINT COMMENT '下单数',
    `order_user_count`        BIGINT COMMENT '下单人数'
) COMMENT '各品牌商品下单统计'
    ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'  -- TSV格式,制表符分隔
    LOCATION '/warehouse/gmall/ads/ads_order_stats_by_tm/';

2.2 字段设计解析

字段名 数据类型 说明 设计考虑
dt STRING 统计日期 固定日期格式,便于时间维度分析
recent_days BIGINT 最近天数 支持多时间窗口分析(1/7/30天)
tm_id STRING 品牌ID 业务主键,用于关联
tm_name STRING 品牌名称 便于直接展示,减少关联查询
order_count BIGINT 下单数 核心指标,统计订单数量
order_user_count BIGINT 下单人数 统计独立用户数,反映用户覆盖

三、数据装载策略详解

3.1 整体装载逻辑

sql 复制代码
-- 为什么采用"查询历史数据 + UNION + 新增数据"的模式?
insert overwrite table ads_order_stats_by_tm
select * from ads_order_stats_by_tm  -- 步骤1:先查询历史所有数据
union                                -- 步骤2:UNION去重合并
-- 新增数据计算部分...
设计原因分析:
  1. 容错性考虑:脚本可能因资源不足失败,重新执行时需要保留历史数据

  2. 数据完整性:确保不会因部分失败导致数据丢失

  3. 幂等性设计:支持重复执行,结果一致

3.2 UNION vs UNION ALL选择

sql 复制代码
-- 使用UNION而非UNION ALL的原因:
-- 1. UNION会自动去重,防止重复插入
-- 2. 当脚本重复执行时,避免生成重复记录
-- 3. 虽然性能稍差,但数据量小可接受

-- UNION ALL示例(不去重):
SELECT id FROM table1
UNION ALL  -- 合并所有行,包括重复
SELECT id FROM table2;

-- UNION示例(去重):
SELECT id FROM table1
UNION      -- 合并并去重
SELECT id FROM table2;

四、核心SQL代码逐行解析

4.1 最近1天数据处理

sql 复制代码
select
    1 recent_days,  -- 固定值,表示统计最近1天
    tm_id,
    tm_name,
    sum(order_count_1d) order_count,  -- 聚合函数:对单日订单数求和
    count(distinct(user_id)) order_user_count  -- 去重统计独立用户数
from dws_trade_user_sku_order_1d
where dt='2022-06-08'  -- 筛选特定日期
group by tm_id, tm_name  -- 按品牌分组
关键函数解析:
  • SUM():聚合函数,计算总和

  • COUNT(DISTINCT):统计不重复值的数量

  • GROUP BY:分组子句,配合聚合函数使用

4.2 最近7天和30天数据处理

sql 复制代码
select
    recent_days,
    tm_id,
    tm_name,
    sum(order_count),  -- 对炸裂后的订单数求和
    count(distinct(if(order_count>0,user_id,null)))  -- 条件去重统计
from
(
    select
        recent_days,
        user_id,
        tm_id,
        tm_name,
        case recent_days  -- CASE条件表达式
            when 7 then order_count_7d
            when 30 then order_count_30d
        end order_count
    from dws_trade_user_sku_order_nd 
    lateral view explode(array(7,30)) tmp as recent_days  -- 炸裂函数
    where dt='2022-06-08'
)t1
group by recent_days, tm_id, tm_name
高级函数详解:
1. LATERAL VIEW EXPLODE()
sql 复制代码
-- 原始数据:一行包含7日和30日数据
-- 炸裂后:每个recent_days值生成一行
lateral view explode(array(7,30)) tmp as recent_days

-- 示例:
-- 原始:order_count_7d=100, order_count_30d=500
-- 炸裂后:
-- 行1: recent_days=7, order_count=100
-- 行2: recent_days=30, order_count=500
2. CASE WHEN表达式
sql 复制代码
-- 根据条件返回不同值
case recent_days
    when 7 then order_count_7d
    when 30 then order_count_30d
    else 0  -- 可选的默认值
end

-- 等同于:
if(recent_days=7, order_count_7d, 
   if(recent_days=30, order_count_30d, 0))
3. COUNT(DISTINCT IF())
sql 复制代码
-- 条件去重统计
count(distinct(if(order_count>0, user_id, null)))

-- IF函数:条件成立返回user_id,否则返回null
-- COUNT不统计null值,实现只统计有订单的用户

4.3 GROUP BY分组原理

sql 复制代码
-- 分组规则示例:
group by recent_days, tm_id, tm_name

-- 情况1:上下级关系(如省份-城市)
--   以最细粒度(城市)为基准分组
group by city_id, province_name  -- province_name只作为展示

-- 情况2:关联关系(如用户ID-用户名)
--   以唯一标识(用户ID)为基准
group by user_id, user_name  -- user_name不会影响分组

-- 情况3:无关联字段(如用户ID-商品ID)
--   将两个字段组合作为分组键
group by user_id, product_id  -- 每个组合唯一

五、性能优化与最佳实践

5.1 存储优化

sql 复制代码
-- ADS层存储特点:
-- 1. 行式存储:适合频繁全表扫描的小数据量场景
-- 2. TSV格式:简单高效,兼容性好
-- 3. GZIP压缩:文本压缩率高,查询时自动解压
-- 4. 小文件合并:定期合并减少文件数量

5.2 查询优化技巧

sql 复制代码
-- 1. 使用分区过滤(虽然ADS层通常不分区)
where dt='2022-06-08'

-- 2. 避免全表扫描
create index on ads_order_stats_by_tm(tm_id)  -- 如果支持索引

-- 3. 合理使用统计信息
analyze table ads_order_stats_by_tm compute statistics;

六、扩展思考与改进建议

6.1 可能的问题与解决方案

问题 解决方案 代码示例
数据量增长 增加dt分区 PARTITIONED BY (dt STRING)
查询性能下降 增加索引或物化视图 CREATE INDEX idx_tm ON ...
数据重复风险 使用MERGE语句 MERGE INTO ads_table USING ...

6.2 监控与维护

sql 复制代码
-- 1. 数据质量检查
select count(*) as total_rows,
       count(distinct dt) as date_count,
       min(dt) as earliest_date,
       max(dt) as latest_date
from ads_order_stats_by_tm;

-- 2. 存储空间监控
hdfs dfs -du -h /warehouse/gmall/ads/ads_order_stats_by_tm/

-- 3. 数据新鲜度检查
select max(dt) as latest_load_time
from ads_order_stats_by_tm;

七、总结

ADS层作为数据仓库的最后一公里,其设计需要平衡多个因素:

  • 业务友好性:字段命名直观,符合业务术语

  • 性能考量:针对小数据量优化,快速响应查询

  • 数据一致性:通过合理的装载策略确保数据准确

  • 可维护性:代码清晰,便于理解和修改

通过本例的品牌商品下单统计表,我们可以看到如何将DWS层的明细数据转化为业务可用的聚合指标,这种模式在ADS层设计中具有典型性和代表性。

相关推荐
魔力军6 小时前
Rust学习Day2: 变量与可变性、数据类型和函数和控制流
开发语言·学习·rust
黄大帅@lz6 小时前
openai提示词学习
windows·学习
pop_xiaoli6 小时前
effective-Objective-C 第二章阅读笔记
笔记·学习·ios·objective-c·cocoa
代码游侠6 小时前
复习——Linux设备驱动开发笔记
linux·arm开发·驱动开发·笔记·嵌入式硬件·架构
恣逍信点6 小时前
《凌微经 · 理悖相涵》第七章 形性一体——本然如是之元观
人工智能·科技·学习·程序人生·生活·交友·哲学
stars-he6 小时前
AI工具配置学习笔记
人工智能·笔记·学习
Master_oid6 小时前
机器学习32:机器终生学习(Life Long Learning)
人工智能·学习·机器学习
袁气满满~_~6 小时前
深度学习笔记三
人工智能·笔记·深度学习
我的xiaodoujiao6 小时前
使用 Python 语言 从 0 到 1 搭建完整 Web UI自动化测试学习系列 47--设置Selenium以无头模式运行代码
python·学习·selenium·测试工具·pytest