【黑马甄选离线数仓day07_常见优化手段及核销主题域开发】

news2024/11/28 2:43:02

 1.常见优化手段

1.1 分桶表基本介绍

  • 分桶表:

    • 分文件的, 在创建表的时候, 指定分桶字段, 并设置分多少个桶, 在添加数据的时候, hive会根据设置分桶字段, 将数据划分到N个桶(文件)中, 默认情况采用HASH分桶方案 , 分多少个桶, 取决于建表的时候, 设置分桶数量, 分了多少个桶最终翻译的MR也就会运行多少个reduce程序(HIVE的分桶本质上就是MR的分区操作)

    • 如何构建一个分桶表呢?

create table 表名(
    字段 类型,
    ....
)
clustered by(分桶字段) [sorted by (字段 [asc | desc])] into N buckets   --- 定义分桶表核心语句
row format......
  • 如何向桶表添加数据

load data local inpath  '' into table 表名; -- 不会触发MR hdfs dfs -put

思考:  是否可以通过  load  data 方式添加数据呢? 不行的
    注意: 如果使用 apache 版本的HIVE, 默认情况下, 是可以通过 load data 方式来加载数据. 只不过没有分桶的效果
    
    但是对于 CDH版本中, 是不允许通过 load data 方式来加载的: 
      在CDH中默认开启了一个参数, 禁止采用load data方式向桶表添加数据:  set hive.strict.checks.bucketing = true;
      

如果 现有一个文本文件数据, 需要加载到分桶表,如何解决呢? 
   第一步: 基于桶表创建一张临时表, 此表和桶表保持相同字段, 唯一区别, 当前这个表不是一个桶表
   第二步: 将数据先加载到这个临时表中
   第三步: 基于临时表, 使用 insert into|overwrite + select 将数据添加到桶表
    
  • 桶表有什么用呢?

1) 进行数据采样工作
    1.1) 当表的数据量比较庞大的时候, 在编写SQL语句后, 需要首先测试 SQL是否可以正常的执行,  需要在表中执行查询操作, 由于表数据量比较庞大, 在测试一条SQL的时候整个运行的时间比较久, 为了提升测试效率, 可以整个表抽样出一部分的数据, 进行测试
    1.2) 校验数据的可行性(质量校验)
    1.3) 进行统计分析的时候, 并不需要统计出具体的指标, 可能统计的都是一些相对性指标, 比如说一些比率(合格率)问题, 此时可以通过采样处理
  

2) 提升查询的效率(更主要是提升JOIN的效率)
    可以减少JOIN次数, 从而提升效率
    
注意:
    在生产环境中, 何时使用桶表, 主要看是否需要应用上述作用

1.2 数据采样

采样函数: 
    tablesample(bucket x out of y [on column])
    
使用位置:  紧紧跟在表名的后面, 如果表名有别名, 必须放置别名的前面

说明:
    x: 从第几个桶开始进行采样
    y: 抽样比例
    column: 分桶的字段, 可以省略
   
注意:
    x 不能大于 y
    y 必须是表的分桶数量的倍数或者因子
  

案例: 
    1) 假设 A表有10个桶, 请分析, 下面的采样函数, 会将那些桶抽取出来呢?
        tablesample(bucket 2 out of 5 on xxx) 
        
        会抽取出几个桶数据呢?   总桶数 / 抽样比例 =  分桶数量     2个桶
        抽取那几个桶呢?   (x + y)
            2, 7
    
   2) 假设 A 表有20个桶, 请分析, 下面的抽样函数, 会将那些桶抽取出来呢?
       tablesample(bucket 4 out of 4 on xxx)  
       
       会抽取出几个桶数据呢?  总桶数 / 抽样比例 =  分桶数量   5个桶
       抽取那几个桶呢? 
           4 , 8,12,16,20
           
       tablesample(bucket 8 out of 40 on xxx)  
       
       会抽取出几个桶数据呢? 总桶数 / 抽样比例 =  分桶数量  二分之一个桶
       抽取那几个桶呢?
           8号桶二分之一 
           
   
   大多数情况下, 都是因子, 取某几个桶的操作

1.3 Join优化操作

思考: 在执行Join的SQL的时候, SQL会被翻译为MR, 思考, 翻译后MR默认是如何进行JOIN操作的呢?

思考: 这种reduce端Join操作, 存在那些弊端呢? 
1- 可能会存在数据倾斜的问题 (某几个reduce接收数据量远远大于其他的reduce接收数据量)
2- 所有的数据处理的操作, 全部都压在reduce中进行处理, 而reduce数量相比Map来说少的多,导致整个reduce压力比较大

思考: 如何提升Join的效率呢? 思路: 能否不让reduce做这个聚合处理的事情, 将这项工作尝试交给mapTask

1.3.1 Map Join

Map Join: 每一个mapTask在读取数据的时候, 每读取一条数据, 就会和内存中班级表数据进行匹配, 如果能匹配的上, 将匹配上数据合并在一起, 输出即可

好处: 将原有reduce join 问题全部都可以解决

弊端: 
    1- 比较消耗内存
    2- 要求整个 Join 中, 必须的都有一个小表, 否则无法放入到内存中

仅适用于: 小表 join 大表 | 大表 join 小表   
    在老版本(1.x以下)中, 需要将小表放置在前面, 大表放置在后面, 在新版本中, 无所谓
    建议, 如果明确知道那些表示小表, 可以优先将这些表, 放置在最前面

如何使用呢? 
      set hive.auto.convert.join=true; -- 开启 map join的支持  默认值为True
      set hive.auto.convert.join.noconditionaltask.size=20971520; -- 设置 小表数据量的最大阈值: 默认值为 20971520(20M)

如果不满足条件, HIVE会自动使用 reduce join 操作

1.3.2 Bucket Map Join

  • 适用场景: 中型表 和 大表 join:

    • 方案一: 如果中型表能对数据进行提前过滤, 尽量提前过滤, 过滤后, 有可能满足了Map Join 条件 (并不一定可用)

    • 方案二: Bucket Map Join

使用条件: 
    1- Join两个表必须是分桶表
    2- 开启 Bucket Map Join 支持:  set hive.optimize.bucketmapjoin = true;
    3- 一个表的分桶数量是另一个表的分桶数量的整倍数
    4- 分桶列 必须 是 join的ON条件的列
    5- 必须建立在Map Join场景中

1.3.3 SMB Join

  • 大表 和 大表 join

    • 解决方案: SMB Join ( sort merge bucket map join)

使用条件: 
    1- 两个表必须都是分桶表
    2- 开启 SMB Join 支持:  
        set hive.auto.convert.sortmerge.join=true;
        set hive.optimize.bucketmapjoin.sortedmerge = true;
        set hive.auto.convert.sortmerge.join.noconditionaltask=true;
   3- 两个表的分桶的数量是一致的
   4- 分桶列 必须是 join的 on条件的列, 同时必须保证按照分桶列进行排序操作
       -- 开启强制排序
       set hive.enforce.sorting=true;
       -- 在建分桶表使用: 必须使用sorted by()
  
   5-  应用在Bucket Map Join 场景中
       -- 开启 bucket map join
       set hive.optimize.bucketmapjoin = true;
   
   6- 必须开启HIVE自动尝试使用SMB 方案: 
       set hive.optimize.bucketmapjoin.sortedmerge = true;
       
 
	最终汇总出来整体配置: 
    set hive.auto.convert.join=true;
    set hive.auto.convert.join.noconditionaltask.size=20971520; 
    set hive.optimize.bucketmapjoin = true;
    set hive.auto.convert.sortmerge.join=true;
    set hive.optimize.bucketmapjoin.sortedmerge = true;
    set hive.auto.convert.sortmerge.join.noconditionaltask=true;
    set hive.enforce.sorting=true;
    set hive.optimize.bucketmapjoin.sortedmerge = true;
  
建表:
  create table test_smb_2(mid string,age_id string) CLUSTERED BY(mid) SORTED BY(mid) INTO 500 BUCKETS;
  
 
至于分多少个桶: 取决于表的数据大小 和 小表阈值 之间相差了多少倍

1.4 HIVE的索引

索引有什么用呢? 用于提升查询的效率

为什么说, 索引可以提升查询的效率呢? 思想性

1.4.1 HIVE原始索引(废弃)

	hive的原始索引可以针对某个列, 或者某几列构建索引信息, 构建后提升查询执行列的查询效率
    
    存在弊端: 
        hive原始索引不会自动更新,每次表中数据发生变化后, 都是需要手动重建索引操作, 比较耗费时间和资源, 整体提升性能一般
       
    所以在HIVE3.x版本后, 已经直接将这种索引废弃掉了, 无法使用, 而且官方描述在hive1.x 和 hive2.x版本中, 也不建议优先使用原始索引

1.4.2 Row Group Index索引

row group index: 行组索引

条件: 
    1) 要求表的存储类型为ORC存储格式
    2) 在创建表的时候, 必须开启 row group index 索引支持
        'orc.create.index'='true'
    3) 在插入数据的时候, 必须保证需求进行索引列, 按序插入数据

适用于: 数值类型的, 并且对数值类型进行 >  <  = 操作

思路: 
    插入数据到ORC表后, 会自动进行划分为多个script片段, 每个片段内部, 会保存着每个字段的最小, 最大值, 这样, 当执行查询 > < = 的条件筛选操作的时候, 根据最小最大值锁定相关的script片段, 从而减少数据扫描量, 提升效率
    
操作: 
    CREATE TABLE lxw1234_orc2 (字段列表 ....) stored AS ORC 
    TBLPROPERTIES ( 
      'orc.compress'='SNAPPY', 
      -- 开启行组索引 
      'orc.create.index'='true' 
    )
    插入数据的时候, 需要保证数据有序的
    insert overwrite table lxw1234_orc2
    SELECT  id, pcid FROM lxw1234_text 
    -- 插入的数据保持排序(可以使用全局排序, 也可以使用局部排序, 只需要保证一定有序即可, 建议使用局部排序 插入数据效率高一些, 因为全局排序只有一个reduce) 
    DISTRIBUTE BY id sort BY id;
    
使用: 
    set hive.optimize.index.filter=true; 
    SELECT COUNT(1) FROM lxw1234_orc1 WHERE id >= 1382 AND id <= 1399;

1.4.3 Bloom Fliter Index索引

bloom filter index (布隆过滤索引): 布隆过滤器

条件: 
    1) 要求表的存储类型为 ORC存储方案
    2) 在建表的饿时候, 必须设置为那些列构建布隆索引
    3) 仅能适合于等值过滤查询操作
 
思路: 
    在开启布隆过滤索引后, 可以针对某个列, 或者某几列来建立索引, 构建索引后, 会将这一列的数据的值存储在对应script片段的索引信息中, 这样当进行 等值查询的时候, 首先会到每一个script片段的索引中, 判断是否有这个值, 如果没有, 直接跳过script, 从而减少数据扫描量, 提升效率
    
  
操作:  
    CREATE TABLE lxw1234_orc2 (字段列表....)
    stored AS ORC 
    TBLPROPERTIES ( 
      'orc.compress'='SNAPPY', 
      -- 开启 行组索引 (可选的, 支持全部都打开, 也可以仅开启一个)
      'orc.create.index'='true', 
      -- pcid字段开启BloomFilter索引 
      'orc.bloom.filter.columns'='pcid,字段2,字段3...'
    )
    
    插入数据: 没有要求, 当然如果开启行组索引, 可以将需要使用行组索引的字段, 进行有序插入即可
    
使用:
    SET hive.optimize.index.filter=true; 
    SELECT COUNT(1) FROM lxw1234_orc1 WHERE id >= 0 AND id <= 1000 AND pcid IN ('0005E26F0DCCDB56F9041C','A');

在什么时候可以使用呢?

1- 对于行组索引, 我们建议只要数据存储格式为ORC, 建议将这种索引全部打开, 至于导入数据的时候, 如果能保证有序, 那最好, 如果保证不了, 也无所谓, 大不了这个索引的效率不是特别好

2- 对于布隆过滤索引: 建议将后续会大量的用于等值连接的操作字段, 建立成布隆索引, 比如说: JOIN的字段  经常在where后面出现的等值连接字段

1.5 如何解决数据倾斜问题

1.5.1 Join数据倾斜

在前序讲解reduce 端 JOIN的时候, 描述过reduce 端Join的问题, 其中就包含reduce端Join存在数据倾斜的问题

  • 解决方案一:

可以通过  Map Join  Bucket Map Join   以及  SMB Join 解决
    
注意:  
   通过 Map Join,Bucket Map Join,SMB Join 来解决数据倾斜, 但是 这种操作是存在使用条件的, 如果无法满足这些条件,  无法使用 这种处理方案
  • 解决方案二:

思路:  将那些产生倾斜的key和对应v2的数据, 从当前这个MR中移出去, 单独找一个MR来处理即可, 处理后, 和之前的MR进行汇总结果即可

关键问题:  如何找到那些存在倾斜的key呢?  特点: 这个key数据有很多

运行期处理方案:
    思路: 在执行MR的时候, 会动态统计每一个 k2的值出现重复的次数, 当这个重复的次数达到一定的阈值后, 认为当前这个k2的数据存在数据倾斜, 自动将其剔除, 交由给一个单独的MR来处理即可,两个MR处理完成后, 将结果基于union all 合并在一起即可
    
    实操:  
        set hive.optimize.skewjoin=true;  -- 开启运行期处理倾斜参数
        set hive.skewjoin.key=100000;   -- 阈值,  此参数在实际生产环境中, 需要调整在一个合理的值(否则极易导致大量的key都是倾斜的)
            判断依据: 查看 join的 字段 对应重复的数量有多少个, 然后选择一个合理值
              比如判断:  id为 1  大概有 100w  id为 2 88w  id 为 3 大概有 500w   设置阈值为 大于500w次数据
               或者: 总数量大量1000w, 然后共有 1000个班级, 平均下来每个班级数量大概在 1w条, 设置阈值:  大于 3w条 ~5w条范围 (超过3~5倍才认为倾斜)
        
    
    适用于: 并不清楚那个key容易产生倾斜, 此时交由系统来动态检测

编译期处理方案: 
    思路:  在创建这个表的时候, 我们就可以预知到后续插入到这个表中数据, 那些key的值会产生倾斜, 在建表的时候, 将其提前配置设置好即可, 在后续运行的时候, 程序会自动将设置的key的数据单独找一个MR来进行处理即可, 处理完成后, 再和原有结果进行union all 合并操作
    
    实操:  
        set hive.optimize.skewjoin.compiletime=true;  -- 开启编译期处理倾斜参数
        
        CREATE TABLE list_bucket_single (key STRING, value STRING) 
        -- 倾斜的字段和需要拆分的key值 
        SKEWED BY (key) ON (1,5,6) 
        -- 为倾斜值创建子目录单独存放 
        [STORED AS DIRECTORIES];

    适用于:  提前知道那些key存在倾斜
    
在实际生产环境中, 应该使用那种方式呢?   两种方式都会使用的
    一般来说, 会将两个都开启, 编译期的明确在编译期将其设置好, 编译期不清楚, 通过运行期动态捕获即可

union all 优化方案

 	说明:  不管是运行期 还是编译期的join倾斜解决, 最终都会运行多个MR, 将多个MR结果通过union all 进行汇总, union all也是需要单独一个MR来处理
    
    解决方案: 
        让每一个MR在运行完成后, 直接将结果输出到目的地即可, 默认 是各个MR将结果输出临时目录, 通过 union all 合并到最终目的地
         
        开启此参数即可: 
        set hive.optimize.union.remove=true;

1.5.2 group by 数据倾斜

  • 为什么在group by 的时候, 可能会出现倾斜的问题呢?

假设目前有这么一个表:  

sid       sname    cid
s01       张三     c01
s02       李四     c02
s03       王五     c01
s04       赵六     c03
s05       田七     c02
s06       周八     c01
s07       李九     c01
s08       老王     c04

需求: 请计算每个班级有多少个人
select  cid,count(1) as total  from  stu  group by  cid;

翻译后MR是如何处理SQL呢?

MAP 阶段: 假设Map阶段跑了二个MapTask

mapTask1:
    k2          v2
    c01        {s01       张三     c01}
    c02        {s02       李四     c02}
    c01        {s03       王五     c01}
    c03        {s04       赵六     c03}
mapTask2:
    k2          v2
    c02        {s05       田七     c02}
    c01        {s06       周八     c01}
    c01        {s07       李九     c01}
    c04        {s08       老王     c04}



reduce阶段: 假设reduceTask有二个

reduceTask1: 接收 c01 和 c02的数据
  接收数据
     k2        v2
    c01        {s01       张三     c01}
    c02        {s02       李四     c02}
    c01        {s03       王五     c01}
    c02        {s05       田七     c02}
    c01        {s06       周八     c01}
    c01        {s07       李九     c01}
  
  分组后:
    c01      [{s01       张三     c01},{s03       王五     c01},{s06       周八     c01},{s07       李九     c01}]
    c02      [{s02       李四     c02},{s05       田七     c02}]
   
  结果数据: 
    c01     4
    c02     2
  
reduceTask2: 接收 c03 和 c04的数据
  接收数据
     k2        v2
    c03        {s04       赵六     c03}
    c04        {s08       老王     c04}
   
  分组后:
    c03        [{s04       赵六     c03}]
    c04        [{s08       老王     c04}]
    
  结果数据:
    c03     1
    c04     1

在以上整个计算流程中, 发现 其中一个reduce接收到的数据量比另一个reduce接收的数据量要多的多, 认为出现了数据倾斜的问题, 所以group by 也有可能产生数据倾斜

思考: 如何解决group by的数据倾斜呢?

  • 解决方案一: 基于MR的 combiner(规约, 提前聚合) 减少数据达到reduce数量, 从而减轻倾斜问题

假设目前有这么一个表:  

sid       sname    cid
s01       张三     c01
s02       李四     c02
s03       王五     c01
s04       赵六     c03
s05       田七     c02
s06       周八     c01
s07       李九     c01
s08       老王     c04

需求: 请计算每个班级有多少个人
select  cid,count(1) as total  from  stu  group by  cid;

翻译后MR是如何处理SQL呢?

MAP 阶段: 假设Map阶段跑了二个MapTask
mapTask1:
    k2          v2
    c01        {s01       张三     c01}
    c02        {s02       李四     c02}
    c01        {s03       王五     c01}
    c03        {s04       赵六     c03}
规约(提前聚合)操作: 处理逻辑与reduce处理逻辑一直
  分组: 
     c01    [{s01       张三     c01},{s03       王五     c01}]  
     c02    [{s02       李四     c02}]
     c03    [{s04       赵六     c03}]
  聚合得出结果:
      c01     2
      c02     1
      c03     1
mapTask2:
    k2          v2
    c02        {s05       田七     c02}
    c01        {s06       周八     c01}
    c01        {s07       李九     c01}
    c04        {s08       老王     c04}
规约(提前聚合)操作: 处理逻辑与reduce处理逻辑一直
  分组: 
     c01    [{s06       周八     c01},{s07       李九     c01}]  
     c02    [{s05       田七     c02}]
     c04    [{s08       老王     c04}]
 聚合得出结果:
      c01     2
      c02     1
      c04     1


reduce阶段: 假设reduceTask有二个
reduceTask1: 接收 c01 和 c02的数据
  接收数据
     k2        v2
     c01       2
     c02       1
     c01       2
     c02       1    
  分组后:
    c01      [2,2]
    c02      [1,1]  
  结果数据: 
    c01     4
    c02     2 
reduceTask2: 接收 c03 和 c04的数据
  接收数据
     k2        v2
     c03       1
     c04       1 
  分组后:
    c03        [1]
    c04        [1]
  结果数据:
    c03     1
    c04     1  
  
 通过规约来解决数据倾斜, 处理完成后, 发现 两个reduce中从原来相差 3倍, 变更为相差 2倍, 减轻了数据倾斜问题
 
 
 如何配置呢? 
     只需要在HIVE中开启combiner提前聚合配置参数即可:  
         set hive.map.aggr=true;
  • 方案二: 负载均衡的解决方案(需要运行两个MR来处理) (大combiner方案)

假设目前有这么一个表:  

sid       sname    cid
s01       张三     c01
s02       李四     c02
s03       王五     c01
s04       赵六     c03
s05       田七     c02
s06       周八     c01
s07       李九     c01
s08       老王     c04

需求: 请计算每个班级有多少个人
select  cid,count(1) as total  from  stu  group by  cid;

翻译后MR是如何处理SQL呢?

第一个MR的操作: 对数据进行打散
Map 阶段:  假设运行了两个MapTask
mapTask1:
    k2          v2
    c01        {s01       张三     c01}
    c02        {s02       李四     c02}
    c01        {s03       王五     c01}
    c03        {s04       赵六     c03}
mapTask2:
    k2          v2
    c02        {s05       田七     c02}
    c01        {s06       周八     c01}
    c01        {s07       李九     c01}
    c04        {s08       老王     c04}  

mapTask执行完成后, 在进行分发数据到达reduce, 默认情况下将相同k2的数据发往同一个reduce, 目前采用方案为随机分发, 保证每一个reduce拿到相等数量的数据信息(负载过程, 让每一个reduce接收到相同数量的数据)

reduce阶段: 假设有两个reduceTask

reduceTask1:
    接收到数据:  
        c01        {s01       张三     c01}
        c01        {s03       王五     c01}
        c01        {s06       周八     c01}
        c01        {s07       李九     c01}
    分组操作: 
        c01    [{s01       张三     c01},{s03       王五     c01},{s06       周八     c01},{s07       李九     c01}]     
    输出结果: 
        c01     4
reduceTask2:
    接收到数据:
        c03        {s04       赵六     c03}
        c02        {s05       田七     c02}
        c02        {s02       李四     c02}
        c04        {s08       老王     c04}
    
    分组操作: 
        c03        [{s04       赵六     c03}]
        c02        [{s02       李四     c02},{s05       田七     c02}]
        c04        [{s08       老王     c04}]
     
    输出结果:
        c02     2
        c03     1
        c04     1

第一个MR执行完成了, 每个reduce都接收到四条数据, 自然也就不存在数据倾斜的问题了

第二个MR进行处理:  严格按照相同k2发往同一个reduce

Map 阶段:  假设有二个mapTask
mapTask1:  
    k2      v2
    c01     4
    c02     2
mapTask2:
    k2      v2
    c03     1
    c04     1
reduce阶段:   假设有两个reduce
reduceTask1: 接收 c01 和 c02 数据
  接收数据:  
     k2     v2
     c01     4
     c02     2
  结果:
     c01    4
     c02    2
reduceTask2: 接收 c03 和c04
  接收数据:  
     k2     v2
     c03     1
     c04     1 
  结果:
     c03     1
     c04     1


通过负载均衡方式来解决数据倾斜, 同样也可以减轻数据倾斜的压力


细细发现, 方案一 和 方案二, 是有类似之处的, 方案一, 让每一个mapTask内部进行提前聚合, 然后到达reduce进行汇总合并得出结构, 方案二: 让第一个MR进行打散并对数据进行聚合计算 得出局部结果, 然后让第二个MR进行最终聚合计算操作, 得出最终结果


说明: 方案二, 比方案一, 更能彻底解决数据倾斜问题, 因为其处理数据范围更大, 整个整个数据集来处理, 而方案一, 只是每个MapTask处理, 仅仅局部处理

如何使用方案二: 
    只需要开启负载均衡的HIVE参数配置即可:
        set hive.groupby.skewindata=true;

这两种方式:  建议在生产中, 优先使用第一种, 如果第一种无法解决, 尝试使用第二种解决


注意事项:   使用第二种负载均衡的解决group by 的数据倾斜, 一定要注意, SQL语句中不能出现多次  distinct操作, 否则 HIVE会直接报错的
    错误信息: 
        Error in semantic analysis: DISTINCT on different columns not supported with skew in data.
    比如说: 
        SELECT ip, count(DISTINCT uid), count(DISTINCT uname) FROMlog GROUP BY ip   此操作就直接报错了,只能使用方案一解决数据倾斜

倾斜的参数配置开启条件, 一定是出现了数据倾斜的问题, 如果没有出现 不需要开启的

思考: 如何才能知道发生了数据倾斜呢?

 倾斜发生后, 出现的问题, 程序迟迟无法结束, 或者说翻译的MR中reduceTask有多个, 大部分的reduceTask都执行完成了, 只有其中一个或者几个没有执行完成, 此时认为发生了数据倾斜
    
    
    关键点: 如何查看每一个reduceTask执行时间
  • 方式: 通过Yarn查看(运行过程中) 或者 jobhistory查看(已经结束的程序) (此操作, 只能在本地演示查看, 云端环境没有开启yarn端口, 无法查看的)

运行的时候点击:

目前, 我们这里可能只有一个reduce, 但是实际上生产环境中, 此位置可能会有多个reduceTask, 我们需要观察每个reduceTask执行时间, 如果发现其中一个或者几个reduce执行时间, 远远大于其他的reduceTask执行时间, 那么说明存在数据倾斜的问题

如果程序以及运行完成了, 想查看刚刚运行的各个reduceTask时间: 使用jobHistory

点击对应需要查看的任务:

点击reduce进入:

2.核销主题_DWS和ADS层

2.1 DWS开发

门店商品分析刻表: dws_goods_store_goods_statistics_quarter_i
门店经营分析刻表: dws_store_manage_statistics_quarter_i

注意:具体计算只计算增量,全量计算直接去掉where条件即可。或者在调度时使用补数的方法,将历史分区一天一天跑出来即可!

2.1.1 门店商品分析刻表

构建一张DWS层的大宽表,包含销售、损耗、收货、要货等信息。维度字段,包含4张DWM表中的共有字段;指标字段,包含需求中所要求的字段以及拓展的字段。

将四张dwm层的表进行合并即可。需要注意的是,要先进行初步聚合,再去union all,可以提高计算效率。

指标:
    销售单量,销售数量,销售金额
    折扣金额
    销售成本
    余额支付金额
    取消商品销售金额
    退款商品销售金额
    线上单量,线下单量,线上销售数量,线下销售数量
    线上销售金额,线下销售金额,线上销售成本,线下销售成本
    损耗数量,损耗金额
    收货数量,收货金额
    要货数量,要货金额
​
维度(最细粒度):
    时间维度(粒度到刻), 门店维度, 商品维度

建表语句
CREATE TABLE IF NOT EXISTS dws.dws_goods_store_goods_statistics_quarter_i(
    trade_date                  STRING COMMENT '交易日期',
    week_trade_date             STRING COMMENT '周一日期',
    month_trade_date            STRING COMMENT '月一日期',
    hourly                      BIGINT COMMENT '交易小时(0-23)',
    quarter                     BIGINT COMMENT '刻钟:1.0-15,2.15-30,3.30-45,4.45-60',
    quarters                    BIGINT COMMENT '刻钟数:hourly*4+quarters',
​
    store_no                    STRING COMMENT '店铺编码',
    store_name                  STRING COMMENT '店铺名称',
    store_sale_type             BIGINT COMMENT '店铺销售类型',
    store_type_code             BIGINT COMMENT '分店类型',
    worker_num                  BIGINT COMMENT '员工人数',
    store_area                  DECIMAL(27, 2) COMMENT '门店面积',
    city_id                     BIGINT COMMENT '城市ID',
    city_name                   STRING COMMENT '城市名称',
    region_code                 STRING COMMENT '区域编码',
    region_name                 STRING COMMENT '区域名称',
    is_day_clear                BIGINT COMMENT '是否日清:0否,1是',
​
    first_category_no           STRING COMMENT '一级分类编码',
    first_category_name         STRING COMMENT '一级分类名称',
    second_category_no          STRING COMMENT '二级分类编码',
    second_category_name        STRING COMMENT '二级分类名称',
    third_category_no           STRING COMMENT '三级分类编码',
    third_category_name         STRING COMMENT '三级分类名称',
    goods_no                    STRING COMMENT '商品编码',
    goods_name                  STRING COMMENT '商品名称',
    is_clean                    BIGINT COMMENT '商品是否日清:0否,1是',
​
    order_num                   BIGINT COMMENT '销售单量',
    sale_qty                    DECIMAL(27, 3) COMMENT '销售数量',
    sale_amount                 DECIMAL(27, 2) COMMENT '销售金额',
    dis_amount                  DECIMAL(27, 2) COMMENT '折扣金额',
    sale_cost                   DECIMAL(27, 2) COMMENT '销售成本',
    balance_amount              DECIMAL(27, 2) COMMENT '余额支付金额',
    cancel_sale_amount          DECIMAL(27, 2) COMMENT '取消商品销售金额',
    refund_sale_amount          DECIMAL(27, 2) COMMENT '退款商品销售金额',
    online_order_num            BIGINT COMMENT '线上单量',
    offline_order_num           BIGINT COMMENT '线下单量',
    online_sale_qty             DECIMAL(27, 3) COMMENT '线上销售数量',
    offline_sale_qty            DECIMAL(27, 3) COMMENT '线下销售数量',
    online_sale_amount          DECIMAL(27, 2) COMMENT '线上销售金额',
    offline_sale_amount         DECIMAL(27, 2) COMMENT '线下销售金额',
    online_sale_cost            DECIMAL(27, 2) COMMENT '线上销售成本',
    offline_sale_cost           DECIMAL(27, 2) COMMENT '线下销售成本',
    loss_qty                    DECIMAL(27, 3) COMMENT '损耗数量',
    loss_amount                 DECIMAL(27, 2) COMMENT '损耗金额',
    receipt_qty                 DECIMAL(27, 3) COMMENT '收货数量',
    receipt_amount              DECIMAL(27, 2) COMMENT '收货金额(收货-退货-退配+调入-调出)',
    require_qty                 DECIMAL(27, 3) COMMENT '要货数量',
    require_amount              DECIMAL(27, 2) COMMENT '要货金额'
)
COMMENT '门店商品分析刻表'
partitioned by(dt STRING COMMENT '统计时间')
row format delimited fields terminated by ','
stored as orc
tblproperties ('orc.compress'='SNAPPY');
数据插入
-- DWS层: 门店 商品的分析刻表
​
-- 第一步: 先计算销售相关的数据
-- 第二步 计算 损耗数量 和 损耗金额
-- 第三步: 收货数量 和 收货金额
-- 第四步: 要货数量 和 要货金额
-- 第五步: 进行合并  FULL JOIN  / Union all 均可以
with t1 as (
    -- 第一步: 先计算销售相关的数据
    select
        -- 时间维度
        trade_date,
        week_trade_date,
        month_trade_date,
        hourly,
        quarter,
        quarters,
        -- 门店维度
        store_no,
        store_name,
        store_sale_type,
        store_type_code,
        worker_num,
        store_area,
        city_id,
        city_name,
        region_code,
        region_name,
        is_day_clear,
        -- 商品维度
        first_category_no,
        first_category_name,
        second_category_no,
        second_category_name,
        third_category_no,
        third_category_name,
        goods_no,
        goods_name,
        is_clean,
        -- 指标
        -- 销售单量/数量/金额
        count( if(trade_type = 0,parent_order_no,null)) - count(if(trade_type = 5,parent_order_no,null)) as order_num,
        sum(sale_qty) as sale_qty,
        sum(sale_amount) as sale_amount,
        -- 折扣金额
        sum(dis_amount) as dis_amount,
        -- 销售成本
        sum(sale_cost) as sale_cost,
        -- 余额支付金额
        sum(if(is_balance_consume = 1,balance_amount,0)) as balance_amount,
        -- 取消商品销售金额
        sum(if(trade_type = 5,sale_amount,0)) as cancel_sale_amount,
        -- -- 退款商品销售金额
        sum(if(trade_type = 2,sale_amount,0)) as refund_sale_amount,
        -- -- 线上线下单量
        count( if(trade_type = 0 and is_online_order = 1,parent_order_no,null)) - count(if(trade_type = 5 and is_online_order = 1,parent_order_no,null)) as online_order_num,
        count( if(trade_type = 0 and is_online_order = 0,parent_order_no,null)) - count(if(trade_type = 5 and is_online_order = 0,parent_order_no,null)) as offline_order_num,
        -- -- 线上线下销售数量
        sum(if(is_online_order = 1,sale_qty,0)) as online_sale_qty,
        sum(if(is_online_order = 0,sale_qty,0))  as offline_sale_qty,
        -- -- 线上线下销售金额
        sum(if(is_online_order = 1,sale_amount,0)) as online_sale_amount,
        sum(if(is_online_order = 0,sale_amount,0))  as offline_sale_amount,
        -- 线上线下销售成本
        sum(if(is_online_order = 1,sale_cost,0)) as online_sale_cost,
        sum(if(is_online_order = 0,sale_cost,0))  as offline_sale_cost,
        0 as loss_qty,
        0 as loss_amount,
        0 as receipt_qty,
        0 as receipt_amount,
        0 as require_qty,
        0 as require_amount
    from dwm.dwm_sold_goods_sold_dtl_i
    group by
        -- 时间维度
        trade_date,
        week_trade_date,
        month_trade_date,
        hourly,
        quarter,
        quarters,
        -- 门店维度
        store_no,
        store_name,
        store_sale_type,
        store_type_code,
        worker_num,
        store_area,
        city_id,
        city_name,
        region_code,
        region_name,
        is_day_clear,
        -- 商品维度
        first_category_no,
        first_category_name,
        second_category_no,
        second_category_name,
        third_category_no,
        third_category_name,
        goods_no,
        goods_name,
        is_clean
    union all
    -- 第二步 计算 损耗数量 和 损耗金额
    select
        -- 时间维度
        trade_date,
        week_trade_date,
        month_trade_date,
        hourly,
        quarter,
        quarters,
        -- 门店维度
        store_no,
        store_name,
        store_sale_type,
        store_type_code,
        worker_num,
        store_area,
        city_id,
        city_name,
        region_code,
        region_name,
        is_day_clear,
        -- 商品维度
        first_category_no,
        first_category_name,
        second_category_no,
        second_category_name,
        third_category_no,
        third_category_name,
        goods_no,
        goods_name,
        is_clean,
        0 as order_num,
        0 as sale_qty,
        0 as sale_amount,
        0 as dis_amount,
        0 as sale_cost,
        0 as balance_amount,
        0 as cancel_sale_amount,
        0 as refund_sale_amount,
        0 as online_order_num,
        0 as offline_order_num,
        0 as online_sale_qty,
        0 as offline_sale_qty,
        0 as online_sale_amount,
        0 as offline_sale_amount,
        0 as online_sale_cost,
        0 as offline_sale_cost,
        sum(loss_qty) as loss_qty,
        sum(loss_amount) as loss_amount,
        0 as receipt_qty,
        0 as receipt_amount,
        0 as require_qty,
        0 as require_amount
    from dwm.dwm_stock_store_goods_loss_quarter_i
    group by
        -- 时间维度
        trade_date,
        week_trade_date,
        month_trade_date,
        hourly,
        quarter,
        quarters,
        -- 门店维度
        store_no,
        store_name,
        store_sale_type,
        store_type_code,
        worker_num,
        store_area,
        city_id,
        city_name,
        region_code,
        region_name,
        is_day_clear,
        -- 商品维度
        first_category_no,
        first_category_name,
        second_category_no,
        second_category_name,
        third_category_no,
        third_category_name,
        goods_no,
        goods_name,
        is_clean
    union all
​
    -- 第三步: 收货数量 和 收货金额
    select
        -- 时间维度
        trade_date,
        week_trade_date,
        month_trade_date,
        hourly,
        quarter,
        quarters,
        -- 门店维度
        store_no,
        store_name,
        store_sale_type,
        store_type_code,
        worker_num,
        store_area,
        city_id,
        city_name,
        region_code,
        region_name,
        is_day_clear,
        -- 商品维度
        first_category_no,
        first_category_name,
        second_category_no,
        second_category_name,
        third_category_no,
        third_category_name,
        goods_no,
        goods_name,
        is_clean,
        0 as order_num,
        0 as sale_qty,
        0 as sale_amount,
        0 as dis_amount,
        0 as sale_cost,
        0 as balance_amount,
        0 as cancel_sale_amount,
        0 as refund_sale_amount,
        0 as online_order_num,
        0 as offline_order_num,
        0 as online_sale_qty,
        0 as offline_sale_qty,
        0 as online_sale_amount,
        0 as offline_sale_amount,
        0 as online_sale_cost,
        0 as offline_sale_cost,
        0 as loss_qty,
        0 as loss_amount,
        sum(receipt_qty) as receipt_qty,
        sum(receipt_amount) as receipt_amount,
        0 as require_qty,
        0 as require_amount
    from dwm.dwm_order_store_goods_receipt_quarter_i
    group by
        -- 时间维度
        trade_date,
        week_trade_date,
        month_trade_date,
        hourly,
        quarter,
        quarters,
        -- 门店维度
        store_no,
        store_name,
        store_sale_type,
        store_type_code,
        worker_num,
        store_area,
        city_id,
        city_name,
        region_code,
        region_name,
        is_day_clear,
        -- 商品维度
        first_category_no,
        first_category_name,
        second_category_no,
        second_category_name,
        third_category_no,
        third_category_name,
        goods_no,
        goods_name,
        is_clean
    union all
    -- 第四步: 要货数量 和 要货金额
    select
        -- 时间维度
        trade_date,
        week_trade_date,
        month_trade_date,
        hourly,
        quarter,
        quarters,
        -- 门店维度
        store_no,
        store_name,
        store_sale_type,
        store_type_code,
        worker_num,
        store_area,
        city_id,
        city_name,
        region_code,
        region_name,
        is_day_clear,
        -- 商品维度
        first_category_no,
        first_category_name,
        second_category_no,
        second_category_name,
        third_category_no,
        third_category_name,
        goods_no,
        goods_name,
        is_clean,
        0 as order_num,
        0 as sale_qty,
        0 as sale_amount,
        0 as dis_amount,
        0 as sale_cost,
        0 as balance_amount,
        0 as cancel_sale_amount,
        0 as refund_sale_amount,
        0 as online_order_num,
        0 as offline_order_num,
        0 as online_sale_qty,
        0 as offline_sale_qty,
        0 as online_sale_amount,
        0 as offline_sale_amount,
        0 as online_sale_cost,
        0 as offline_sale_cost,
        0 as loss_qty,
        0 as loss_amount,
        0 as receipt_qty,
        0 as receipt_amount,
        sum(require_qty) as require_qty,
        sum(require_amount) as require_amount
    from dwm.dwm_order_store_goods_require_quarter_i
    group by
        -- 时间维度
        trade_date,
        week_trade_date,
        month_trade_date,
        hourly,
        quarter,
        quarters,
        -- 门店维度
        store_no,
        store_name,
        store_sale_type,
        store_type_code,
        worker_num,
        store_area,
        city_id,
        city_name,
        region_code,
        region_name,
        is_day_clear,
        -- 商品维度
        first_category_no,
        first_category_name,
        second_category_no,
        second_category_name,
        third_category_no,
        third_category_name,
        goods_no,
        goods_name,
        is_clean
)
insert overwrite table dws.dws_goods_store_goods_statistics_quarter_i partition (dt)
select
    -- 时间维度
    trade_date,
    week_trade_date,
    month_trade_date,
    hourly,
    quarter,
    quarters,
    -- 门店维度
    store_no,
    store_name,
    store_sale_type,
    store_type_code,
    worker_num,
    store_area,
    city_id,
    city_name,
    region_code,
    region_name,
    is_day_clear,
    -- 商品维度
    first_category_no,
    first_category_name,
    second_category_no,
    second_category_name,
    third_category_no,
    third_category_name,
    goods_no,
    goods_name,
    is_clean,
    sum(order_num) as order_num ,
    cast(sum(sale_qty) as decimal(27,3)) as sale_qty ,
    cast(sum(sale_amount) as decimal(27,2)) as sale_amount ,
    cast(sum(dis_amount) as decimal(27,2)) as dis_amount ,
    cast(sum(sale_cost) as decimal(27,2)) as sale_cost ,
    cast(sum(balance_amount) as decimal(27,2)) as balance_amount ,
    cast(sum(cancel_sale_amount) as decimal(27,2)) as cancel_sale_amount ,
    cast(sum(refund_sale_amount) as decimal(27,2)) as refund_sale_amount ,
    sum(online_order_num)as online_order_num ,
    sum(offline_order_num) as offline_order_num ,
    cast(sum(online_sale_qty) as decimal(27,3)) as online_sale_qty ,
    cast(sum(offline_sale_qty) as decimal(27,3)) as offline_sale_qty ,
    cast(sum(online_sale_amount) as decimal(27,2)) as online_sale_amount ,
    cast(sum(offline_sale_amount) as decimal(27,2)) as offline_sale_amount ,
    cast(sum(online_sale_cost) as decimal(27,2)) as online_sale_cost ,
    cast(sum(offline_sale_cost) as decimal(27,2)) as offline_sale_cost ,
    cast(sum(loss_qty) as decimal(27,3)) as loss_qty ,
    cast(sum(loss_amount) as decimal(27,2)) as loss_amount ,
    cast(sum(receipt_qty) as decimal(27,3)) as receipt_qty ,
    cast(sum(receipt_amount) as decimal(27,2)) as receipt_amount ,
    cast(sum(require_qty) as decimal(27,3)) as require_qty ,
    cast(sum(require_amount)as decimal(27,2)) as require_amount,
    trade_date as dt
from t1
group by
    -- 时间维度
    trade_date,
    week_trade_date,
    month_trade_date,
    hourly,
    quarter,
    quarters,
    -- 门店维度
    store_no,
    store_name,
    store_sale_type,
    store_type_code,
    worker_num,
    store_area,
    city_id,
    city_name,
    region_code,
    region_name,
    is_day_clear,
    -- 商品维度
    first_category_no,
    first_category_name,
    second_category_no,
    second_category_name,
    third_category_no,
    third_category_name,
    goods_no,
    goods_name,
    is_clean;

2.1.2 门店经营分析刻表

构建一张DWS层的大宽表,包含维度字段,以及销售、损耗、收货、要货、会员、支付等全部指标。

指标:
    销售单量,销售数量,销售金额
    折扣金额
    销售成本
    余额支付金额
    取消商品销售金额
    退款商品销售金额
    线上单量,线下单量
    线上销售金额,线下销售金额,线上销售成本,线下销售成本
    损耗金额
    收货金额
    要货金额
    
    线上会员单量,实体卡会员单量
    线上会员销售金额,实体卡会员销售金额
    线上会员销售成本,实体卡会员销售成本
    线上会员下单人数,实体卡会员下单人数
    使用余额销售金额,使用余额单量,使用余额的销售成本,使用余额的下单人数
    
维度:
    时间维度(粒度到刻), 门店维度
​

建表语句
CREATE TABLE IF NOT EXISTS dws.dws_store_manage_statistics_quarter_i(
    trade_date          STRING COMMENT '交易日期',
    week_trade_date     STRING COMMENT '周一日期',
    month_trade_date    STRING COMMENT '月一日期',
    hourly              BIGINT COMMENT '交易小时(0-23)',
    quarter             BIGINT COMMENT '刻钟:1.0-15,2.15-30,3.30-45,4.45-60',
    quarters            BIGINT COMMENT '刻钟数:hourly*4+quarters',
​
    store_no            STRING COMMENT '店铺编码',
    store_name          STRING COMMENT '店铺名称',
    store_sale_type     BIGINT COMMENT '店铺销售类型',
    store_type_code     BIGINT COMMENT '分店类型',
    worker_num          BIGINT COMMENT '员工人数',
    store_area          DECIMAL(27, 2) COMMENT '门店面积',
    city_id             BIGINT COMMENT '城市ID',
    city_name           STRING COMMENT '城市名称',
    region_code         STRING COMMENT '区域编码',
    region_name         STRING COMMENT '区域名称',
    is_day_clear        BIGINT COMMENT '是否日清:0否,1是',
​
    order_num           BIGINT COMMENT '销售单量',
    sale_qty            DECIMAL(27, 3) COMMENT '销售数量',
    sale_amount         DECIMAL(27, 2) COMMENT '销售金额',
    dis_amount          DECIMAL(27, 2) COMMENT '折扣金额',
    sale_cost           DECIMAL(27, 2) COMMENT '销售成本',
    balance_amount      DECIMAL(27, 2) COMMENT '余额支付金额',
    cancel_sale_amount  DECIMAL(27, 2) COMMENT '取消商品销售金额',
    refund_sale_amount  DECIMAL(27, 2) COMMENT '退款商品销售金额',
    online_order_num    BIGINT COMMENT '线上单量',
    offline_order_num   BIGINT COMMENT '线下单量',
    online_sale_amount  DECIMAL(27, 2) COMMENT '线上销售金额',
    offline_sale_amount DECIMAL(27, 2) COMMENT '线下销售金额',
    online_sale_cost    DECIMAL(27, 2) COMMENT '线上销售成本',
    offline_sale_cost   DECIMAL(27, 2) COMMENT '线下销售成本',
    loss_amount         DECIMAL(27, 2) COMMENT '损耗金额',
    receipt_amount      DECIMAL(27, 2) COMMENT '收货金额(收货-退货-退配+调入-调出)',
    require_amount      DECIMAL(27, 2) COMMENT '要货金额',
​
    ol_mem_order_num    BIGINT COMMENT '线上会员单量',
    vip_mem_order_num   BIGINT COMMENT '实体卡会员单量',
    ol_mem_sale_amount  DECIMAL(27, 2) COMMENT '线上会员销售金额',
    vip_mem_sale_amount DECIMAL(27, 2) COMMENT '实体卡会员销售金额',
    ol_mem_sale_cost    DECIMAL(27, 2) COMMENT '线上会员销售成本',
    vip_mem_sale_cost   DECIMAL(27, 2) COMMENT '实体卡会员销售成本',
    ol_mem_trade_num    BIGINT COMMENT '线上会员下单人数',
    vip_mem_trade_num   BIGINT COMMENT '实体卡会员下单人数',
​
    balance_sale_amount DECIMAL(27, 2) COMMENT '使用余额销售金额',
    balance_order_num   BIGINT COMMENT '使用余额单量',
    balance_sale_cost   DECIMAL(27, 2) COMMENT '使用余额的销售成本',
    balance_people_num  BIGINT COMMENT '使用余额的下单人数'
)
COMMENT '门店经营分析刻表'
partitioned by(dt STRING COMMENT '统计时间')
row format delimited fields terminated by ','
stored as orc
tblproperties ('orc.compress'='SNAPPY');

需求说明:

销售、损耗、收货、要货指标从dws_goods_store_goods_statistics_quarter_i中汇总可得。
​
计算会员指标和余额支付指标其实就是筛选,从dwm_sold_goods_sold_dtl_i表中,count()和sum()符合条件的数值即可。
​
计算订单量 = 正常交易的订单 - 取消交易的订单,其中正常交易 trade_type=0, 取消交易 trade_type=5,用parent_order_no来计数。
​
is_online_order用来判断是否是线上,1线上,0线下
​
member_type用来判断会员类型, 0非会员,1线上会员,2实体卡会员
数据插入
-- 第一步: 先将之前已经算过的指标进行上卷统计得到新的结果
-- 第二步: 计算会员以及其他的指标
-- 第三步: 用第一张表 left join 第二张表即可
with t1 as (
    select
        -- 时间维度
        trade_date,
        week_trade_date,
        month_trade_date,
        hourly,
        quarter,
        quarters,
        -- 门店维度
        store_no,
        store_name,
        store_sale_type,
        store_type_code,
        worker_num,
        store_area,
        city_id,
        region_code,
        city_name,
        region_name,
        is_day_clear,
​
        sum(order_num) as order_num,
        sum(sale_qty) as sale_qty,
        sum(sale_amount) as sale_amount,
        sum(dis_amount) as dis_amount,
        sum(sale_cost) as sale_cost,
        sum(balance_amount) as balance_amount,
        sum(cancel_sale_amount) as cancel_sale_amount,
        sum(refund_sale_amount) as refund_sale_amount,
        sum(online_order_num) as online_order_num,
        sum(offline_order_num) as offline_order_num,
        sum(online_sale_amount) as online_sale_amount,
        sum(offline_sale_amount) as offline_sale_amount,
        sum(online_sale_cost) as online_sale_cost,
        sum(offline_sale_cost) as offline_sale_cost,
        sum(loss_amount) as loss_amount,
        sum(receipt_amount) as receipt_amount,
        sum(require_amount) as require_amount
​
    from dws.dws_goods_store_goods_statistics_quarter_i
    group by
        -- 时间维度
        trade_date,
        week_trade_date,
        month_trade_date,
        hourly,
        quarter,
        quarters,
        -- 门店维度
        store_no,
        store_name,
        store_sale_type,
        store_type_code,
        worker_num,
        store_area,
        city_id,
        region_code,
        city_name,
        region_name,
        is_day_clear
),
t2 as (
    select
        -- 时间维度
        trade_date,
        week_trade_date,
        month_trade_date,
        hourly,
        quarter,
        quarters,
        -- 门店维度
        store_no,
        store_name,
        store_sale_type,
        store_type_code,
        worker_num,
        store_area,
        city_id,
        region_code,
        city_name,
        region_name,
        is_day_clear,
​
        count( if( trade_type = 0 and member_type = 1,parent_order_no,null)) - count( if( trade_type = 5 and member_type = 1,parent_order_no,null)) as ol_mem_order_num,
        count( if( trade_type = 0 and member_type = 2,parent_order_no,null)) - count( if( trade_type = 5 and member_type = 2,parent_order_no,null)) as vip_mem_order_num,
        sum( if( member_type = 1,sale_amount,0)) as ol_mem_sale_amount,
        sum( if( member_type = 2,sale_amount,0)) as vip_mem_sale_amount,
        sum( if( member_type = 1,sale_cost,0)) as ol_mem_sale_cost,
        sum( if( member_type = 2,sale_cost,0)) as vip_mem_sale_cost,
        count(distinct if(member_type = 1 and trade_type = 0, member_id,null)) as ol_mem_trade_num,
        count(distinct if(member_type = 2 and trade_type = 0, member_id,null)) as vip_mem_trade_num,
        sum(if(is_balance_consume = 1,balance_amount,0) ) as balance_sale_amount,
        count(if(is_balance_consume = 1 and trade_type = 0,parent_order_no,null)) - count(if(is_balance_consume = 1 and trade_type = 5,parent_order_no,null)) as balance_order_num,
        sum(if(is_balance_consume = 1,sale_cost,0) ) as balance_sale_cost,
        count(distinct if(is_balance_consume = 1 and trade_type = 0,member_id,null)) as balance_people_num
    from dwm.dwm_sold_goods_sold_dtl_i
    group by
        -- 时间维度
        trade_date,
        week_trade_date,
        month_trade_date,
        hourly,
        quarter,
        quarters,
        -- 门店维度
        store_no,
        store_name,
        store_sale_type,
        store_type_code,
        worker_num,
        store_area,
        city_id,
        region_code,
        city_name,
        region_name,
        is_day_clear
)
insert overwrite table dws.dws_store_manage_statistics_quarter_i partition (dt)
select
    -- 时间维度
    t1.trade_date,
    t1.week_trade_date,
    t1.month_trade_date,
    t1.hourly,
    t1.quarter,
    t1.quarters,
    -- 门店维度
    t1.store_no,
    t1.store_name,
    t1.store_sale_type,
    t1.store_type_code,
    t1.worker_num,
    t1.store_area,
    t1.city_id,
    t1.region_code,
    t1.city_name,
    t1.region_name,
    t1.is_day_clear,
​
    t1.order_num,
    t1.sale_qty,
    t1.sale_amount,
    t1.dis_amount,
    t1.sale_cost,
    t1.balance_amount,
    t1.cancel_sale_amount,
    t1.refund_sale_amount,
    t1.online_order_num,
    t1.offline_order_num,
    t1.online_sale_amount,
    t1.offline_sale_amount,
    t1.online_sale_cost,
    t1.offline_sale_cost,
    t1.loss_amount,
    t1.receipt_amount,
    t1.require_amount,
​
    t2.ol_mem_order_num,
    t2.vip_mem_order_num,
    t2.ol_mem_sale_amount,
    t2.vip_mem_sale_amount,
    t2.ol_mem_sale_cost,
    t2.vip_mem_sale_cost,
    t2.ol_mem_trade_num,
    t2.vip_mem_trade_num,
    t2.balance_sale_amount,
    t2.balance_order_num,
    t2.balance_sale_cost,
    t2.balance_people_num,
    t1.trade_date as dt
from t1 left join t2 on t1.trade_date = t2.trade_date and t1.quarters = t2.quarters and t1.store_no = t2.store_no

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1266596.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

内衣洗衣机和手洗哪个干净?小型洗衣机质量排名

这两年内衣洗衣机可以称得上较火的小电器&#xff0c;小小的身躯却有大大的能力&#xff0c;一键可以同时启动洗、漂、脱三种全自动为一体化功能&#xff0c;在多功能和性能的提升上&#xff0c;还可以解放我们双手的同时将衣物给清洗干净&#xff0c;让越来越多小伙伴选择一款…

基于Webserver的工业数据采集控制小项目

主要用到的知识点&#xff0c;http协议&#xff0c;modbus协议&#xff0c;以及进程间通信&#xff0c;消息队列&#xff0c;共享内存等 框架 数据采集 #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #…

C#常用运算符的优先级

前言 运算符在C#编程语言中扮演着重要的角色&#xff0c;用于执行各种计算和操作。了解运算符的优先级是编写高效和正确代码的关键。本文将深入探讨C#中38个常用运算符的优先级划分和理解&#xff0c;并提供详细的说明和示例&#xff0c;以帮助读者更好地理解运算符的使用。 目…

linux设置主机名

查看主机名&#xff1a;hostname 临时修改主机名&#xff1a;hostname 新主机名 [rootlocalhost ~]#hostname centos [rootlocalhost ~]#hostname centos 永久修改主机名&#xff1a; [rootlocalhost ~]#cat /etc/hostname localhost.localdomain

C++ day42背包理论基础01 + 滚动数组

背包问题的重中之重是01背包 01背包 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 每一件物品其实只有两个状态&#xff0c;取或者不…

AI技术如何助力实现智慧交通

人工智能的常见优势在于能够实时、高效地分析处理大量的数据&#xff0c;并结合算法模型提供个性化、专业化的服务。在智慧交通方面&#xff0c;人工智能同样可以发挥专长&#xff0c;助力打造智能高效的交通运输网络&#xff0c;本篇就为大家简单介绍一下AI技术如何促进智慧交…

多平台小程序编译适配,是否会让更多App互联互通?

随着科技的飞速发展&#xff0c;我们正迅速进入一个以数字化为主导的时代。 在这个时代中&#xff0c;通信、小程序、快应用、云服务器等平台连接类软件如火如荼的发展&#xff0c;手机、手表、AR/VR眼镜等智能移动穿戴设备迅速的升级迭代&#xff0c;5G、芯片、算力等基础设施…

Python财经股票数据保存表格文件 <雪球网>

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 环境使用: Python 3.10 解释器 Pycharm 编辑器 &#x1f447; &#x1f447; &#x1f447; 更多精彩机密、教程&#xff0c;尽在下方&#xff0c;赶紧点击了解吧~ python源码、视频教程、插件安装教程、资料我都准备好了&…

天软高频时序数据仓库

1天软高频时序数仓方案架构 天软高频时序数据仓库是深圳天软科技开发有限公司专为金融用户提供的专业高频行情数据处理方案&#xff0c;集数据接入、检查、处理、存储、查询、订阅、计算于一体。 方案支持各类系统的实时行情、非实时行情接入&#xff1b;还支持压缩存储、分布式…

Kubernetes Dashboard 涉及的一些常规技巧

Kubernetes Dashboard 提供了一个GUI形式的K8S集群管理工具&#xff0c;通过它我们能很容易的观察到集群资源消耗情况、服务器运行状态以及针对Pod的相关观察与操作&#xff1b; Dashboard 的相关配置 Dashboard 提供了通过配置启动命令行参数来控制其相关行为的能力&#xf…

知识工作者,需要填报工时么? | IDCF

作者&#xff1a;冬哥 来源&#xff1a;DevOps 引 子 “知识工作者&#xff0c;需要填报工时么&#xff1f;”忘记是因为什么&#xff0c;突然想到这个话题。似乎是没什么值得讨论的话题&#xff0c;我们的观点也是旗帜鲜明地认为没有必要&#xff0c;但实际现实中填报工时似…

游戏开发原画的设计方法

游戏原画设计是游戏开发中至关重要的一环&#xff0c;因为它直接影响到游戏的视觉吸引力和用户体验。以下是一些常见的游戏原画设计方法&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 理解游戏概念&…

如何用CHAT写“科技探索者”视频号运营方案

问CHAT&#xff1a;生成一篇“科技探索者”视频号运营方案&#xff0c;要求内容&#xff1a; &#xff08;1&#xff09;视频号的定位、面向的人群、主要发布哪方面的内容 &#xff08;2&#xff09;视频号的内容设计&#xff08;用什么样的方式来体现、最好有内容创意&#xf…

会议预告 | 求臻医学受邀参加2023·Inno China 产业创新大会

INNO CHINA 中国产业创新大会聚焦于数据驱动产业变革升级、医疗科技与产业转型升级、企业数字化转型升级、产业服务生态构建及商业智能融合发展等领域。如今&#xff0c;已成为中国新兴科技、热门赛道行业论坛、创新成果展示、参与、共创的高维度学术与产业年度相聚的节日&…

CRM系统是怎样帮助销售流程自动化的?

销售业绩是衡量企业经营的重要指标&#xff0c;也是销售人员一直要达成的目标。销售业绩能否提高取决于销售人员的能力、客户服务水平&#xff0c;还需要借助有效的工具。CRM系统就是这样的一款软件。企业如何提高销售业绩&#xff1f;不妨试试CRM销售流程自动化。 CRM如何实现…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《基于世界模型深度强化学习的含风电电力系统低碳经济调度》

这个标题表明研究的主题涉及到一个电力系统&#xff0c;该系统包含风电&#xff0c;并且使用基于世界模型的深度强化学习进行低碳经济调度。以下是对标题中各个关键词的解读&#xff1a; 基于世界模型&#xff1a; 这可能指的是使用一种模型来表示电力系统所在的环境&#xff0…

使用mock.js模拟数据

一、安装mock.js npm i mockjs 二、配置JSON文件 我们创建一个mock文件夹&#xff0c;用于存放mock相关的模拟数据和代码实现。 我们将数据全部放在xxx.json文件夹下&#xff0c;里面配置我们需要的JSON格式的数据。 注意&#xff1a;json文件中不要留有空格&#xff0c;否则…

如何使用 ONLYOFFICE 文档代理功能

简介 ONLYOFFICE 文档以在线应用程序的方式运行&#xff0c;在很多情形中可能会存在需要将其集成至内部网络的情形。如今&#xff0c;许多内部网络维护者可能会出于某些目的使用不同的 Web 服务器作为代理。此时ONLYOFFICE 文档中的代理功能就能派上用场了。市面上应用最广泛的…

交流负载的功能实现原理

交流负载的功能实现原理主要涉及到电力电子技术、电机控制技术和电力系统保护技术等多个方面。 交流负载的功能实现需要通过电力电子器件进行电能的转换和控制&#xff0c;电力电子器件主要包括开关器件和电力电子变压器等。开关器件主要用于实现电能的通断控制&#xff0c;如晶…

【shell】文本三剑客之sed详解

目录 一、sed简介&#xff08;行编辑器&#xff09; 二、基本用法 三、sed脚本格式&#xff08;匹配地址 脚本命令&#xff09; 1、不给地址&#xff0c;那么就是针对全文处理 2、单地址&#xff0c;表示#&#xff0c;指定的行&#xff0c;$表示最后一行&#xff0c;/pattt…