20120711DB2数据库逻辑设计(一)

鉴于CSDN无故删除博文,本博客不再更新,暂时迁至http://www.db365.net


商业智能群199567325,2012年7月11号《db2数据库逻辑设计(一)》,讲解者:赵坚密Jimmy。

讲课方式,YY频道号:85536471


YY频道每周三讲解,具体请加QQ群199567325下载讲课录音。


DB2逻辑设计

赵坚密[email protected]

1表

1.1规范化和反规范化

a不能拆分1NF

  表1 不符合1NF

员工

部门

部门经理

 

人力资源

张三

 

财务

李四

 

财务

李四

 

 

 

 

 

 

  表2 符合1NF

员工

部门

部门经理

 

张三

人力资源

张三

 

张三

财务

李四

 

李四

财务

李四

 

 

 

 

 

b不能重复2NF(1—>2:消除非主属性对码的部分依赖)

  表3 符合2NF

员工编号

员工姓名

部门

部门经理

 

1

张三

人力资源

张三

 

2

张三

财务

李四

 

3

李四

财务

李四

 

 

 

 

 

 

c不能冗余3NF(2—>3:消除非主属性对码的传递依赖)

  表4 符合3NF

员工编号

员工姓名

部门

 

 

1

张三

人力资源

 

 

2

张三

财务

 

 

3

李四

财务

 

 

 

 

 

 

 

  表5

部门编号

部门

部门经理

 

 

1

人力资源

张三

 

 

2

财务

李四

 

 

 

 

 

 

 

 

 

 

 

 

 

d通俗的介绍:

第一范式:属性不可再分

就是字段A,不能再分成A.filed1,A.filed2

第二范式实在第一范式得基础上

第二范式其实就是要求有主键

通过主键可以唯一确定一行记录

也就是员工表,必须有个员工ID

部门表必须有部门ID

第三范式实在第二范式得基础上

消除了字段对非主属性得传递依赖

员工表

员工ID,员工姓名,部门ID,部门名称

这个是不允许得

不能有部门名称

部门会有另一张表

e反规范化

反规范化,即数据冗余。首先需要付出空间代价,其次是管理代价,维护数据的完整性。它的好处是:减少查询所要连接表的个数,减少了I/O和CPU时间,加速了查询。。因此做反规范化时,一定要权衡利弊,仔细分析数据的存取需求和实际的性能特点。

1.2创建表时的可选参数

a COMPRESSION 压缩70%

b APPEND ON 直接插入表尾

c PCTFREE 表中空闲百分比

d PARTITION BY RANGE 快速加载和分离数据

e VOLATILE 访问时使用索引

2索引

2.1执行计划

DB2基于成本的优化,优化器计算SQL语句的多种访问路径下的执行成本(CPU内存硬盘等),最终选择最优路径作为SQL语句的执行计划。

动态SQL每执行一次都需要重新编译和优化,静态SQL不需要。所以静态SQL免去了编译和优化得过程,节约了时间,但是随着时间的改变,数据库的数据以及服务器的资源负载改变之后原先的执行计划可能不是最优。

2.2访问数据的方法

a表扫描

按顺序扫描整个表。

b索引扫描

通过首先访问表上的索引来定位到某一行,然后再访问该行。

c完全索引访问

所有需要的数据都在索引中,那么就没必要访问索引所在的基表

2.3影响索引作用的因素

a区分度(检索比例)

优化器根据统计信息来生成执行计划,如果数据库没有收集索引的统计信息,优化器就无从下手,只能按部就班,通过全表扫描来执行查询。所以,新创建的索引需要重新运行统计,否则索引无效。

举一个例子,有个表TABLE1,其中有一个字段COL1取值是“1”、“2”、“3”三种,运行统计的结果是告诉数据库TABLE1中的数据其中字段COL1的各种取值所占的比重。示意如下:

“1”- 12%;

“2”- 66%;

“3”- 22%。

假设还有个字段COL2取值和数据所占的百分比如下:

“A”- 50%;

“B”- 50%。

则查询语句1:

select * from TABLE1 where COL1 = “1” and COL2 = “A”,

数据库优化器会优先选择字段COL1上的索引来定位表中的数据,因为通过COL1上的索引就可以将结果集迅速定位在一个小范围内12%。而相反的,对于查询语句2:

select * from TABLE1 where COL1 = “2” and COL2 = “A”,

数据库会优先选择COL2上的索引,因为对于语句2的查询条件COL2上的索引具有更好的区分度。

从上面可以看出,数据库的优化器通常会优先选择区分度较高的索引(针对于查询条件,条件不同选择的索引可能不同)。

数据库里的数据是变化的,所以某个时候采集的统计信息,过一段时间后可能会过时,甚至误导数据库优化器,这样同样会造成运行性能的低下。所以除了,最初建立索引时需要运行统计,在表中的数据发生变化时也需要运行统计。经验:当表中数据量变化达到10%时,需要重新运行统计。

b聚集度

补充知识:按块访问表数据。

c函数与索引

函数,like语句。。。

Substring(col_name,1, 3) vs. Substring(col_name, 3, 3)

like ‘QQQ% vs.like ‘%QQQ’

 

2.4谓词

a范围定界

 

b索引控制

 

c数据控制

 

d保留谓词

 

2.5索引与操作

 

 

2.6索引或操作

 

 

2.7索引参数

索引或者表空间的CREATE/ALTER语句可以指定FREEPAGE和PCTFREE参数。可通过ALTER语句修改参数。

例子,FREEPAGE为5:5页之后空1页;

PCTFREE取值0~99,如为40:某一页有超过40%的可用空间,则利用。

2.8索引优化向导

db2advis

2.9索引开销

性能利器

双刃剑

索引对插入操作的影响(Oracle)

索引对插入操作的影响(MySQL)

比较索引与促发器对性能的影响

 

2.10索引总结

使用索引实现关键数据的高效访问。但是需要知道每个索引都会给数据库更新带来额外的开销。这就意味着,低效的索引会给数据库带来灾难。

对于数据库,我们必须关注关键数据的读取,为他们提供最高效的访问路径。对此,基本策略就是建立索引。在索引提供高效访问的同时,也带来了额外的系统开销。开销分为磁盘空间的开销和处理器开销。下面我们讨论一下处理器开销。每当在表中插入或删除记录时,该表的所有索引必须进行相应调整。每当对已建立索引的字段进行更新时,这种调整也会发生。举例子说,如果在未建立索引的表中插入数据需要100个单位时间,那么每增加一个索引就会增加100到250个单位时间。有趣的是,维护索引的开销与简单触发器带来的开销大致相当。

在建立索引前线介绍一些最通俗的信息,这些信息来自developWorks,列出这些信息是因为我觉得这些信息通常情况下是值得参考的:

1.         当要在一个合理的时间内结束查询时,应避免添加索引,因为索引会降慢更新操作的速度并消耗额外的空间。有时候还可能存在覆盖好几个查询的大型索引。

2.         基数较大的列很适合用来做索引。

3.         考虑到管理上的开销,应避免在索引中使用多于5个的列。

4.         对于多列索引,将查询中引用最多的列放在定义的前面。

5.         避免添加与已有的索引相似的索引。因为这样会给优化器带来更多的工作,并且会降慢更新操作的速度。相反,我们应该修改已有的索引,使其包含附加的列。例如,假设在一个表的 (c1,c2)上有一个索引i1。您注意到查询中使用了"wherec2=?",于是又创建一个(c2)上的索引i2。但是这个相似的索引没有添加任何东西,它只是i1的冗余,而现在反而成了额外的开销。

6.         如果表是只读的,并且包含很多的行,那么可以尝试定义一个索引,通过CREATE INDEX中的INCLUDE子句使该索引包含查询中引用的所有列(被INCLUDE子句包含的列并不是索引的一部分,而只是作为索引页的一部分来存储,以避免附加的数据FETCHES)。

对于数据仓库(查询系统数据库)可以建立较多的索引(索引和数据的比例可以是1:1)。

决定是否使用索引,可以重点考虑检索比率。即,判断索引有效性的依据,就使用键值作唯一性条件检索出的数据的百分比。百分比越低,索引越有效。做出这个论断的前提是一些假设,如磁盘访问的相关性能。

索引键值相关记录的物理位置是否相邻也很重要,因为是通过块来操作数据的。建立了索引之后,如果索引键所指向的记录散布于整个表中,即使这些记录在表中占的比率很小,但因为它们分散在整个磁盘上,所以索引的性能就会大打折扣。

另外值得注意的是,函数和类型转换可能导致索引失效。

3表分区

2.1分区表的优势

当单表数据量达到一定级别,随着数据量的增长,响应时间高于线性增长,呈现指数级增长趋势。

P570,16C,32G的机器,测试,当数据量达到千万及以上,即使对索引列进行聚集操作也是呈现非线性增长。

分区表根据表分区键将表数据分布到多个表分区中。比起普通表,分区表凭借其先天优势,在表功能、SQL处理性能等多方面遥遥领先。它允许一个逻辑表被分成多个分散的逻辑存储对象,每个村处对象对应表的一部分,用值的范围来指定每个分区。

总结:首先,增加了表的功能。数据可以分区、分表空间存放,这也可以方便的进行数据的转入转出。其次,这样做提高了SQL处理的性能,由于各个月的数据分区存放,如果用户需要访问某一特定月的数据,可以直接对相应的分区访问即可,这样避免了对其他数据的访问。同时,数据存放在不同表空间,在进行数据访问时,可以并行I/O,以提高访问效率。同时,使用分区表还有一个很大的好处,就是锁方面的好处。当应用程序访问某一月数据时,只需对相应的分区加锁,从而避免了像普通表一样对整个表加锁,这就大大提高了数据库并发性。

转入转出功能对大数据量的表非常有用,数据可以灵活插拔,不用时转出,用时转入。如果把不用的数据转出,可以减少数据量,显著提高性能。并且用转入转出删除和插入数据非常快。

2.2分区表设计

可以根据转入转出的特点来设计分区,根据月份分区。控制每个分区的数据量在合理的范围,让数据尽可能平均分布到各个分区。表分区的范围跟转出数据范围一致,可以使转入转出操作简化。

尽量避免全局索引。

可以使用db2advisor来生创建成分区表语句。

2.3分区表索引

a全局索引(9)

b分区索引(9.7之后)

2.4分区是把双刃剑

数据驱动分区能将一个表中的数据分散到多个独立的分区中,但这并不意味着并发问题就完全解决了。例如,一个表按日期进行分区,每星期的数据一个分区。若把一年的数据写入五十二个逻辑上不同的分区,这种分区方式的确很有效。但问题是,每个星期所有人都会拥入同一个分区插入新数据——更糟的是,如果分区键是当前系统日期,所有这些并发操作,都会针对同一个数据块(除非利用一些结构上得实现技巧,例如维持几个可供插入的页或数据块列表),结果将导致非常棘手得内存争用。这个大型表中的大部分都无人访问,但存储最新数据分区的访问却过于集中,当许多进程同时插入数据时,这样的分区方式显然不够理想。

注意:如果所有数据都通过单一进程进行插入(数据仓库环境中会出现这种情况),“访问过于集中”问题就不存在了,而五十二个星期的分区方案也不会导致并发性问题。

另一方面,假设根据订单的地理位置进行分区(如果产品在某地热销而在另一些地方销路不畅,则应谨慎采用此分区方式)。指定某个时间,由于销售不太可能全部来自同一区域,所以插入的数据大体会随机分不到各分区。但要基于时间生成报表时,这种分区对性能影响较为明显,因为分区是按地理位置划分的,效率肯定比按时间划分的分区要低。然而,基于地理位置的分区也有可能对基于时间的查询有利,因为在多处理器的机器上,对各分区的搜寻可以并行执行,随后将结果合并。

因此,分区是把双刃剑。一方面,它通过分区键将数据聚集在一起,利于高速检索。另一方面,对并发执行的插入操作,分散数据可避免出现“访问过于集中”的问题。但在实践中,这两个目标可能彼此矛盾,所以首要问题是搞清楚要解决的主要问题是什么,并针对主要问题设计分区。而且,两方面的得失都要检查,看结果能否接受。理想的情况是为select而设计的数据聚集方式,与为insert而设计的散步方式是一致的,只可惜这并不常见。

2.5分区与数据分布

或许你认为,只要表非常大,且希望避免数据的并发写入操作发生资源争用,就一定要采用某种方法对数据进行分区。但时事并非如此。

假设有个很大的客户订单表,如果该表中大部分数据都来自于同一个客户(该情况时有发生),那么按客户ID对数据进行分区,就不会有太大帮助。我们可以非常粗略的把查询分为两大类:与大客户相关的查询及与较小客户相关的查询。当查询小客户的数据时,在客户ID上的索引选择性(区分度)会很高,因而查询效率也很高,这时完全不需要分区。聪明的优化器在获得关于键值分布的适当统计数据后,即可侦测到分不得不均匀并转而使用索引。这种把小客户存储在较小的分区,紧靠在含有主要客户的大分区旁的做法,好处并不大。

相反,当查询大客户的相关数据时,优化器也知道扫描表时效率最高的处理方式。在此情况下,由于该大客户的数据占全表很大比例——假设为80%,仅扫描该客户数据所在分区并不比全表扫描快很多,所以性能提升不大,但购买DBMS的分区功能(该功能单独定价)却需要额外开销。

总结:对分区表进行查询,当数据按分区键分布均匀时,收益最大。

2.6数据分区的最佳方法

绝对不要忘记,整体改善业务处理的操作,才是选择非标准的存储选项(例如分区)的目标。这意味着,改善不合理的业务流程是重中之重。例如,牺牲晚上的时间进行批处理工作,优化白天的事物型处理,是合理的;也可以优化批处理工作,如果将关键的上载时间减至最短(期间数据对用户仍不可用),我们可以接受交易处理速度稍慢一些。这是平衡问题。

一般而言,当有多个处理在类似条件下执行时,不应过度偏袒其中一个。就这点上,只要是根据数据值决定物理位置的存储方式(例如聚集型索引和分区),更新数据时代价都非常高。对普通表的更新,几乎是在物理地址不变的情况下做更改,最多只修改和移动表中的一些字节而已;但如果采用了上述那些存储方式,更新必将导致一系列删除、插入操作和相关索引维护工作。

更新分区键会引起移动数据,似乎应避免这么做,但奇怪的是,更具可更新的键值进行分区,有时效果更好。例如,有个表,用作服务队列,某进程会在该表中插入不同类型(例如T1到Tn)的服务请求。新出现的服务请求,初始化状态被设为W——表示“等待处理”。服务器进场S1到Sp会定期检查表中是否有W状态得请求,若有则将其状态更改为P——表示“处理中”,接着,在完成每个请求后其状态被置为D——表示“已完成”。

。。。。。。

总结:对表进行分区的方法有多种,显而易见的分区方法未必是最有效的,一定要从整体考虑。

 

4 MDC

5 MQT

6 DPF

 


你可能感兴趣的:(sql,数据库,优化,db2,存储,compression)