首页 > 代码库 > OALP数据库优化之2 – Cube处理优化

OALP数据库优化之2 – Cube处理优化

OALP数据库优化之2 – Cube处理优化

当我们在OLAP数据库的世界中说起Process的时候,它至少可以分为两类:维度的处理跟Cube的处理,本部分只讨论cube的处理及优化,维度的处理优化会在另一部分讨论。

首先我们应该明确所谓处理(Process)这个概念,它可以简单的理解为将数据从一个或多个数据源加载、搬移到分析服务对象中的过程,对Cube处理来说就是加载到度量值组分区中的过程,所以Cube处理的优化其实归根结底是分区的处理优化。

处理过程简介

如下图所示,分区的处理过程可以分为两步:

wKioL1Q3hxLhmmSHAABeCcZQzro762.jpg

1.      处理事实数据

处理事实数据简单的说就是将数据从数据源搬到分区对象的过程,因为分区中的事实数据需要关联到维度,所以中间还有一步是查找与事实数据对应的已经处理的维度键值。下面三步并行执行已完成事实处理:

  1. 发送SQL查询来从源中抽取数据,好像是每次10万行

  2. 为上面读入的1万行数据在分析服务的维度对象中查找响应的维度键值,然后填充到处理缓存中

  3. 当处理缓存满的时候,将数据写入到磁盘中

2.      构建聚合及位图索引

在事实数据被处理到分区对象之后,处理就开始构建聚合及位图索引。聚合的处理是在内存中进行的,如果内存不足以构建所有的聚合,那么就会一块一块的先写入到磁盘的临时文件,在处理的最后做合并。

在设计OLAP数据库的时候我们应该在聚合上做均衡的考虑,因为大量的聚合肯定会提高查询的效率,但是同时会降低处理的效率。

分区的处理是通过向OLAP数据库发出分区处理命令进行的,主要有以下的分区处理命令:

ProcessFull

全处理会首先删除现有的存储内容(事实数据、聚合及位图索引),然后首先执行ProcessData过程,紧接着执行ProcessIndexes

ProcessData

处理数据命令也是首先删除现有的存储内容(事实数据、聚合及位图索引),然后处理事实数据,但是不会构建聚合及位图索引

ProcessIndexes

该命令执行的时候假设事实数据已经存在了,它在事实数据上构建新的聚集及位图索引

ProcessAdd

该命令创建一个临时分区,在其上执行完全执行,最后将临时分区Merge到目标分区中。该命令式一个XMLA命令,在UI上名为ProcessIncremental

ProcessClear

删除分区中现有的存储内容,它是XMLA的命令,在UI上名为UnProcess

ProcessClear Indexes

仅删除分区中的聚合及位图索引

处理过程的监控

我们可以使用SQL Server自带的Profiler来对OLAP数据库的处理做监控,首先我们需要知道Profiler中哪些Events是用来监控OLAP处理的,其实这个问题比较显而易见,所有与之相关的事件都处于Process Reports这个目录下面,包括:

wKioL1Q3hyaTM-n9AAFBumFBEUM375.jpg

  • Process Report Begin

事件ID5,它表示所有OLAP数据库相关的处理报告的开始事件

  • Process Report Current

事件ID7,它表示所有进度报告当前状态事件。例如,在处理期间,当前报表包含有关被处理的对象(维度、分区、多维数据集等)的处理信息

  • Process Report End

事件ID6,它表示所有OLAP数据库相关的处理报告的开始事件

  • Process Report Error

事件ID8,它表示所有处理报告错误事件

从我个人的使用情况来说,我一般只使用Process ReportEnd事件,因为所有的事件都是以Begin开始,中间经历Current最后以EndError结束。因为我使用Profiler只是用来调优而不是找错,所以不需要Error事件;而任何出现在ProcessReport Begin的事件肯定最后会反应在Process Report End事件中(应该是这样的吧?),所以ProcessReport BeginProcess Report End之间我们只需要Process Report End就可以了;对于ProcessReport  Current,本人不是太明白这个事件是干什么的,不过它有一个其他事件无法代替的作用:假如度量值组有1千万数据,AS肯定是没办反一次性都读入内存然后处理的,所以它会每次读取比如10万数据来处理,然后再处理10万直至全部处理完,ProcessReport Current能捕获到现在为止处理的数据行数。

接下来我们要知道的是关于Profiler捕获到的数据都有哪些信息,说白了就是有哪些数据列。我们在此只列出最主要的数据列:

  • EventSubClass– OLAP数据库处理事件类,下面是一些主要的事件

  • Process

  • Merge

  • Delete

  • DeleteOldAggregations

  • Rebuild

  • Commit

  • Rollback

  • CreateIndexes

  • CreateTable

  • InsertInto

  • Transaction

  • Initialize

  • Discretize

  • Query

  • CreateView

  • WriteData

  • ReadData

  • GroupData

  • GroupDataRecord

  • BuildIndex

  • Aggregate

  • BuildDecode

  • WriteDecode

  • BuildDMDecode

  • ExecuteSQL

  • NowExecutingSQL

  • ExecuteModifiedSQL

  • Connecting

  • BuildAggsAndIndexes

  • MergeAggsOnDisk

  • BuildIndexForRigidAggs

  • BuildIndexForFlexibleAggs

  • WriteAggsAndIndexes

  • WriteSegment

  • DataMiningProgress

  • ReadBufferFullReport

  • ProactiveCacheConversion

  • Backup

  • Restore

  • Synchronize

  • TextData与事件相关的文本数据,大部分情况下是对事件的一种描述。比如对于Process事件在结束时会描述为“Finishedprocessing the XXX partition

  • DatabaseName事件发生的数据库

  • ObjectName& ObjectPath 表示事件发生的对象以及该对象的路径

  • StartTime事件开始时间

  • Duration- 包含所报告的事件开始到结束的时间长度(只存在于ProcessReport End事件中)

  • EndTime- 包含所报告事件的结束时间(只存在于ProcessReport End事件中)

  • IntegerData包含与发生的事件关联的整形数据,例如已处理行数的当前计数(只存在于ProcessReport EndProcess Report Current事件中)

  •  

下面我们以实际的例子来描述一下Profiler到底捕获了什么样的处理数据。对一个只有一个度量值组一个分区的Cube进行处理,Profiler捕获的事件如下:

BuildProcessing Schedule

Cube ProcessBegin

                Measure Group Process Begin

                                PartitionProcess Begin

                                                WriteData for Partition Begin

                                                                ExecuteSQL to get data from Source

                                                                ReadData Begin

                                                                                ReadData Current – 到现在为止处理的数据行

                                                                                ReadData Current – 到现在为止处理的数据行

                                                                ReadData End

                                                WriteData for Partition End

                                                BuildAggregation and Indexes Begin

                                                                BuildIndex

                                                                BuildAggregate

                                                BuildAggregation and Indexes End

                                PartitionProcess End

                Measure Group Process End

Cube ProcessEnd

处理过程的优化

毋庸置疑地有繁多的优化措施可以帮助我们提升Cube的处理效率,比如通过添加索引提升取元数据的速度,提升IO子系统,排除数据库锁等,但是在我们试图应用这些细的优化措施之前,我们应该首先确保我们应用了对Cube处理作用最大的技术:分区+增量处理。

 

毋庸置疑地有繁多的优化措施可以帮助我们提升Cube的处理效率,比如通过添加索引提升取元数据的速度,提升IO子系统,排除数据库锁等,但是在我们试图应用这些细的优化措施之前,我们应该首先确保我们应用了对Cube处理作用最大的技术:分区+ 分区合并+ 增量处理

恰当的分区是提升查询机处理效率最有效的方式,假如我们一个销售事实表中包含了近10年的近亿数据,并且还在以每天几万条数据的方式在增长,那如果该度量值组只有一个分区,我们每天不得不对该度量值组做FullProcess,也就是每天都需要处理上亿的数据;但是如果我们是一天一个分区,那么我们每天只需要处理几万数据就可以了。所以分区让我们可以将历史的、固定不变的数据与最近的数据隔离开来,这样就只需要处理最近的少量数据就可以了

不过实际中每天一个分区会造成管理的混乱,所以有时候我们可以只创建少量的分区,比如只有两个分区,一个表示历史分区,一个表示当前月数据的分区,这样每天我们只在当前月分区上做增量处理(给只处理一天的数据差不多,只是多了Merge的花费),然后在下月的第一天我们将当前月分区的数据Merge到历史分区中。

如果每天的数据量不是特别大(比如千万甚至上亿),该方式能够满足绝大部分的处理性能需求。

 

毋庸置疑地有繁多的优化措施可以帮助我们提升Cube的处理效率,比如通过添加索引提升取元数据的速度,提升IO子系统,排除数据库锁等,但是在我们试图应用这些细的优化措施之前,我们应该首先确保我们应用了对Cube处理作用最大的技术:分区+ 分区合并+ 增量处理

恰当的分区是提升查询机处理效率最有效的方式,假如我们一个销售事实表中包含了近10年的近亿数据,并且还在以每天几万条数据的方式在增长,那如果该度量值组只有一个分区,我们每天不得不对该度量值组做FullProcess,也就是每天都需要处理上亿的数据;但是如果我们是一天一个分区,那么我们每天只需要处理几万数据就可以了。所以分区让我们可以将历史的、固定不变的数据与最近的数据隔离开来,这样就只需要处理最近的少量数据就可以了

不过实际中每天一个分区会造成管理的混乱,所以有时候我们可以只创建少量的分区,比如只有两个分区,一个表示历史分区,一个表示当前月数据的分区,这样每天我们只在当前月分区上做增量处理(给只处理一天的数据差不多,只是多了Merge的花费),然后在下月的第一天我们将当前月分区的数据Merge到历史分区中。

如果每天的数据量不是特别大(比如千万甚至上亿),该方式能够满足绝大部分的处理性能需求。

如果应用了上面简单的处理方式后还不能满足处理性能的要求,那么我们可能需要参考下面一些比较琐碎的优化方式:

源数据端的优化

所谓数据源端的优化其实就是关系型数据库的优化以及OLAP分区所对应的数据查询语句的优化,这主要有以下的方式:

  • 如果可能的话为分区查询语句构建恰当的索引,不过我们必须同时考虑到索引对数据插入的负面影响

  • 是每个度量值组的分区对应于至多一个关系型数据库表的分区,这样每个分区的数据查询语句只会访问一个表分区

  • 尽量从分区的数据查询语句中去除JOIN,被JOIN得出的列应该被物理化到事实表中

  • 如果有页面切分,我们可以重构索引来提升填充因子,同时可以采用数据压缩来降低IO

  • 通过使用NOLOCK来降低数据库锁开销

  • 事实表的设计遵循以下的最优设计

Surrogatekeystinyint, smallint, int, bigint
Datekeyint inthe format yyyyMMdd
Integermeasurestinyint, smallint, int, bigint 
Numericmeasures

smallmoney, money, real, float

(Note that decimaland vardecimal require more CPUpower to process than money and float types)
Distinctcount columns

tinyint, smallint, int, bigint

(If your count column is char, consider either hashing or replacing with surrogate key)



OLAP端优化

待续….

处理选项的优化

待续….

 


OALP数据库优化之2 – Cube处理优化