Mikoyan's profile時間的灰燼PhotosBlogLists Tools Help

Blog


    August 09

    如何架构一个BI系统(zt)

    开始接触软件工程的时候,知道其中一个步骤叫做“总体设计”,做这项工作的人就叫“软件设计师”。当时觉得这个名称比软件开发工程师酷多了。到了现在,又开始流行“架构师”(Architect),这个名称听起来比软件设计师又酷了几分。

    如今,如果你偶尔遇到一个年轻人,也就是二十出头、三十不到的样子,却客客气气地给你递上一张注明“数据仓库资深架构师”的名片。这个时候,你千万不要诧异。说来也不奇怪, BI在国内刚发展起来没几年,在这个领域干个四五年就足以混个资深的名头了。

    不过,话说回来,拿着“资深架构师”的名头去忽悠是一回事,但架构师究竟该干什么,架构设计究竟怎么进行,如何架构一个BI系统?的确是需要认真研究一番的!

    第一节:模块

         BI系统(或者说数据仓库系统)也同样需要架构,它作为一种软件系统,是符合一般架构原则的。首先,我们来看看架构设计中包括那些内容。 架构的重点是描述系统的结构,以及它们之间的关联、交互接口。

         BI系统可以划分成业务模型、元数据、数据质量、接口平台、报表集市、指标库等若干模块。可以看出,在这里,这些模块的命名都是静态的名词,而不是动词 (例如业务建模、数据质量管理等)。之所以如此,是因为这是在描述系统的结构而非功能。具体来讲,业务模型是存放业务数据的结构,可以再往下细分,并有不 同的分层方法。例如可以分成ODS、EDW、DM等层,也有的会根据业务复杂度或数据量考虑,舍弃ODS层。业务模型是支撑业务分析需求的,例如报表、仪 表盘、OLAP、专题应用等。

         元数据为整个系统数据的形态和数据流动的过程起到支撑作用,也就是说,数据从源头开始,到最终用户眼前,其来龙去脉,每个环节的状态都需要掌握。还有人将 它比喻成模块之间的粘合剂,但我更愿意将它称作是“数据”之间的粘合剂,因为模块之间自有它们的交互接口规格来粘合。数据质量模块为衡量数据源质量、 ETL过程处理质量提供支撑。

         接口平台是处于源系统和数据仓库系统之间的玩意儿,作用在于可以更方便地明确界定双方职责。当然,通常有很多系统似乎并不大愿意将职责搞得过于明确了倒宁 愿糊涂一些。糊涂一些的好处在于一开始省了好多事,但在以后扯皮的事情就少不了了。此外,报表集市为报表应用提供支持,指标库为绩效管理需求提供支持。其 实,这两者还可以归入业务模型一类,因为它们都是服务于分析需求的。


    第二节:需求

         之所以分成若干模块,是为了让架构清晰,降低这些模块之间的耦合,这符合“分离变化”的原则。那么,这一结构到底是否合理呢?还得看这个架构面临的需求到 底是什么。做好这一步,就需要把系统的用户分为两大类角色:一是系统运营角色,他们对系统的正常运行、维护负责; 二是业务分析角色,他们需要从这个系统得到数据分析的功能。

         显然,第二种角色的分析数据来源都将来自业务模型模块,而第一种角色将从剩余模块中满足自己的需要,而不直接和业务模型这个模块打交道。在架构设计中,重 点应该放在如何满足系统管理用户的需求上面。当然,只是"重点",而非舍弃业务分析角色,毕竟在业务模型模块中,还需要根据业务、数据量、分析应用等方面 的特点,来进一步细化。

         就个人经验认为,架构设计应该是与具体业务关系不大的,这种架构应该是半通用的。之所以是半通用,是因为在系统功能上面,BI项目大同小异,而在业务需求 上面,架构只需要对客户的业务、分析需求分成几个大类,例如按行业为业务模型分类,按OLAP、报表来为分析应用分类,不需要太过细致。

         下面,让我们来看看系统运营角色的需求。

         首先,我们可以把这类角色再细分成两类: 一是开发设计及实施者。之所以将开发者作为系统的用户,是因为数据仓库项目应该看作一个过程,而不是产品,因此在开发阶段,其实其架构最重要的用户就是开 发者,当然要为之提供便利。 二是系统管理员。系统交付之后,如何监控系统运行、发现数据质量问题、应付新的分析需求等,当然都是系统管理员的分内之事。

         那么,对于开发实施人员,他需要进行系统部署、ETL的开发调试、质量的稽核;对于设计人员,则需要进行模型的变更、系统调优、系统一致性分析等;而系统管理员则需要监控ETL过程、监控系统运行、响应系统警报、接口数据管理等。这些都可以看作是用例。
    这些用例就是架构设计的"需求",如何满足他们,并且保持良好的体系和清晰的结构,能够易于维护且能够满足日后肯定会增加的业务需求等等,这些都是架构师们仔细斟酌的事情。

          最后,看一下分析人员的需求。举个例子来讲,某销售总监说:“我需要了解近半年来东区和西区的销售量、收入、成本对比”,这可以算是一个用例。对这个需 求,架构师该如何做呢?正确做法是,在架构中不能考虑东区、西区这些业务概念,那样就太过于细致,而是应当将这种需求抽象成一种分析应用,例如 “即席查询”。如此,架构师所着重考虑的事情就是如何满足这一类需求,而非这一个需求。

    架构设计四项原则:
    1、架构设计主要面向系统用户为主;
    2、架构设计的内容主要包括:系统功能需求、分析需求分类;支持这两者的后台结构,对结构进行粗略划分,以让其内部能够保持简单的交互方式;
    3、架构设计中不要包含过于细致的业务术语(除非为了说明方便),要尽可能保持架构的复用;
    4、如果架构设计确实包含不能被其他项目复用的地方,将这部分独立出去。

    June 07

    常用SQL语句书写技巧(ZT)

    SQL结构化查询字符串的改写,是实现数据库查询性能提升的最现实、最有效的手段,有时甚至是唯一的手段,比如在不允许大幅度修改现有数据库结构的情况下。
    通过优化SQL语句提高查询性能的关键是:
     根据实际需求情况,建立合适的索引;
     使用一切可能的方式去利用好索引,避免全表扫描;
     尽量减少内存及数据I/O方面的开销
    一、 建立索引
    (一)建立“适当”的索引,是快速查询的基础。
    索引(index)是除表之外另一重要的、用户定义的存储在物理介质上的数据结构。当根据索引码的值搜索数据时,索引提供了对数据的快速访问。事实上,没有索引,数据库也能根据SELECT语句成功地检索到结果,但随着表变得越来越大,使用“适当”的索引的效果就越来越明显。注意,在这句话中,我们用了“适当”这个词,这是因为,如果使用索引时不认真考虑其实现过程,索引既可以提高也会破坏数据库的工作性能。
    索引实际上是一种特殊的目录,SQL SERVER提供了两种索引:
     聚集索引(clustered index,也称聚类索引、簇集索引)
    我们把这种正文内容本身就是一种按照一定规则排列的目录称为“聚集索引”。
    例如:
    汉语字典中按拼音查某一个字,就是使用“聚集索引”,实际上,你根本用不着查目录,直接在字典正文里找,就能很快找到需要的汉字(假设你知道发音)。
     非聚集索引(nonclustered index,也称非聚类索引、非簇集索引)
    我们把目录纯粹是目录,正文纯粹是正文的排序方式称为“非聚集索引”。
    例如:
    汉语字典中按部首查某一个字,部首目录和正文一定要刻意的通过页码才能联系到一起,其顺序不是天然一致的。
    聚集索引与非聚集索引的最大区别就在于:聚集索引是对原数据表进行排序,因此只要符合索引条件,就能够直接连续的读取数据记录,几乎可以达到对数据表的零扫描;而非聚集索引仅仅只是另外建了一张索引表,取数据的时候,从索引表取得结果后,还需要到指针所指的数据行读取相应数据,因此,在性能上,聚集索引会大大优于非聚集索引。
      但是在一张表中,聚集索引只允许一个,是比较宝贵的,因此要尽可能的用于那些使用频率最高的索引上。 另外,查询时必需要用到索引的起始列,否则索引无效。另外,起始列也必需是使用频繁的列,那样的索引性能才会达到最优化。
    (二)表:何时应使用聚集索引或非聚集索引
    动作描述 使用聚集索引 使用非聚集索引
    列经常被分组排序 ○ ○
    返回某范围内的数据 ○
    一个或极少不同值
    小数目的不同值 ○
    大数目的不同值 ○
    频繁更新的列 ○
    外键列 ○ ○
    主键列 ○ ○
    频繁修改索引列 ○
    (三)索引建立的一些注意项
    1、不要把聚集索引浪费在主键上,除非你只按主键查询
    虽然SQL SERVER默认是在主键上建立聚集索引的,但实际应用中,这样做比较浪费。通常,我们会在每个表中都建立一个ID列,以区分每条数据,并且这个ID列是自动增大的,步长一般为1。此时,如果我们将这个列设为主键,SQL SERVER会将此列默认为聚集索引。这样做有好处,就是可以让您的数据在数据库中按照ID进行物理排序,但这样做实用价值不大。
    从我们前面谈到的聚集索引的定义我们可以看出,使用聚集索引的最大好处就是能够根据查询要求,迅速缩小查询范围,避免全表扫描。在实际应用中,因为ID号是自动生成的,我们并不知道每条记录的ID号,所以我们很难在实践中用ID号来进行查询。这就使让ID号这个主键作为聚集索引成为一种资源浪费。聚集索引相对与非聚集索引的优势是很明显的,而每个表中只能有一个聚集索引的规则,这使得聚集索引变得更加宝贵,应该用在其他查询频率高的字段上。其次,让每个ID号都不同的字段作为聚集索引也不符合“大数目的不同值情况下不应建立聚合索引”规则;当然,这种情况只是针对用户经常修改记录内容,特别是索引项的时候会负作用,但对于查询速度并没有影响。
    2、索引的建立要根据实际应用需求来进行
    并非是在任何字段上简单地建立索引就能提高查询速度。聚集索引建立的规则大致是“既不能绝大多数都相同,又不能只有极少数相同”。举个例子,在公文表的收发日期字段上建立聚合索引是比较合适的。在政务系统中,我们每天都会收一些文件,这些文件的发文日期将会相同,在发文日期上建立聚合索引对性能的提升应该是相当大的。在群集索引下,数据物理上按顺序存于数据页上,重复值也排列在一起,因而在范围查找时,可以先找到这个范围的起末点,且只在这个范围内扫描数据页,避免了大范围扫描,提高了查询速度。
    另一个相反的例子:比如在雇员表的“性别”列上只有“男”与“女”两个不同值,因此就完全没必要建立索引。
    3、在聚集索引中加入所有需要提高查询速度的字段,形成复合索引
    根据一些实验的结果,我们可以得出一些可供参考的结论:
     仅用复合聚集索引的起始列作为查询条件和同时用到复合聚集索引的全部列的查询,速度是几乎一样的,甚至比后者还要快(在查询结果集数目一样的情况下);
     仅用复合聚集索引的非起始列作为查询条件的话,
    这个索引是不起任何作用的。
     复合聚集索引的所有列都用上,而且因为查询条件严格,查询结果少的话,会形成“索引覆盖”,性能可以达到最优。
     最重要的一点:无论是否经常使用复合聚合索引的其他列,其起始列一定要是使用最频繁的列。
    4.根据实践得出的一些其他经验,特定情况下有效
     用聚合索引比用不是聚合索引的主键速度快;
     用聚合索引比用一般的主键作order by速度快,特别是在小数据量情况;
     使用聚合索引内的时间段,搜索时间会按数据占整个数据表的百分比成比例减少,而无论聚合索引使用了多少个;
     日期列不会因为有分秒的输入而减慢查询速度;
     由于改变一个表的内容,将会引起索引的变化。频繁的insert,update,delete语句将导致系统花费较大的代价进行索引更新,引起整体性能的下降。一般来讲,在对查询性能的要求高于对数据维护性能要求时,应该尽量使用索引,否则,就要慎重考虑一下付出的代价。在某些极端情况下,可先删除索引,再对数据库表更新大量数据,最后再重建索引,新建立的索引总是比较好用。
    二、 编写优化的SQL语句,充分利用索引
    下面就某些SQL语句的where子句编写中需要注意的问题作详细介绍。在这些where子句中,即使某些列存在索引,但是由于编写了劣质的SQL,系统在运行该SQL语句时也不能使用该索引,而同样使用全表扫描,这就造成了响应速度的极大降低。
    SQL语句在提交给数据库进行操作前,都会经过查询分析阶段,SQLSERVER内置的查询优化器会分析查询条件的的每个部分,并判断这些条件是否符合扫描参数(SARG)的标准。只有当一个查询条件符合SARG的标准,才可以通过预先设置的索引,提升查询性能。
    SARG的定义:用于限制搜索操作的一种规范,通常是指一个特定的匹配,一个确定范围内的匹配或者两个以上条件的AND连接。一般形式如下:
    列名 操作符 <常数 或 变量>

    <常数 或 变量> 操作符 列名
    列名可以出现在操作符的一边,而常数或变量出现在操作符的另一边。如:
    Name=’张三’
    价格>5000
    5000<价格
    Name=’张三’ and 价格>5000
    如果一个表达式不能满足SARG的形式,那它就无法限制搜索的范围了,也就是说SQL SERVER必须对每一行都判断它是否满足WHERE子句中的所有条件,既进行全表扫描。所以,一个索引对于不满足SARG形式的表达式来说是无用的, 如:当查询条件为“价格*2 >5000”时,就无法利用建立在价格字段上的索引 。
    SQLSERVER内置了查询优化器,能将一些条件自动转换为符合SARG标准,如:将“价格*2 >5000” 转换为“价格 >2500/2 ”,以达到可以使用索引的目的,但这种转化不是100%可靠的,有时会有语义上的损失,有时转化不了。如果对“查询优化器”的工作原理不是特别了解,写出的SQL语句可能不会按照您的本意进行查询。所以不能完全依赖查询优化器的优化,建议大家还是利用自己的优化知识,尽可能显式的书写出符合SARG标准的SQL语句,自行确定查询条件的构建方式,这样一方面有利于查询分析器分析最佳索引匹配顺序,另一方面也有利于今后重读代码。
    介绍完SARG后,我们再结合一些实际运用中的例子来做进一步的讲解:
    1、 Like语句是否属于SARG取决于使用%通配符的样式
    如:name like ‘张%’ ,这就属于SARG
    而:name like ‘%张’ ,就不属于SARG
    通配符%在字符串首字符的使用会导致索引无法使用,虽然实际应用中很难避免这样用,但还是应该对这种现象有所了解,至少知道此种用法性能是很低下的。
    2、 “非”操作符不满足SARG形式,使得索引无法使用
    不满足SARG形式的语句最典型的情况就是包括非操作符的语句,如:NOT、!=、<>、!<、!>、NOT EXISTS、NOT IN、NOT LIKE等。
    下面是一个NOT子句的例子:
      ... where not (status ='valid')
      not运算符也隐式的包含在另外一些逻辑运算符中,比如<>运算符。见下例:
      ... where status <>'invalid';
      再看下面这个例子:
      select * from employee where salary<>3000;
      对这个查询,可以改写为不使用not:
      select * from employee where salary<3000 or salary>3000;
      虽然这两种查询的结果一样,但是第二种查询方案会比第一种查询方案更快些。第二种查询允许对salary列使用索引,而第一种查询则不能使用索引。
    3、 函数运算不满足SARG形式,使得索引无法使用
    例:下列SQL条件语句中的列都建有恰当的索引,但执行速度却非常慢:
    select * from record where substring(card_no,1,4)=′5378′(13秒)
    select * from record where amount/30< 1000(11秒)
    select * from record where convert(char(10),date,112)=′19991201′(10秒)
    分析:
    where子句中对列的任何操作结果都是在SQL运行时逐列计算得到的,因此它不得不进行全表扫描,而没有使用该列上面的索引;如果这些结果在查询编译时就能得到,那么就可以被SQL优化器优化,使用索引,避免表搜索,因此将SQL重写成下面这样:
    select * from record where card_no like ′5378%′(< 1秒)
    select * from record where amount < 1000*30(< 1秒)
    select * from record where date= ′1999/12/01′ (< 1秒)
    你会发现SQL明显快很多
    4、 尽量不要对建立了索引的字段,作任何的直接处理
    select * from employs where first_name + last_name ='beill cliton';
    无法使用索引
    改为:
    select * from employee where
    first_name = substr('beill cliton',1,instr('beill cliton',' ')-1)
    and
    last_name = substr('beill cliton',instr('beill cliton',' ')+1)
    则可以使用索引
    5、 不同类型的索引效能是不一样的,应尽可能先使用效能高的
    比如:数字类型的索引查找效率高于字符串类型,定长字符串char,nchar的索引效率高于变长字符串varchar,nvarchar的索引。
    应该将
    where username='张三' and age>20
    改进为
    where age>20 and username='张三'
    注意:
    此处,SQL的查询分析优化功能可以做到自动重排条件顺序,但还是建议预先手工排列好。

    6、 尽量不要使用 is null 与 is not null作为查询条件
      任何包含null值的列都将不会被包含在索引中,如果某列数据中存在空值,那么对该列建立索引的性能提升是值得怀疑的,尤其是将null作为查询条件的一部分时。建议一方面避免使用is null和is not null, 另一方面不要让数据库字段中存在null, 即使没有内容,也应利用缺省值,或者手动的填入一个值,如:’’ 空字符串。
    7、 某些情况下IN 的作用与OR 相当 ,且都不能充分利用索引
    例:表stuff有200000行,id_no上有非群集索引,请看下面这个SQL:
    select count(*) from stuff where id_no in(′0′,′1′) (23秒)
    where条件中的′in′在逻辑上相当于′or′,所以语法分析器会将in (′0′,′1′)转化为id_no =′0′ or id_no=′1′来执行。我们期望它会根据每个or子句分别查找,再将结果相加,这样可以利用id_no上的索引;但实际上,它却采用了"OR策略",即先取出满足每个or子句的行,存入临时数据库的工作表中,再建立唯一索引以去掉重复行,最后从这个临时表中计算结果。因此,实际过程没有利用id_no上索引,并且完成时间还要受tempdb数据库性能的影响。
    实践证明,表的行数越多,工作表的性能就越差,当stuff有620000行时,执行时间会非常长!如果确定不同的条件不会产生大量重复值,还不如将or子句分开:
    select count(*) from stuff where id_no=′0′
    select count(*) from stuff where id_no=′1′
    得到两个结果,再用union作一次加法合算。因为每句都使用了索引,执行时间会比较短,
    select count(*) from stuff where id_no=′0′
    union
    select count(*) from stuff where id_no=′1′
    从实践效果来看,使用union在通常情况下比用or的效率要高的多,而exist关键字和in关键字在用法上类似,性能上也类似,都会产生全表扫描,效率比较低下,根据未经验证的说法,exist可能比in要快些。
    8、 使用变通的方法提高查询效率
      like关键字支持通配符匹配,但这种匹配特别耗时。例如:select * from customer where zipcode like “21_ _ _”,即使在zipcode字段上已建立了索引,在这种情况下也可能还是采用全表扫描方式。如果把语句改为:select * from customer where zipcode >“21000”,在执行查询时就会利用索引,大大提高速度。但这种变通是有限制的,不应引起业务意义上的损失,对于邮政编码而言,zipcode like “21_ _ _” 和 zipcode >“21000” 意义是完全一致的。
    9、 组合索引的高效使用
    假设已在date,place,amount三个字段上建立了组合索引
    select count(*) from record
    where date > ′19991201′ and date < ′19991214′ and amount > 2000
    (< 1秒)
    select date,sum(amount) from record group by date
    (11秒)
    select count(*) from record
    where date > ′19990901′ and place in (′BJ′,′SH′)
    (< 1秒)
    这是一个设置较合理的组合索引。它将date作为前导列,使每个SQL都可以利用索引,并且在第一和第三个SQL中形成了索引覆盖,因而性能达到了最优。如果索引不便于更改,修正SQL中的条件顺序以配合索引顺序也是可行的。
    10、 order by按聚集索引列排序效率最高
    排序是较耗时的操作,应尽量简化或避免对大型表进行排序,如缩小排序的列的范围,只在有索引的列上排序等等。
    我们来看:(gid是主键,fariqi是聚合索引列)
    select top 10000 gid,fariqi,reader,title from tgongwen
    用时:196 毫秒。 扫描计数 1,逻辑读 289 次,物理读 1 次,预读 1527 次。
    select top 10000 gid,fariqi,reader,title from tgongwen order by gid asc
    用时:4720毫秒。 扫描计数 1,逻辑读 41956 次,物理读 0 次,预读 1287 次。
    select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc
    用时:4736毫秒。 扫描计数 1,逻辑读 55350 次,物理读 10 次,预读 775 次。
    select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi asc
    用时:173毫秒。 扫描计数 1,逻辑读 290 次,物理读 0 次,预读 0 次。
    select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi desc
    用时:156毫秒。 扫描计数 1,逻辑读 289 次,物理读 0 次,预读 0 次。
    从以上我们可以看出,不排序的速度以及逻辑读次数都是和“order by 聚集索引列” 的速度是相当的,但这些都比“order by 非聚集索引列”的查询速度是快得多的。
    同时,按照某个字段进行排序的时候,无论是正序还是倒序,速度是基本相当的。
    三、 关于节省数据查询系统开销方面的措施
    1、 使用TOP尽量减少取出的数据量
    TOP是SQL SERVER中用来提取前几条或前某个百分比数据的关键词。
    select top 20 gid,fariqi,reader,title from tgongwen order by gid desc
    select top 60 percent gid,fariqi,reader,title from tgongwen order by gid desc
    在实际的应用中,应该经常利用top 剔除掉不必要的数据,只保留必须的数据集合。这样不仅可以减少数据库逻辑读的次数,还能避免不必要的内存浪费,对系统性能的提升都是有好处的。
    2、 字段提取要按照“需多少、提多少”的原则,避免“select *”
    这个举个例子:
    select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc
    用时:4673毫秒
    select top 10000 gid,fariqi,title from tgongwen order by gid desc
    用时:1376毫秒
    select top 10000 gid,fariqi from tgongwen order by gid desc
    用时:80毫秒
    由此看来,字段大小越大,数目越多,select所耗费的资源就越多,比如取int类型的字段就会比取char的快很多。我们每少提取一个字段,数据的提取速度就会有相应的提升。提升的幅度根据舍弃的字段的大小来判断。
    3、 count(*) 与 count(字段) 方法比较
    我们来看一些实验例子(gid为Tgongwen的主键):
    select count(*) from Tgongwen
    用时:1500毫秒
    select count(gid) from Tgongwen
    用时:1483毫秒
    select count(fariqi) from Tgongwen
    用时:3140毫秒
    select count(title) from Tgongwen
    用时:52050毫秒
    从以上可以看出,用count(*)和用count(主键)的速度是相当的,而count(*)却比其他任何除主键以外的字段汇总速度要快,而且字段越长,汇总速度就越慢。如果用count(*), SQL SERVER会自动查找最小字段来汇总。当然,如果您直接写count(主键)将会来的更直接些。
    4、 有嵌套查询时,尽可能在内层过滤掉数据
    如果一个列同时在主查询和where子句中出现,很可能当主查询中的列值改变之后,子查询必须重新查询一次。而且查询嵌套层次越多,效率越低,因此应当尽量避免子查询。如果子查询不可避免,那么要在子查询中过滤掉尽可能多的行。
    5、 多表关联查询时,需注意表顺序,并尽可能早的过滤掉数据
    在使用Join进行多表关联查询时候,应该使用系统开销最小的方案。连接条件要充份考虑带有索引的表、行数多的表,并注意优化表顺序;说的简单一点,就是尽可能早的将之后要做关联的数据量降下来。
    一般情况下,sqlserver 会对表的连接作出自动优化。例如:
    select name,no from A
    join B on A. id=B.id
    join C on C.id=A.id
    where name='wang'
    尽管A表在From中先列出,然后才是B,最后才是C。但sql server可能会首先使用c表。它的选择原则是相对于该查询限制为单行或少数几行,就可以减少在其他表中查找的总数据量。绝大多数情况下,sql server 会作出最优的选择,但如果你发觉某个复杂的联结查询速度比预计的要慢,就可以使用SET FORCEPLAN语句强制sql server按照表出现顺序使用表。如上例加上:SET FORCEPLAN ON…….SET FORCEPLAN OFF 表的执行顺序将会按照你所写的顺序执行。在查询分析器中查看2种执行效率,从而选择表的连接顺序。SET FORCEPLAN的缺点是只能在存储过程中使用。
    小结:
     聚集索引比较宝贵,应该用在查询频率最高的地方;
     在数据为“既不是绝大多数相同,也不是极少数相同”状态时,
    最能发挥聚集索引的潜力;
     复合索引的设置和使用要注意保持顺序一致;
     条件子句的表达式最好符合SARG规范,是可利用索引的;
     任何对列的操作都导致全表扫描,如数据库函数、计算表达式等,
    查询时应尽可能将操作移至等号的某一边;
     要注意含有null值时,是不能充分利用索引的;
     exist, in、or等子句常会使索引失效;
    如果不产生大量重复值,可以考虑把子句拆开,再用union拼合;
     排序时应充分利用带索引的字段;
     尽可能早,快的过滤掉无用的数据,只将必须的数据带到后续的操作中去
    从前面讲叙的内容可以看出,SQL语句优化的实质就是在结果正确的前提下,用分析优化器可以识别的SARG规范语句,充份利用索引,减少数据的I/O次数,尽量避免全表扫描的发生。
    以上内容有些是指导性的理论原则,有些是实际摸索的经验,大家在使用时应灵活处理,根据实际情况,选择合适的方法。本文中列举的实验数据仅作比对用,不具备普遍意义。大家在实际项目中,应充分利用性能监测和分析工具(如SQLSERVER带的相关工具)来检验自己的优化效果。
    此外,还有很重要的一点要提醒大家,同样复杂的数据操作,在SQLSERVER数据库级别完成的代价要远远小于在应用端用程序代码完成的代价,所以建议大家全面,深入的学习SQL语法中重要关键字的应用,如:Group By ,Having等,尽量把数据操作任务放在数据库系统中完成 。数据库应用系统的性能优化是一个复杂的过程,上述这些只是在SQL语句层次的一种体现,深入研究还会涉及数据库层的资源配置、网络层的流量控制以及操作系统层的总体设计等等,这些将在以后的文章中详细论述
    February 17

    Informix动态服务器表分片策略的计划和调整(ZT)

    Informix动态服务器表分片策略的计划和调整
    作者: itzealot


    【导读】本文介绍Informix动态服务器表分片策略的计划和调整

    数据分片允许在表一级对数据存储进行控制。表分片INFORMIX数据库的一个特征。用户可以对表中的记录或索引进行分组,并且存储在不同的位置,这样可以将数据存储到多个磁盘上,从而减少对磁盘I/O的竞争。数据分片的方案以及分片数据所存放的一组dbspace构成了分片策略。数据分片有两种基本类型:基于轮转分片基于表达式分片,对于基于轮转法分片,正如其名字一样,数据是根据轮转法方式存入表中的。基于表达式分片则根据表中的一个或多个字段对分片的规则进行定义。一般在预知查询条件时采用这种方式,从而避免查询中对某些分片的扫描。

    表中的数据"索引"进行分片主要是为了提高应程序的效率,由于INFORMIX动态服务器可以并行地扫描多个磁盘上的数据,从而实现内部查询的并行操作,因此采用分片技术可以提高查询效率。内部查询的并行化有助于减少对一个复杂查询的响应时间。表分片技术与并行数据查询(PDQ)特征联系在一起使用,这样INFORMIX服务器可以分配多条线索。从所有数据分片上并行地选取数据。此外,还可以仅仅对包含目标数据的数据分片进行扫描。从而大幅度地提高了整个系统效率。“DATASKIP"这一个特征还允许用户跳过那些出现故障或者不包含目标数据的数据分片,当某些数据所在的盘出现故障时,就可以体现出高度的数据可获得性我们通过大量的数据分片将数据分布在许多的磁盘上,也实现了外部查询的并行操作。这样在大量用户对同一个表进行访问时,可以减少I/O的竞争,每秒钟完成的事务数(系统吞吐能力)也得到了提高。表分片技术还通过对存储在dbspace上的数据分片进行备份/恢复操作。

    分片方案

    创建表创建索引时候均可以用到分片方案。索引可以附加在与其相关联的数据上,或与数据分离存放。一个索引如果出现在对表数据的分片方案中,就可以认为索引已经附加在数据上。另外一个方面,如果索引的分片方案与数据不同,就称为索引与数据分离。这种情况下,索引存放在指定的dbspace上。数据分片方式主要有两种:基于轮转法基于表达式的方案

    轮转法方案

    轮转法(PR)所使用的分片规则是系统内部定义的。使用这种方案,新追加的记录被存放在轮转法方式指定的下一个数据分片。记录所插入的第一个数据分片也是随机选定,例如,下列语法用于创建一个名为xyz的表:

    CREATETABLExyzFRAGMENTBYROUNDROBIN

    INdbspace1,dbspace2......dbspaceN

    INFORMIX不支持用轮转法方式创建索引,因为这样会降低系统性能。轮转法方案的优点在于各数据分片上数据量是比较均匀的,对记录进行更新时,并不需要对记录进行转移。然而轮转法有一个缺陷,在进行一个查询时,要扫描所有的数据分片。因此,轮转法方案不支持DATASKIP,不允许INFORMIX动态服务器越过某个数据分片。如果不支持DATASKIP,同时又有一个数据分片出现错误,那么整个查询将会失败,因为不能确定出现故障的数据分片上是否有符合条件的数据记录存在。轮转法方案适用的情况是:用户需要快速加载数据,用户预先不知道数据访问的方式。用户的数据经常更新,或者是用户对于数据分布方式未知。

    基于表达式的分片方式

    对于基于表达式的分片方案,用户可以用下面两种规则对数据进行分片

    范围规则

    范围规则用SQL的关系或逻辑操作定义表的数据分片的边界。范围规则可以包含关系操作符,比如>,<,>=,<=,还可以包含一些逻辑操作符,比如AND。范围规则最好根据表的某一个字段进行分片,但也可以根据两个或者多个字段进行分片。下面的分片实例运行效率并不很高,因为向表中插入一行时候需要进行太多的运算。所有不符合表达式条件的记录将存放在REMAINDERdbspace中。基于范围表达式的分片方案可以确保只对包含目标数据的数据分片进行扫描。

    下面是一个采用基于范围表达式分片方案创建表的例子:

    CREATETABLExyz(aainteger....)

    FRAGMENTBYEXPRESSION

    aa<=100INdbspace1

    aa>1000ANDaa<2000INdbspace2

    REMAINDERINdbspace3

    绝对规则

    绝对规则使用了SQL的关系与逻辑操作符。与范围规则不同,绝对规则运行用户采用关系操作符与逻辑操作符对规则进行定义。此外,表中可以有多个字段参与分片。

    例:FRAGMENTBYEXAMPLE

    zipcode=94536ORzipcode=94538INdbspace

    zipcode=94025ORzipcode=92310INdbspace

    REMAIDERINdbspace3

    对于以上这种分片方案,必须知道每一个邮政编码所联系的数据个数,以确保每个数据分片上的数据量比较平衡,从而使INFORMIX动态服务器减少扫描的数据分片的数目。指定分片方案时,要确保数据分片之间不互相重叠。此外,定义数据分片时可以不包括REMAINDER分片。

    分片的基本原则

    数据分片的表达式必须尽可能简单,因为执行较复杂的表达式将加重CPU的负荷。同时,数据库中并不是每一个表都需要分片,除非能从数据分片中得到显著的收益。分片的表达式因为能确保磁盘I/O操作均衡,尽管我们没必要制定一个均衡的数据分片方案。如果大量的查询只对表数据中很小的区域进行访问,那么应该用表达式将那些被频繁访问的数据分片到多个盘上,尽管这样的分片也许数据量并不均衡。表达式应该把限制性最强的部分放在前面。对表达式进行修正是为了减少表达式的计算量,减少每次访问的数据量,从而最终减轻CPU的负荷。如果表达式中第一个不等式的结果为假,那么整个表达式的结果也将为假,因此不必计算表达式的其它部分(AND表达式)。比如说,为了插入数值25,下列表达式需要计算6个不等式:

     x>=1andx<=10indbspace1

     x>10andx<=20indbspace2

     x>20andx<=30indbspace3

    如果用如下表达式,则只需要计算4个不等式:

     x<=10andx>=1indbspace1

     x<=20andx>10indbspace2

     x<=30andx>20indbspace3

    分片的表达式中应该避免数据类型的转换。例如,日期数据类型在表达式中内部转换为整数类型。对于频繁更新的字段进行分片,会带来许多管理上附加工作。例如,如果根据一个日期字段进行分片,而超过保存日期的记录被删除,那么包含超期数据的数据分片将最终变空。这样就需要删除旧的数据分片,并为最新日期的记录创建一个新的数据分片。

    分片策略的设计

    一个分片策略包含数据分布方案以及数据分片所存放的一组dbspace。制定数据分片策略时需要根据分片的目标以及数据库的信息,诸如硬件/软件特性、查询特性、数据分布等作出决策。同时还需要知道一个现存的未分片数据库是否做转换,以及是否需要临时创建相应的应用程序。在前面的例子中,已经预知查询的方式,则可以加以利用。我们还应考虑到查询方式在将来的不断变化,诸如数据库的区域和/或帐户的附加部分,这一点也很重要。

    数据分片的目标包括最大程度的内部查询并行化、外部查询并行化、提高数据可用性、更细的备份/恢复粒度以及更强的数据加载效率。

    数据分片获得内部查询并行化:是指INFORMIX动态服务器充分发挥数据分片PDQ功能的优势,并行地处理一个复杂的查询。这是决策支持系统(DSS)一类应用程序的主要目标。DSS查询从一个表中顺序读出大量数据记录。我们推荐使用数据分片。选择轮转法分片方案还是基于表达式的分片方案取决于查询特征、数据分布等因素,一般来说,当用户不能确定根据表中哪一个字段做基于表达式的分片,从而保持数据分片的均衡,或者不知道数据访问的方式时,我们推荐采用轮转法方式。轮转法方式不支持对索引的分片,因为扫描线索要越过分片的边界去读取索引,这样会导致效率的下降。分片策略还应该确保数据均衡的分布在不同的数据分片上,确保并行顺序扫描能均衡地完成。

    数据分片获得外部查询的并行化:是指在大量用户运行较小的查询、返回少量的数据的条件下,INFORMIX动态服务器最大程度提高性能的能力。一般来讲,对于存在大量用户,需要实时响应的应用程序,称为联机事务处理(OLTP)OLTP查询总是在同一时间访问数据的一小部分区域,总是随机地对一些数据行进行更新或者删除操作。这些操作总是和索引扫描有关。在这种情况下,应该用表达式将数据表和索引表进行分片,从而允许查询在扫描过程过中某些数据分片。如果不考虑I/O竞争,数据分片和索引分片可以在同一个盘上,并使用同样的分片策略。另一方面,在一个大系统中如果额外有空余的盘,并且磁盘I/O可能成为潜在的瓶颈,那么最后将索引单独建在一块盘上。调换一下顺序,当按照某一字段创建索引时候,如果每一个查询都根据同一字段访问数据时,我们也可以使用与数据分片不相同的策略对索引进行分片。这种情况下,最好在WHERE子句中使用另外一个字段,分片策略的理想化程度取决于数据的分布和对表的查询的分布情况。我们的目标通过数据分布消除I/O瓶颈,尽管每个数据分片上的数据量可能不太均匀。

    数据分片增强数据可获得性:是指可以在某些数据分片发生故障的时候,数据库仍然能接受应用程序的查询请求。这种能力是有INFORMIX动态服务器的DATASKIP特征提供的。

    数据分片增强数据加载的性能:尤其适用于周期性地加载几个G的数据,从而需要快速加载技术的大型应用程序。将数据分片到不同的磁盘上,可以使数据自动地进行并行加载,这是通过使用多个I/O流向数据分片所驻留的磁盘上写数据而达到的。轮转法分片方案应该最能保证快速数据加载,因为复杂表达式的计算会加重CPU的负荷,如果采取较简单的表达式并将每个数据分片放在单独的盘上,用基于表达式的分片方案同样可以保证快速加载数据。

    以下是确定合理的分片策略所必须的步骤

    硬件/软件特征

    要搞清楚硬件平台,如CPU的速度,数目,磁盘数目,大小,磁盘控制器的数目,以及与每个控制器相连接的磁盘数目,等等。这些信息对于确认表分片的数目以及怎样存放数据分片以减少I/O竞争,都是十分有用的。除了可用的磁盘外,对于每个表的数据分片的数目都有一定的上限,这些限制与分片的目标有关,如果分片的主要目的是增强内部查询的并行程度,那么系统CPU的数目和数据总线的带宽将限制一个表所能得到的并行线索的最大数目。另一个方面,如果分片的主要目标是增强外部查询的并行程度,那么分片的数目可大于CPU的数目,从而保证数据分布在许多磁盘上,在OLTP条件下可以允许用户并发地访问不同的磁盘,然而,当数据分片的容量变小的时候,应用程序会寻找多个数据分片,同时对寻找的结果进行合并。这些都会降低查询的效率。

    对于具有高速CPU和低速盘的系统,每个表的分片数目可以超过物理CPU的实际个数。

    所选的硬件平台的操作系统类型和编译器对选择分片方案也是一个重要的因素。有的操作系统擅长处理MOD操作以及数据类型转换。

    了解查询的特征

     

    要了解一个应用程序到底是OLTP还是DSS类型,还要了解SELECT语句查询用的频繁还是update/delete操作频繁。如果查询多用SELECT语句,还要确定带有“groupby","orderby"等复杂子句查询的执行频度。对于这些情况的了解有助于平衡I/O,消除瓶颈。检查每个SELECT查询的选择性以及返回数据的比例。如果一个查询的选择性(selectivity)很大,就需要为查询创建索引。检查有无JOIN操作,并确认JOIN操作的主码是什么。如果在DSS查询中总对某一特定的表进行JOIN操作,那么这个表应该被分片到不同的磁盘上以避免I/O瓶颈。检查每个查询的查询条件。最后将所涉及的表中的字段画一个矩阵。接着将某一查询中用做查询条件的字段填上“+”字符。有了这个矩阵,我们可确认在所有的查询中,哪个查询条件最常用。这一信息与每一查询的执行频度一起,有助于确认对哪个字段做基于表达式的分片收益最大。检查数据是怎样被访问的,即数据是通过顺序读取还是通过“INDEXSCAN"被访问。为每一个查询配备“SETEXPLAIN"子句,加上表的模式信息,可以达到以上目标。

    数据分布及特征

    确认表中用户查询条件的字段的取值范围。确认表中每一取值范围内符合记录的个数。在许多DSS类应用程序中,结果是从几个GB的数据或几个月,甚至一年的数据中得出来的。在这种条件下,很容易确认某一州,某个城市的记录数,或者是整个月的数据供以后使用。如果大多数查询将某个州和某月作为筛选条件,那么这些字段是参与基于表达式的分片方式的最佳选择。此外,还应了解表中数据被修改的速率,诸如增、删、改等。

     

    数据分析系统性能调整(ZT)

    银行数据大集中之后,业务部门越来越迫切地希望能从现有的数据中找到对开展业务有价值的信息,提供更多的辅助功能。在此背景下,出现了各种各样的分析系统,有的银行正在规划数据仓库(DW)的开发,有些银行已开发了客户关系管理(CRM)系统。
      DW与CRM都以数据分析为基础,有的称之为决策支持系统(DSS),有的称之为商务智能(BI)。但无论是CRM还是DW,都不容易实现,即便在欧美发达国家已经有了成功的实践经验,国有四大商业银行的账务数据量之大和客户数之多可能是欧美任何一家大银行都无法相比的。在欧美,如果银行的客户数或账户数超过一千万就是大型银行了,与我国四大国有商业银行的一些省级分行的数据量相当。
      要在四大国有商业银行实施数据分析系统,即使使用最先进的计算机设备,最先进的应用系统,最科学的算法,都不得不面临一个共同的问题——性能调整。

      一、数据分析系统与联机交易系统性能的度量区别
      数据分析系统对响应速度的要求虽然没有联机交易系统高,但也有一定的业务要求,每天增量的数据转换、装载、抽取、更新等必须在规定许可的时间内处理完。
      响应时间和吞吐量仍是数据分析系统最为关注的两个问题,与传统的OLTP系统不同的是:
      1.OLTP系统重在联机事务处理的响应速度、吞吐量;数据分析系统重在查询,只有少量的联机事务处理,其吞吐量主要表现为单位时间内允许的查询数。
      2.OLTP系统的查询交易一般仅返回一条或很少的记录;数据分析系统的查询有两个响应  ①从提交查询的时刻到第一条记录返回给最终用户时刻之间的时间,②从查询提交到返回所有记录之间的时间。

      二、数据分析系统性能调整的过程
      1.首先建立并定义性能指标。在系统正式投入生产之前就有明确的性能需求,数据量与要求实现的功能决定了要采用的系统平台。
      2.制定并实施性能监控方案。如什么时候监控,监控的周期,并及时记录监控的结果(包括各应用程序运行时各类资源的占用情况、响应速度、各数据表的数据量及访问频率等)。
      3.根据监控记录分析各度量元素(响应速度、吞吐量、CPU、内存、I/O等)是否满足预期定义的指标。
      4.确定主要约束是CPU、内存、网络,还是I/O,如CPU已达到或超过85%的利用率等。
      5.确定可以调整的资源。了解哪些方面可负担得起性能改进,哪些资源可承受附加的负荷。
      6.调整数据库配置。每次更改一个,最好不要同时更改多个参数。
      7.如果调整数据库配置不起作用,则应调整操作系统或硬件配置。
      以上是一个重复的过程。

      三、应用设计
      性能调整不仅是系统管理员的事,更需要应用开发人员的配合。不好的应用设计会吞噬掉机器的性能。
      1.使用存储过程
      为了提高处理性能,应尽可能采用存储过程而不采用嵌入SQL。存储过程主要有以下优点:
      (1)同发出单一的SQL语句或发送整块的PL/SQL文本到服务器相比,信息只需发送一次,减少了交互,通过网络传送的信息量较少。
      (2)存储过程经创建、分析、认证、编译等处理后,存放在数据库管理系统(DBMS)服务器,SQL语句是静态的,可以即时调用,执行时不需要再编译。如果存储过程已经在共享内存中,就不需要从磁盘中读取,可以立即执行。
      (3)减少对内存的需求。多个用户执行时,只需将过程的单个拷贝即可,多用户共享同样的代码。
      (4)连续的执行以较小的开销实现,从而改善性能。动态SQL每次运行都需要较大的预处理开销。与表和索引一样,系统可以收集存储过程的统计信息,优化器可以创建最合适的访问计划。
      有数据表明,实现同一个功能,采用存储过程只需采用嵌入SQL的20%的时间。
    使用存储过程还比较安全,存储过程的执行需要有该存储过程定义者或所有者的权力,这样就限制了用户能够执行的数据库操作。同时,使用存储过程还能提高软件开发的生产率,可以把存储过程看成面向对象设计中的经过封装的类,其他存储过程或应用程序为完成某个功能,可以继承该存储过程而不需要重写SQL语句。如果需要修改该存储过程功能,也不必对所有继承该存储过程的应用进行修改,可使修改的工作量降到最小,保证了应用程序的完整性与一致性。另外,存储过程也是可重用的单元,对提高可靠性也有所帮助。
      2.使用C程序设计语言作为补充
      不要使用C++程序设计语言处理数据,更不要使用Java程序设计语言。在所有的高级程序设计语言中,C程序设计语言的运行效率是公认的,可以使用C程序设计语言作为补充。存储过程有自身的缺陷,如编程语言SQL功能较差,与编程环境集成不够,移植性差,能提供的内部功能函数有限,执行过程中能提供的信息有限,不便调试等,对于一些特定的业务需求目标和数据的具体情况,可能用嵌C更好。
      3.建立索引
      建索引是提高数据访问效率的重要途径,但建索引有时并不一定能起到作用,索引不能满足未知需求,有时会适得其反,降低系统性能。关于索引,可归纳出以下几点:
      (1)索引数尽量少。当要在一个合理的时间内结束查询时,应避免添加索引。过多的索引会降低更新操作的速度并消耗额外的空间,使磁盘有效使用率降低,增加系统的复杂性和管理成本。低速查询不一定表示数据库或索引有问题,很可能是程序有问题。
      (2)基数较大的列很适合用来做索引。如果索引的惟一值有限(如<100),则不宜使用索引。
      (3)最好不选择大的列作索引。
      (4)考虑到管理上的开销,应避免在索引中使用多于 5 个的列,避免覆盖多个查询的大型索引。
      (5)对于多列索引,将查询中引用最多的列放在定义的前面。
      (6)添加与已有索引相似的索引会给优化器带来更多的工作,降低更新操作的速度。如果需要,可以修改已有的索引,使其包含附加的列。
      (7)在经常进行连接,但没有指定为外键的列上建立索引。
      (8)在频繁进行排序或分组的列上建立索引。
      (9)在需要时建群集索引。群集索引允许对数据页采用更线性的访问模式,允许更有效的预取,并且有助于避免排序。这样查询操作会更快,但插入操作会慢。适合插入更新频率不高的表。
      (10)确保最优的索引使用。
      4.优化查询
      优化查询的出发点是如何减少查询的资源利用:减少I/O,减少运算量。可以用Set Explain命令分析各种查询语句的效率。
      (1)把频繁使用的小表放在内存或高速缓存中,可以明显减少I/O。
      (2)减少所读的行数和所读或更新的列。如,仅读取满足条件的第一条记录,仅读取或更新必须的列。
      (3)用临时表缩小查询范围。
      (4)尽量避免子查询和明确关联的子查询。
      (5)避免复杂规则表达式。
      (6)尽量使用数据库引擎提供的函数,如:sum,avg,min,max。
      (7)尽量使用连接而不用嵌套循环,避免连接长字符串。
      (8)尽量用Where缩小连接范围。
      (9)避免不必要的大表的全表搜索。
      5.数据结构与算法设计
      (1)尽量采用整数类型
      整数是最常用的数据类型,在运算字符串变量时计算机先把字符串中的每一个字符逐一转换为整数,然后再对每一个整数分别进行运算。计算机软件处理整数的效率要比处理字符串快2n倍,其中n是字符串中字符的个数。
      所以,在设计表结构时,一些计算时频繁用到的字段,如分支机构代码、系统用户代码、客户代码等,应尽量采用整数类型。
      (2)少用可变长字符串
       对少于或等于30个字节的字段,应避免使用可变长字符串(VARCHAR)数据类型。在这种情况下,VARCHAR类型通常会浪费空间,所以建议使用CHAR 类型。如果数据量很大,空间的浪费往往会对查询时间造成影响。
      (3)数据模型
      为了减少数据冗余,数据建模时一般都需要规格化达到第三范式,如果需要冗余也是因为外键关系和数据引用完整性的需要。适当的非规格化虽然需要占用更多的空间,但通过减少频繁的连接、聚集和推导可以提高数据查询的性能。例如,客户经理号与客户经理名,客户经理名依赖客户经理号,如果在客户经理业绩表中仅有客户经理号,在查询客户经理业绩时就需要做表的关联,从而降低查询响应速度。非规格化以数据更新和数据空间的损失为代价换取数据访问的优化。一般的非规格化形式有:列复制,创建数据阵列,预连接表,预聚集数据。
      (4)算法设计
      良好的算法,对提高性能有很大的帮助。对于一个业务功能,可以用多种算法去实现,因此应该评估每种算法的执行效率,从而选择最优算法。
      这里说一下排序。是排序,就要耗费资源,所以应尽量减少排序,避免不必要的排序,简化排序。可以将数据放在临时表中以避免排序,减少所需排序的行数,用简单关键字排序,排序较少或较小的列,以简化排序。
      如果要排序应尽量使用内排序,避免使用外排序。外排序和内排序相比较要慢很多,而且磁盘排序会消耗临时表空间中的资源。
      四、数据库系统参数调整
      OLTP系统为了达到更新交易吞吐量的最大化,一般使用缓冲日志,增加物理日志长度,最大化写入缓冲百分比。为防止任何DSS类型的查询占用系统资源,可通过将相关并行查询参数配置设为较小值以限制并行查询的资源(如Informix的PDQPRIORITY、Oracle的PQO并行查询选项、DB2的INTRA_PARALLEL、CURRENT DEGREE等)。
      要使查询引擎处理的查询数最大化(吞吐量),以Informix为例,可以将相关的并行查询参数设为PDQPRIORITY≤25%。
      要使单个查询的处理时间最小化(响应速度),可设置PDQPRIORITY=50%,最好采用快速CPU多处理器。
      以上看起来似乎有些矛盾,但应根据实际情况平衡优先级。在不同的运行时间或针对不同的执行任务,使用不同的设置。例如,日常工作时间用户数较多时,将PDQPRIORITY设置为较低,同时限制一些大数据量的查询,大数据量的查询可以放在非工作时间做,可设置较高的PDQPRIORITY。
      一些数据库管理系统允许用户设置页面大小,如DB2,对于OLTP应用程序采用较小的页面更为可取,这样消耗的缓冲池中的空间更少。对OLAP应用程序,通常使用较大页面,可以减少在读取特定数量的行时发出的I/O请求的数量。较大的页面还可以减少索引中的层数。但是,如果行长度小于页面大小的1/255,则每页中都将存在浪费的空间,因为每页最多只能有255行(对于索引数据页不适用)。在这种情况下,采用较小的页面大小或许更合适一些。
      DB2、Informix、Oracle都有许多参数可以调整,这里不一一叙述。
      五、硬件系统方面的考虑
      对于数据分析系统而言,由于系统用户较少,网络一般不会成为瓶颈。所以系统方面主要考虑处理器、内存和磁盘,原则是并行性相较于速度而言对提高性能更有效。
      对于大型分块表,使用多CPU可以并行搜索每个分块。增加CPU个数可以支持更多的用户数并增加并行性。CPU越快,越能支持复杂查询和大型数据库。处理器的缓冲区越多就越快,多层缓冲可以帮助平衡处理器负荷。
      一般来说,处理器、内存越多越好,但在现实环境中,数据处理的瓶颈常在输入/输出上,存储器与计算机间的数据传输速度比计算机运算速度一般慢2~3个数量级,磁盘速度的提高远远落后于CPU。我们在多个数据分析系统中发现存在I/O瓶颈。
      系统中磁盘利用率一般不应超过45%。磁盘除了考虑磁盘机速度、控制器与通道速度外,还要考虑当前和最大驱动器数(磁盘多多益善,多些小驱动器比少些大驱动器好,新驱动器较快但较大)。
      如果为了提高可靠性使用了RAID磁盘设备,为提高I/O性能,最好采用RAID10而不是RAID5。在DB2中可以用DB2_PARALLEL_IO注册表变量,强制对由多个物理磁盘组成的单个RAID容器表空间执行并行I/O。
      使用裸设备、对存储空间分块可以显著提高系统性能。
      1.使用裸设备
      I/O操作有两种方式:文件系统或cookied file(熟文件)和裸设备Raw I/O(或原始设备、生设备)。
      文件系统又分为缓冲(Buffered)I/O、内存映射(Memory Mapped)I/O、DIO、CIO。以往最常用的文件系统为Memory Mapped I/O、Buffered I/O。DIO可以在文件系统级越过caching,减少CPU负载。2003年IBM在AIX 5L version 5.2.10文件系统JFS2推出了CIO,包含了DIO的优点,多线程可以同时读写共享的文件,但性能仍比裸设备Raw I/O低。
      与文件系统相比,裸设备有以下优点:
      (1)空间是物理连接的,由一大块相邻磁盘空间构成,数据库管理引擎不需要跳过磁盘寻找数据时,能大大提高性能。熟文件的磁盘空间可能由多个Unix文件共享。连续的磁盘空间是设计表格与索引的重要因素。
      (2)数据直接在共享内存与磁盘之间传输,不需要操作系统缓冲过程,从而加快了响应速度。数据库管理引擎对数据库操作优化I/O,避免其他涉及操作系统的步骤,而文件系统的实现要通过caching和锁机制。
      (3)利用裸设备能更好地保证系统出现故障时恢复数据。
    当然,文件系统使用比较方便,Raw I/O对存储管理要求比较高。I/O按性能速度从高到低为Raw I/O、CIO、DIO、Memory Mapped I/O、Buffered I/O。有许多测试表明,裸设备比熟文件快15%~25%。
      2.磁盘分区
      DB2、Informix、Oracle建表时都可以确定Extent初始值。Informix建议Extent不超过33个。DB2对Extent Size的建议为估计空间大小/4k×16M 。Oracle Extent的管理很灵活,除了操作系统自身的限制外,可以指定Extent数量的最大和最小值。
      数据分析系统包含了当前和历史的数据,一般数据量都很大,需要分布存放。一些数据库管理系统有限制:如在一个分区上的总页数不能超过16M页,如果超过这个限制,为了提高性能则需采用分布存储方式,把数据存放在不同的物理设备上,通过并行读写可以有效利用多磁盘的I/O带宽,实现真正的数据分布并发处理。如果存在磁盘瓶颈,应确保表空间分布在所有可用磁盘上。如果磁盘利用率仍然很高,可能需要更多的磁盘。
      数据分块的方法有范围分割法、哈希分割法、循环分割法、表达式分割法等,哈希分割法普遍使用于数据仓库。如:对于交易数据可以按交易日期存放,对账户数据可以按所属分支机构存放。各数据库管理系统可以采用的分割法可能不同。
      给数据对象分配空间时应注意:
      (1)把频繁访问的表尽量放置到不同的表空间中。
      (2)把索引和表数据分开放置到不同的表空间中。
      (3)高增长表不要放到同一个表空间中。
      (4)把经常使用的表存放在磁盘中间。
      数据分布存放的另一个好处是,可以提高数据的安全性,某个表空间损坏不至于影响到其他表空间。
      六、运行规划
      数据分析系统必须每天装载、更新生产交易系统下传的数据。系统从初始化开始正常运行后,数据会随着业务的增长而增长,分析功能及用户也会随之增长。每天在生产交易系统下传数据到达后,需在规定的有限时间里完成这些任务。所以做好运行设计,不但要考虑现在每天的任务安排,还要考虑未来的增长情况。
      运行规划包括以下几个部分:
      (1)首先确定批处理系统可用时间窗口和终端用户可用时间窗口。例如,每天早晨三点收到总行数据中心的数据,终端用户在上午九点就要查看到最新数据,这之间有六个小时可以用来做批处理。
      (2)确定任务完成窗口。估算数据抽取、清理/转换、装载需要的时间,估算汇总统计、更新等正常业务功能处理需要的时间,各种查询的响应时间,各种任务的执行周期等。确定哪些必须在终端用户工作时间之前完成,哪些可以在终端用户工作时完成,哪些可以在终端用户工作时间之后完成。
      (3)计划性维护。确定何时维护及维护的内容。随着时间的推移、用户需求的改变,有的数据会过时,应将其定期归档,把长时间不用的数据转移到其他设备中予以存储,删除休眠数据,清理脏数据。还要考虑备份,包括备份的数据量,备份所需时间,备份的级别,何时备份,备份的周期等。
      定期更新数据表的统计信息是计划性维护中一个很重要的任务,如运行DB2的runstats on命令、Informix的update statistics for命令等,这些统计信息直接影响查询的执行计划。DB2有一个实用程序REORGCHK,如果运行RUNSTATS后仍不能改进性能,REORG实用程序可以选择根据指定的索引将数据重新排列成一个物理序列。对有大量更新的表,如果统计信息后性能提高不明显,可以删除和重建索引。
      (4)纠正性维护。包括允许维护的时间,允许多少故障时间和恢复时间。
      一般情况下,银行购买产品后很少做参数调整、程序优化等方面的工作。针对机器出现的性能方面的问题,生产厂商也往往是推出系统升级方案。而银行数据分析系统同交易系统不同,由于其需求不断增加,没有确定的边界,因此,性能调整也是一个没有结束的过程,若要最终达到资源极限,则需要升级硬件。

    聚合策略中选择OLAP还是聚合表(ZT)

    为了实现对出于做报表和分析的需要所作的查询做出最快的回应,数据库系统面临着艰巨的挑战。这个挑战突出了数据库设计中的一对根本矛盾:即最快还是最好。数据库可以存储最小单位的数据量以保持运行速度最快;但是使用者在这种低级的存储水平是很难完成报表或分析的。用户是在总结这样高层次的标准上使用这些数据。而且他们要求完美的查询结果。
    面对这种挑战,我们开发了一种策略,使用数据聚合,或者是预先摘要数据。这种聚合策略能够完全评价整个数据库的成就。底线是可获得完美(或至少可接受)的查询结果,除非人们不愿意使用数据库。
    聚合策略一般依靠两个技术:OLAP和相关聚合表(和有关聚合意识相关技术,如Oracle 8i 和 DB2 UDB V8)。当一些DBAs依靠相关聚合表开发策略,并不认为同样要使用OLAP。相反的,我看到很多报表和分析的基础是过多的依靠OLAP而没有考虑聚合表技术。这正是我今天在这里想说的,如何选择,以及使用何种技术处理各种聚合。
    也许最流行的聚合方法是使用聚合表。有时这种方法可以采用新的表计划形式以支持不同的数据结果,但比数据库粗糙,而有时,可以采取物化的形式,即依靠聚合表优化查询,但是这些查询常常隐藏在直接查询的背后。有时候两种方式同时使用。不管在什么情况下,这些表能够大大提高查询的执行情况。当培训工人使用这种技术时,有大量的相关查询工具和书写报表工具。所有这些聚合表的采用以提高查询的执行是一个具有实践性,高效的方法,但是使用OLAP也可能是一个更好的方法。
    一些DBAs不愿意考虑使用OLAP是因为他们还没有用过它,或者是因为与他们所用的查询工具不兼容。但是兼容性问题已经变得越来越不重要了,特别是在两个OLAP DBMSs Essbase和Microsoft Analysis Services的领导下。现在所有最新的工具都支持Essbase,意味着使用相关的工具查询相关数据同样也可以用来查询OLAP数据。Analysis Services使用一个OLAP数据存取层(面向OLAP的OLE DB)即它与相关数据存储层(OLE DB)是兼容的。它容许将查询分解成OLAP数据并将该数据提交给相关装置。甚至具有更强的通用性也不再是遥远的梦想。正如九月,George Spofford在一个智能企业的议题中说:“随着以计算机为模式的网络服务的大量出现,该模式为不同的系统连接创造了新的,更好的方法,整个情形都变了:现在,分析更容易与其他计算相互作用交织在一起。”我想说的是OLAP数据变得越来越能与相关数据兼容了,我们在这一点基础上可以考虑现有技术是否可以提交所需的整个聚合数据。
    一旦编报表的人发现OLAP,他或她会发现使用OLAP的优点。在多数情况下,OLAP通常要比其他查询完成的更快(尽管有时不如聚合表快)。但是另一个显著的优点是对查询的适应性强。轻松的以任何维度、级别或数量就能回应出以列或行显示的一套结果是特别具有吸引力的。Analysis Services使用MDX(多维表达)语言,而不是(SQL),来提取OLAP数据。这种查询语言(和多维的OLAP索引)能大大加强其适应性。Essbase还提供可自由使用他们的API或添加电子数据表。从任何维度,级别和数量上呈行或列的显示,SQL通常会要求查询一个CASE的综述具有SUM或其他合计功能。或者它要求从柱型列表资源转换成以行显示的结果中查询专门表以获取想要的数据。不论使用何种方式,如果被查询的表不是行或列的形式,使用SQL查询都会很复杂且执行的处理密度大。另外,OLAP提供大量的分析函数以完成整个运算中的各个部分运算,配置和计算在聚合级别的数据,虽然很复杂,但是很有用。总而言之,OLAP的速度和适应性使其在聚合策略下的数据存储系统中成为一个有吸引力的选择。从另一方面看,依赖OLAP过多也不是一件好事。将过多的查询加在OLAP上的结果就像一个厨房水槽的管道,是一个有着多维和过多数据的立方体,立方体将会出现堵塞,或者对它在作任何改变就会出现这种结局。所以坚持使用这样一种立方体就像一个初级的报表或分析表回应任何查询的变化,实际上这是不可能实现的。
    不难想象你怎么处理厨房水槽的管道。在起初有关报表和分析的查询时用一个立方体就可以满足,所以对二者都可以使用OLAP。这样做是高效的,且能确保你的报表与分析表轻松衔接(既然他们有相同的即时数据资源)。然而,逐渐的,新的要求增加了,商业规则也变了。新的维度,数量,计算和新数据要求被加入这个立方体。虽然一段时间,立方体赶上了变化,但是从另外的角度而言,一种变化的出现导致数量的增加,进而引起查询过程处理时间的延长。OLAP的开发者知道维度和数量的增加会在数据库容量和处理时间上发生数据爆炸,或者说是指数型增长。这是由于交错空间的矩阵聚合是一定被计算的。当承受过多的数据或者过多的空间时,数据爆炸导致的过多需求也会使最好的OLAP深陷泥潭。从这一点而言,应该意识到对OLAP立方体的要求太多了。
    当你将报表查询从分析查询中分离出来通常会发生什么呢,你会使用OLAP仅作为分析查询,而用聚合表做报表查询(可以实现但不一定产生最好的结果)。这种重新的设计,可能是又费时又费力。如果你在深陷泥潭前,一开始就将分析查询和报表查询分开,并考虑你的支持系统需要多少变化,那就会轻松的多了。我曾经不止一次有过这样的经历,我愿意将我的一些心得与所需之士共享。
    首先要采取以下行动:
    1、发展和明确哪种聚合是最经常被查询的。如果你还没有建立数据库,你需要询问用户,查阅现存的报表和预测分析。如果你已经建立了一个数据库,审视你的系统,找出哪种聚合是最经常被查询的。Oracle, DB2和Analysis Service都有收集这种信息的方法。对较为频繁的查询,要建立优先查询的概念。比如,这种查询是紧急的,还是不是?
    2、要理解对聚合需求的延迟性。对某些人而言,花很多时间处理和计算,从而出现延迟是一个问题。延迟更新选择的具体观点向数据不一致打开大门取决于查询是取具体的数据还是取基础表中的数据。对有些用户这不是问题,但对其他人则是一个问题。较低的延迟聚合OLAP一般而言没有什么问题,尽管依赖于数据的分配,涉及的数据量以及你所用的OLAP数据库的独特之处。
    3、确定什么是文本数据,比如地址,超链接等等,需要在聚合数据旁予以提示。直到在出现采用OLAP标准的XML前,用OLAP聚合数据系统整合文本数据是极度困难的。
    4、前端工具的选择是一个要着重考虑的问题。有时它会促使后端数据的决定。合理的数据库和OLAP各自有自己的作用;对于以组织为单位,或者以产品分类的长篇累牍的报表的查询,足以显示相关技术实力。而轻松使用以图形表示的查询方式则是OLAP的实力之所在。介于这两个极端间的各种技术都应该被考虑。
    5、确定哪种聚合是报表服务器计算的,哪种聚合是数据库或OLAP服务器计算的。在报表服务器中重新聚合是浪费时间,除非他们是一些特定查询模式。
    6、 如果OLAP和相关技术显示都可以处理聚合数据,则都可以使用。如果可能,多试用几个OLAP数据库,或者至少要向已使用过不止一个OLAP数据库的人士咨询。主要的困难在于对各个OLAP数据库在泛函性,可测性,可支持的操作平台,以及能否轻松使用和其他方面的比较。
    7、对于支持聚合策略的聚合表和OLAP要保持开放的思想。有可能你两种都需要使用。但是不要假定你应该只使用其中一个,而在特定时刻使用另一个。最佳方式是保持开放的思想,而不是完全依赖卖方的建议,并且让你的系统工程师对相关技术和OLAP技术都接受培训。
    8、在你知道你需要的聚合数据不能存储是由于OLAP存在设计限制时,你可以使用聚合表。(比如,在Analysis Services下,你不得不在一维限制适用地查询聚合数据中使用父子型的方式。或在Essbase,你不得不频繁使用以元为单位的"动态计算"来减少处理时间。
    如果你已经有了一个报表系统,给你介绍一些警告标志,表明你没有充分使用OLAP聚合技术;
    1、在更广泛定义的分析需求下,为了集中新的聚合数据,你要不断地添加新的聚合表(比如,实际支出对预算不一致的分析,或提升效率性分析)。
    2、你的查询会越来越复杂,因为他们执行了分配,以行列为形式的混合单位的计算。尽管相关管理人士DBMSs在这个领域增加了多个函数,但是这些分析聚合运算就OLAP数据库而言太长了。你也许会发现有更好的函数和更简单轻松使用这些计算的方法。
    3、你的报表会变得非常复杂,要花很多时间制成,因为你的报表服务器在执行以上的运算。
    4、你有如此多的聚合表,那么数据存储,处理时间和保存都成为问题。在这一点上可以考虑使用ETL工具,但是OLAP也应该被考虑在内。
    5、当具体观点更新,或变成一个议题时,要锁定争论的焦点。
    6、要考虑购买新的硬件以提高查询的执行情况。
    7、你的DBA不熟悉OLAP。
    如果你已经装了报表系统,这儿有些警告标志,当你使用OLAP过度时,那么聚合表也许更有效。
    1、报表服务器再次聚合低级别的OLAP数据而不使用OLAP聚合。大多数人没有意识到他们的报表服务器也许做了远超过用户需要的数据聚合。
    2、立方体要花费很长时间处理添加的新维度或其他变化,添加更多的数据使他通过你的处理窗口。
    3、多个维度(10维以上)来自同样的资源表。比如,有个产品维度,以及产品类型,产品尺寸,产品颜色等。在这个例子里,四个都是来自相同表的维度。即使Essbase有特质维度,Analysis Services有实质维度用来处理这些一对多关系的数据(效率更高的是多对多),处理这些关系数据使用相关技术会更有效。使用相关技术,产品、产品类型、产品尺寸、产品颜色将都会在一个数据表中。如果新查询迫使我们添加20个这样的维度,使用聚合表更容易实现。比使用相关技术执行的更完美。
    4、OLAP立方体具有维度间的不相关性(潜在的数据交集是不存在的),仅支持来自一个立方体的报表查询。
    5、OLAP聚合数据的补时会淹没服务器。
    6、你在考虑购买新硬件以提高查询的完成质量。
    相关技术和OLAP技术仍然很难创建明确的规则,什么时候使用OLAP,什么时候使用聚合表仍旧是个难题。但是认真考虑支持你的聚合策略的两种技术将会是非常值得的。
    February 08

    信息化建设要警惕BI陷阱(ZT)

     

    笔者所在的公司是一家意大利独资的制造型企业,8年前进入中国市场时就引进了当时还是非常领先的一套ERP系统,该ERP系统在当时的环境下几乎是外资企业惟一的选择,因为进入中国的产品还非常少。

    几年下来,公司的发展速度已经越来越让人感觉到ERP系统的局限性,尤其是该ERP的数据呈现能力非常差,且基于人才难觅的IBM AS400开发体系。为了达到管理和流程的要求,公司不得不耗费大量的资源开发各种解决某些具体问题的报表分析工具。由于业务变化迅速和人员的更替,这些定制的报表成为管理可持续性发展的一个巨大障碍。而事实上,没有系统规划的,就事论事的报表开发和数据呈现方式永远也无法真正达到管理集成化的目标,很难对管理决策起到真正战略性的指导作用,也无法构建出真正意义上的企业智能系统。

    作为中途切入的信息系统的负责人,这种现状让笔者常有如芒在背的感觉。如何整合资源,建立结构化的高效的商务智能分析体系成为一个长期的心病。经过几年的搜寻, 始终没有找到一种能和现存ERP进行无缝集成的分析系统。大部分产品只是商业智能系统开发工具,并不提供对相应ERP的现成的数据分析系统。

    终于有一天获悉公司目前使用的ERP的提供商开发了一套基于该ERP的“企业业绩分析系统”,其平台为当今业内极为领先的Cognos和Data Stream。不需要任何中间件和接口开发,这无疑是天衣无缝的解决方案。然而,项目的进展出乎包括顾问在内的所有人的意料,原来信誓旦旦的一个月变成了长达半年多的时间,至今仍然没有真正使用起来。这在本人项目经验中是前所未有的现象,也是在管理层和顾问看来非常“可耻”的教训。

    时至今日,随着对BI系统的理解的加深和对整个项目进程的回顾,才发现商业智能应用的规划、设计、开发、实施是一项极其复杂的系统工程。我们对BI系统的把握实在是肤浅,而这种肤浅就是企业陷入BI陷阱的根本原因。以下总结希望能够对正在实施或者计划实施的企业有些启示。

    统一协调,全局规划
    BI 系统由于是构筑于所有的业务系统之上,有着独特的复杂性和全面性。BI系统决不仅仅是一个单纯的IT项目的实施,它涉及到企业经营管理的各个方面,需要上至公司高层领导下至基层业务人员的大力配合。实施这样的系统的难度和所需要投入的资源远超于普通的业务支持系统。企业必须进行缜密的思考和全局的计划,把 BI软件纳入企业软件管理的整体战略之中。全局规划不仅要对项目实施队伍做出规划,同时还要对项目后续的部署维护和功能的增强完善所需要的资源做出规划。商务智能计划必须有一个整体的愿景和路线图,否则,就很难统一起来。

    在更细节化的层面建立逻辑化、系统化的方法对于项目成功也是至关重要的。在笔者公司,BI项目的开始并没有做到全局规划,统一协调。尤其是对资源的协调准备不足。虽然上下目标一致,但实际实施过程中业务部门并没有真正地投入足够的资源,潜意识里仍然把此项目看作是“锦上添花”的额外负担,这为以后的实施不畅埋下了伏笔。

    报表系统和BI有区别
    实现现有业务报表的问题常被作为BI应用的开始,笔者所在的企业亦是如此。虽然务实,但却是一个陷阱。传统的报表系统和BI是有本质区别的。传统的业务报表系统针对分离的事务处理而设计扁平系统,并不擅长于结构化的的分析和统计。而一个独立的BI系统,能够从传统业务系统中获取各类业务数据,通过数学模型建立多层次的分析体系,并将其转化成有商业意义的信息。BI的应用需求往往复杂多变。BI的实施复杂性远远超过传统的报表系统。不能带着传统事务处理系统的思维模式进行BI系统实施。

    另外,报表系统和BI的使用对象和目的也不尽相同。报表系统更着重于短期的运作支持,而BI则关注长期的战略决策,甚至更着重于商业趋势和业务单元的联系而非具体的数据和精确度本身。BI并不是用来代替着眼于日常运做的报表系统的!这种理解的含糊也非常容易导致对BI项目复杂度和资源的投入要求估计不足。这是笔者所犯的第一大问题。

    BI的组织和技能要素
    建立BI体系需要许多技能,包括商务技能、信息技术技能和分析技能。然而要建立同时具备以上三种能力的数据分析部门谈何容易。善于联系看似不相关的事物并能有效地呈现它们之间的关系是一种非常难得的能力,通常企业里面具备这种能力的人才很少,即使有也没有被充分重视。国际国内的BI人才奇缺。如果企业不能有效地组织BI活动(如着手建立集中化的BI能力中心和投资BI技能建设)将无法在战略层面展示BI的作用,且将面对至少50%的额外实施费用。而没有集中的,专门的BI功能部门,BI系统无法被深入和有效的支持。

    由于人才的稀少,建立一个集中的,汇集各种人才的BI能力中心是非常必要的。来自不同部门的人以建立一种互相协作的BI队伍远比寻找同时具备三种能力的人才更现实可行。一个有效的BI能力中心有三个重要的任务:指导用户能够实现重复的BI任务(如管理报表和简单的重复分析)的自我服务;承担复杂的,额外的分析工作知道这些分析能够成为可重复使用的简单工作;确保BI系统的功能和潜力不被高估,实实在在地解决现实的问题。

    企业建设BI系统的目的,是要从大量的数据中找出可以给企业带来增值效益的数据分析,但是这些数据必须有相应的人对其进行跟踪处理,否则BI的价值也就只停留在迅速做出报表的层面,BI的核心价值也被大打折扣。而所有的任务,都需要精心的策划和长期的努力。笔者所在的公司只有一个高负荷的规模很小的IT队伍,显然在BI能力方面并不具备组织上的条件。这点并没有被充分认识到,所以困难是显而易见的。


    数据基础先行
    “BI是数据驱动的应用”。BI系统建设的核心是坚固、高质量的数据基础。建立这样一个数据资料库的任务是极其艰巨的,要消耗大量的时间和资源。而企业数据的积累是伴随着各种基础信息系统的建设而进行的,这是一个长期的过程。

    在基础系统尚未建立和完善阶段,切忌同时发动不同的系统建设,如笔者所在的公司在实施BI系统的同时就在建设分销供应链系统。不仅资源捉襟见肘,数据的质量和完备问题也是不可预料的因素。本意是整合公司所有的数据资源,但是数据资源仍在不断地变化,如何整合这些尚未确定的资源是一个巨大的挑战。

    我们的BI项目仍在艰难地进行,有了这些经验和教训,我们坚信通过我们的努力,商业智能工具最终一定能够给企业带来巨大的应用价值,也许有可能超越我们的想象。