优化Cube

层次结构

理论上,对于N维,你最终会得到2 ^ N维组合。但是对于某些维度组,不需要创建这么多组合。例如,如果您有三个维度:洲,国家,城市(在层次结构中,“更大”维度首先出现)。在深入分析时,您只需要以下三种组合组合:

按大陆分组

按大陆,国家分组

按大陆,国家,城市分组

在这种情况下,组合计数从2 ^ 3 = 8减少到3,这是一个很好的优化。 YEAR,QUATER,MONTH,DATE案例也是如此。

派生列

派生列用于一个或多个维度(它们必须是查找表上的维度,这些列称为“派生”)可以从另一个维度推导出来(通常它是相应的FK,这称为“主机列”)

例如,假设我们有一个查找表,我们将其连接到事实表,并将其与“其中DimA = DimX”。请注意,在Kylin中,如果您选择FK为维度,相应的PK将自动排队,无需任何额外费用。秘诀是,由于FK和PK总是相同的,Kylin可以先在FK上应用过滤器/ groupby,然后将它们透明地替换为PK。这表明如果我们想在我们的立方体中使用DimA(FK),DimX(PK),DimB,DimC,我们可以安全地选择DimA,DimB,DimC。

事实表(连接)查找表

column1,column2 ,,,,,, DimA(FK)DimX(PK),, DimB,DimC

假设DimA(代表FK / PK的维度)具有到DimB的特殊映射:

dimA    dimB     dimC

1       a       ?

2       b      ?

3       c       ?

4       a       ?

在这种情况下,给定DimA中的值,确定DimB的值,因此我们说dimB可以从DimA导出。当我们构建一个包含DimA和DimB的多维数据集时,我们简单地包含DimA,并将DimB标记为派生。派生列(DimB)不参与长方体生成:

原创组合:

ABC,AB,AC,BC,A,B,C

从A到B时的组合:

AC,A,C

在运行时,如果查询类似于“select count(*) from fact_table inner join looup1 group by looup1 .dimB”,则期望包含DimB的长方体来回答查询。但是,由于派生优化,DimB将出现在NONE的长方体中。在这种情况下,我们首先修改执行计划以使其由DimA(其主机列)进行分组,我们将得到如下的中间答案:

DIMA   COUNT(*)

1         1

2         1

3          1

4          1

之后,Kylin将用DimB值替换DimA值(因为它们的值都在查找表中,Kylin可以将整个查找表加载到内存中并为它们构建映射),并且中间结果变为:

DimB     count(*)

a                1

b                1

c                1

a                1

在此之后,运行时SQL引擎将进一步将中间结果聚合为:

DimB    count(*)

a          2

b          1

c          1

这一步发生在查询运行时,这意味着“以额外的运行时聚合为代价”

 

性能优化

分区列优化

如果cube的分区列与Hive表的分区列相同,那么根据它过滤数据能让Hive聪明地跳过不匹配的分区。因此强烈建议用Hive的分区列(如果它是日期列)作为cube的分区列。这对于那些数据量很大的表来说几乎是必须的,否则Hive不得不每次在这步扫描全部文件,消耗非常长的时间。

文件合并

如果启用了Hive的文件合并,你可以在conf/kylin_hive_conf.xml里关闭它,因为Kylin有自己合并文件的方法(下一节):

<property>

<name>hive.merge.mapfiles</name>

<value>false</value>

<description>Disable Hive's auto merge</description>

</property>

重新分发中间表

Hive在HDFS上的目录里生成了数据文件:有些是大文件,有些是小文件甚至空文件。这种不平衡的文件分布会导致之后的MR任务出现数据倾斜的问题:有些mapper完成得很快,但其他的就很慢。针对这个问题,Kylin增加了这一个步骤来“重新分发”数据,这是示例输出:

total input rows = 159869711

expected input rows per mapper = 1000000

num reducers for RedistributeFlatHiveTableStep = 160

重新分发表的命令:

hive -e "USE default;

SET dfs.replication=2;

SET hive.exec.compress.output=true;

SET hive.auto.convert.join.noconditionaltask=true;

SET hive.auto.convert.join.noconditionaltask.size=100000000;

SET mapreduce.job.split.metainfo.maxsize=-1;

set mapreduce.job.reduces=160;

set hive.merge.mapredfiles=false;

INSERT OVERWRITE TABLE kylin_intermediate_airline_cube_v3610f668a3cdb437e8373c034430f6c34 SELECT * FROM kylin_intermediate_airline_cube_v3610f668a3cdb437e8373c034430f6c34 DISTRIBUTE BY RAND();"

首先,Kylin计算出中间表的行数,然后基于行数的大小算出重新分发数据需要的文件数。默认情况下,Kylin为每一百万行分配一个文件。在这个例子中,有1.6亿行和160个reducer,每个reducer会写一个文件。在接下来对这张表进行的MR步骤里,Hadoop会启动和文件相同数量的mapper来处理数据(通常一百万行数据比一个HDFS数据块要小)。如果你的日常数据量没有这么大或者Hadoop集群有足够的资源,你或许想要更多的并发数,这时可以将conf/kylin.properties里以下配置设为小一点的数值,比如:

kylin.job.mapreduce.mapper.input.rows=500000

其次,Kylin会运行 “INSERT OVERWRITE TABLE … DISTRIBUTE BY “ 形式的HiveQL来分发数据到指定数量的reducer上。在很多情况下,Kylin请求Hive随机分发数据到reducer,然后得到大小相近的文件,分发的语句是”DISTRIBUTE BY RAND()”。

如果你的cube指定了一个高基数的列,比如”USER_ID”,作为”分片”维度(在cube的“高级设置”页面),Kylin会让Hive根据该列的值重新分发数据,那么在该列有着相同值的行将被分发到同一个文件。这比随机要分发要好得多,因为不仅重新分布了数据,并且在没有额外代价的情况下对数据进行了预先分类,如此一来接下来的cube build处理会从中受益。在典型的场景下,这样优化可以减少40%的build时长。在这个案例中分发的语句是”DISTRIBUTE BY USER_ID”:

请注意: 1)“分片”列应该是高基数的维度列,并且它会出现在很多的cuboid中(不只是出现在少数的cuboid)。 使用它来合理进行分发可以在每个时间范围内的数据均匀分布,否则会造成数据倾斜,从而降低build效率。典型的正面例子是:“USER_ID”、“SELLER_ID”、“PRODUCT”、“CELL_NUMBER”等等,这些列的基数应该大于一千(远大于reducer的数量)。 2)”分片”对cube的存储同样有好处,不过这超出了本文的范围。

将cuboid数据转换为HFile

这一步启动一个MR任务来讲cuboid文件(序列文件格式)转换为HBase的HFile格式。Kylin通过cube统计数据计算HBase的region数目,默认情况下每5GB数据对应一个region。Region越多,MR使用的reducer也会越多。如果你观察到reducer数目较小且性能较差,你可以将“conf/kylin.properties”里的以下参数设小一点,比如:

kylin.hbase.region.cut=2
kylin.hbase.hfile.size.gb=1

rowkey构建

对rowkey的构建也有一定的要求,一般而言,需要把基数大的字段放在前面,这样可以在scan的过程中尽可能的跳过更多的rowkey。

另一方面将基数小的列放在rowkey的后面,可以减少构建的重复计算,有些cuboid可以通过一个以上的父cuboid聚合而成,在这种情况下,Kylin将会选择最小的父cuboid。例如,AB能够通过ABC(id:1110)和ABD(id:1101)聚合生成,因此ABD会被作为父cuboid使用,因为它的id比ABC要小。基于以上处理,如果D的基数很小,那么此次聚合操作就会花费很小的代价。因此,当设计cube的rowkey顺序的时候,请记住,将低基数的维度列放在尾部。这不仅对cube的构建过程有好处,而且对cube查询也有好处,因为后聚合(应该是指在HBase查找对应cuboid的过程)也遵循这个规则。

数据转换为HFile

kylin将生成的cube通过生成HFile的方式导入到hbase,这个优化点可以配置hbase的相关参数。

  1. region数量默认是1,如果数据量大的话可以提高region数量
  2. region大小默认是5GB,也就是hbae官方建议的大小;如果cube大小比这个值小太多,可以减小单region的大小
  3. hfile文件大小,默认是1GB,由于是通过mapreduce写入的,小文件意味着写入快,但是读取慢,大文件意味着写入慢,读取快

经验

  1. 尽量将需要展现的字段作为维度,没必要所有的一股脑加进去。
  2. 每次查询或者要经常group by的字段作为Mandatory维度。且该维度放在        rowkey的最前面。
  3. 将数量相近也就是说某两个字段通过select count("字段名")获取的结果近似1:1,设置为joint维度。
  4. rowkey的顺序按查询频率从高到低,从前往后排。
  5. 将经常出现在同一SQL中的不同维度放置在一个维度组中,将从不出现在一个SQL查询中的不同维度设置在不同的维度组中。
  6. Dictionary默认为dict类型,如果某个字段中的值非常大(小幽遇到过的一个字段中的值保存成文本足足有23Kb!!!),大到以至或者可能使得Cube在build过程中出现OOM的错误,则需要将该字段的值设置为fixed_length类型,取可以展现这个维度的前length个字节,比如对于之前那个23kb的字段值,经和业务人员协商,发现取前4000个字节就可以表示这个字段了。所以fixed_length的值设置为4000.值得一提的是,Dictionary默认为false,是不给该字段在内存中建立词典树的,而更改为true则表示给该字段建立词典树。有词典树,则会优化带有该字段的SQL查询,提升查询速度,但相应地也会消耗一些内存。

总结

基于kylin的ui,可以看到kylin在构建cube时各个流程的耗时,可以依据这些耗时做相应的优化,常见的,可以从耗时最长的步骤开始优化,比如:

  1. 遇到创建hive中间表时间很长,考虑对hive表进行分区处理,对表中的文件格式更改,使用orc,parquet等高性能的文件格式
  2. 遇到cube构建时间过长,查看cube设计是否合理,维度的组合关系是否可以再减少,构建引擎是否可以优化

分享一个其他得cube优化设计的推荐:https://www.cnblogs.com/wenBlog/p/10255467.html

kylin简单优化cube的更多相关文章

  1. 【转】Kylin中的cube构建

    http://blog.csdn.net/yu616568/article/details/50365240 前言   在使用Kylin的时候,最重要的一步就是创建cube的模型定义,即指定度量和维度 ...

  2. 一次千万级别的SQL查询简单优化体验

    背景:从两张有关联的表查询数据,A表数据量1400万,B表数据量8000万.A与B通过ID逻辑关联,没有实际的外键.B表是后来扩展出来的. 问题:根据某个ID查询时超时,运行时跑不出结果. 原因:使用 ...

  3. 双数组trie树的基本构造及简单优化

    一 基本构造 Trie树是搜索树的一种,来自英文单词"Retrieval"的简写,可以建立有效的数据检索组织结构,是中文匹配分词算法中词典的一种常见实现.它本质上是一个确定的有限状 ...

  4. [mysql] 2进制安装和简单优化

    ##################################mysql 2进制安装和简单优化################################################## ...

  5. 封装ajax,让调用变得简单优化

    思考一下: 通常我们在使用ajax来发送接口请求时,每一次都会调用ajax固定的元素,比如data.url.method.success.error等.那么我们想一下能不能先把ajax封装起来,在每次 ...

  6. linux简单优化

    1.简单优化 #关闭firewalld,selinux,NetworkManager systemctl(管理服务的命令) stop(关服务) firewalld (服务名称,d是demo的意思) s ...

  7. mysql的简单优化【简单易学】

    1.选取最适用的字段属性: 表字段尽量设小,不要给数据库增加没必要的空间:如:值为'01'.'02',给char(2)即可: 2.使用连接(JOIN)来代替子查询(Sub-Queries): 使用jo ...

  8. mysql简单优化思路

    mysql简单优化思路 作为开发人员,数据库知识掌握的可能不是很深入,但是一些基本的技能还是要有时间学习一下的.作为一个数据库菜鸟,厚着脸皮来总结一下 mysql 的基本的不能再基本的优化方法. 为了 ...

  9. mysql之优化器、执行计划、简单优化

    mysql之优化器.执行计划.简单优化 2018-12-12 15:11 烟雨楼人 阅读(794) 评论(0) 编辑 收藏 引用连接: https://blog.csdn.net/DrDanger/a ...

随机推荐

  1. 用CSS实现一个抽奖转盘

    效果 基本是用CSS实现的,没有用图片,加一丢丢JS.完全没有考虑兼容性. 首先画一个转盘, <!DOCTYPE html> <html lang="en"> ...

  2. scala用ssh2连接Linux

    这个需要安装库: import ch.ethz.ssh2.{Connection, Session, StreamGobbler} 首先用 ip 和 post 创建连接: val conn: Conn ...

  3. org.springframework.core.io.ClassPathResource类

    测试代码 package cn.edu.hdu.pichen.springexample; import java.io.BufferedReader; import java.io.IOExcept ...

  4. 【C#加深理解系列】(二)序列化

    什么是序列化 序列化,它又称串行化,是.NET运行时环境用来支持用户定义类型的流化的机制.序列化就是把一个对象保存到一个文件或数据库字段中去,反序列化就是在适当的时候把这个文件再转化成原来的对象使用. ...

  5. 【Java基础】【14正则表达式&常用工具类】

    14.01_常见对象(正则表达式的概述和简单使用) A:正则表达式 是指一个用来描述或者匹配一系列符合某个语法规则的字符串的单个字符串.其实就是一种规则.有自己特殊的应用. 作用:比如注册邮箱,邮箱有 ...

  6. Vim编辑器显示行数

    很多时候,我们编写代码的时候,编译器报错,在某一行,这时我们虽然可以:行数来跳转,但是没有直观的行数,总是感觉不妥,vi和vim默认是没有行号的,那么怎么办呢?下面我就教你怎么设置行号. 工具: 一台 ...

  7. log4j2 使用纪要

    简介 Apache Log4j 2 是Log4j 的升级版,在该版本实现中,日志的处理流程及效率有了显著提升. 此外新版本也合入了一些logback日志框架体系的一些改进点. 关键特性 API分离,接 ...

  8. 补习系列(5)-springboot- restful应用

    一.目标 了解 Restful 是什么,基本概念及风格: 能使用SpringBoot 实现一套基础的 Restful 风格接口: 利用Swagger 生成清晰的接口文档. 二.Restful 入门 什 ...

  9. SpringBoot基础系列-使用日志

    原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9996897.html SpringBoot基础系列-使用日志 概述 SpringBoot ...

  10. SpringBoot整合系列-整合MyBatis

    原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9971036.html SpringBoot整合Mybatis 步骤 第一步:添加必要的j ...