本文共 3998 字,大约阅读时间需要 13 分钟。
对于我们这个项目来说,数据库的存取的性能决定了数据提供的性能。优化的大致的原理只有两个:一是数据分块存放,便于数据的转储和管理;二是中间处理,提高数据提供的速度。
基于上面两个根本的原理,借助于数据仓库的概念,列举数据库的优化方式:1. 分区在数据仓库中,事实表,索引表,维度表分处于三个不同的表空间当中(在部署的时候,最好是部署到不同的磁盘上)。这样子做的原因就是便于并发操作,其实数据仓库和普通的数据库之间没有严格的界限,主要还是部署上,当然oracle本身会为数据仓库中的“事实表”生成“知识库”等操作,保证更快的数据提供效率,其实可以借助于job和外部程序来调度存储过程实现。基于这个思路,本项目数据库中的索引将和事实表分开维护,当然这称不上分区()。真正的分区是指下面的内容。分区就是partition/subpartition,对于事实表本身来说,以月为单位作partition挂载到不同表空间上。具体的示例如下:create table T_LOGNODE_RECORD(…… CALLIN_HH NUMBER(2) not null, CALLIN_DD NUMBER(2) not null, CALLIN_MONTH NUMBER(2) not null, CALLIN_YEAR NUMBER(4) not null, MONTH_MOD NUMBER(1) not null)PARTITION BY LIST (MONTH_MOD) (PARTITION P0 VALUES (0) TABLESPACE TS0, PARTITION P1 VALUES (1) TABLESPACE TS1, PARTITION P2 VALUES (DEFAULT) TABLESPACE TS2);上述的代码中以MONTH_MOD字段作为分区标准,将T_LOGNODE_RECORD分到三个不同的表空间(TS0,TS1,TS2)中,这里有一个技巧,MONTH_MOD = 月份mod3,这样子可以不需要人工的维护哪个月分入哪个分区。当然简单的以月作为分区之后,对于我们当前的数据库来说还是远远不够的,因为即使是一个月的数据依然是很巨大的,那么需要我们做SUBPARTITION,做法的示例为:create table T_LOGNODE_RECORD(…… CALLIN_DD NUMBER(2) not null, MONTH_MOD NUMBER(1) not null)PARTITION BY RANGE(MONTH_MOD)SUBPARTITION BY LIST(CALLIN_DD)SUBPARTITION TEMPLATE(SUBPARTITION SUBP1 values (1),SUBPARTITION SUBP2 values (2),SUBPARTITION SUBP3 values (3))(PARTITION P0 VALUES less than (1),PARTITION P1 VALUES less than (2),PARTITION P2 VALUES less than (3));分区方式有三种:RANGE(范围),LIST(列表分区),HASH(哈希分区),需要解释的HASH分区,是oracle调用内置的hash函数来完成对数据的平均分布,保证分区内部的数据量相同,所以只需要制定分区的数量即可。对于复合分区来说。不是所有分区格式都可以嵌套的,oracle只支持范围列表分区,范围哈希分区,特别的范围分区可以支持多个字段range by(field1,field2)。对于本项目中用到的分区方式,只有示例中给出的两种,至于分区的好处,请查看google,^_^。给出操作的sql示例如下:select * from T_LOGNODE_RECORD partition(P0)update T_LOGNODE_RECORD partition(P0) t set……insert语句没有影响。当然上述的操作可以像普通的Sql语句一样,不指定分区也可以进行,但在查询的时候请尽量能确定分区和子分区subpartition,这样子会让查询的速度提高百倍。可以删除指定的分区drop或者truncate, EXPORT和IMPORT分区中数据,但是当进行分区的删除操作的时候,会使全局的索引(index)实效,需要重新建立。2. 维度Dimension这个算是oracle的进阶功能了,在PLSQL Developer没有办法找到这个对象(但是可以执行语句来生成该对象,但是无法进行后期的维护),只能在Toad中有它的身影。它是表明数据维度字段之间的大小关系。典型的自然是下面的年月日了。create table DIM_TIME ( D_YEAR VARCHAR2(4) not null, D_QUATER VARCHAR2(2) not null, D_MONTH VARCHAR2(2) not null, D_DAY DATE not null)CREATE DIMENSION DIM_TIME LEVEL YEAR IS (DIM_TIME.D_YEAR) LEVEL QUATER IS (DIM_TIME.D_QUATER) LEVEL MONTH IS (DIM_TIME.D_MONTH) LEVEL DAY IS (DIM_TIME.D_DAY) HIERARCHY Y_Q_M_D ( DAY CHILD OF MONTH CHILD OF QUATER CHILD OF YEAR ) HIERARCHY Y_M_D ( DAY CHILD OF MONTH CHILD OF YEAR ) 建立了两条继承关系Y_Q_M_D和Y_M_D。当DIM_TIME本身的统计,以及与其他表作联合查询然后汇总时,月的汇总数据自动以日汇总的数据为基础,这样子大大提高数据汇总的速度。可以为一张表建立多个维度表,一个维度中可以有多个继承关系。维度极大程度上提高了数据汇总的速度,使我们这个项目的数据统计分析的利器。3. 物化视图(快照)物化视图MATERIALIZED VIEW。值得高兴的是PLSQL Developer和Toad上同时拥有了这个对象的存在(Toad上可能将这个称为快照snapshots),但是令人郁闷的事情产生了,在PLSQL Developer上写成的MATERIALIZED VIEW在Toad中无法识别,看来还要两个都用才可以。物化视图,顾名思义拥有视图的属性,它是建立在实际表的基础上,将实际表中的数据抽象展示,甚至创建的方式都几乎一样。但是它成为物化,就意味着它是实体对象,从某种意义上将,它更像一个中间表,可以像表格一样直接查询其中的数据(甚至就在table列表中可以看到它),但是它不仅仅是中间表,因为它可以影响原始表的数据,并且oracle可以自动将针对原始表的查询汇总语句直接重定向到物化视图上,来提升查询的速度。CREATE MATERIALIZED VIEW MV_LOG_RECORDREFRESH FORCE ON DEMANDENABLE QUERY REWRITEASSELECT t. NODE_ID, Count(*) as Call_Times from T_LOGNODE_RECORD tGROUP BY t. T_LOGNODE_RECORD上面的SQL语句就已经在T_LOGNODE_RECORD表上建立一个物化视图。REFRESH的参数 FORCE表示强制刷新,还可以选择的参数有fast和complete两种,fast是最快的刷新方式,表示增量刷新(要做到增量刷新,必须在物化视图中包含唯一性的标示的字符,如主键和rowid等,当然即使包含了也不一定可以做到快速刷新,因为我们项目中没有涉及到要刷新的物化视图,在此就不多言了);complete表示完整的数据刷新,重新生成物化视图;force是选择性的刷新,根据实际的情况来选择是force还是complete。ON DEMAND表示刷新触发的条件。上面的物化视图只有在用户发起查询请求时,才会去刷新数据,即将原始表中的数据取到物化视图的表中。还有一种方式就是 ON COMMIT,当用户操作原始数据时,就刷新对应的物化视图,这种方式适合对于即时性要求高的项目。如果需要做定时的刷新,就要用到下面的方式: REFRESH FAST START WITH SYSDATE NEXT SYSDATE + 1/48。物化视图是可以跨越多个表的,也可以直接的查询物化试图,例如你可以:Select * from MV_LOG_RECORD.总结
在上述的三种方法中,属于数据库性能优化的主要手段,当然还有很多可以做的细节的优化,例如尽量不要在你要查询的字段上面允许为空,尽量将联合查询的关系控制为number型等等。对了,如果做了维度表,做了物化试图,你去查询原始表的时候速度一定会增加么?答案是“不”,你要做的一个重要的事情,就是告诉oracle,它可以主动的优化查询,语句如下:ALTER SESSION SET QUERY_REWRITE_ENABLED=TRUE;ALTER SESSION SET QUERY_REWRITE_INTEGRITY=TRUSTED;要把这三个优化的手段写得很清楚,这么简单的几句话是不可以的。只是让大家了解一个项目的数据库的部署和稍微高阶一点的优化方式。转载地址:http://japgj.baihongyu.com/