- 让DB2跑得更快:DB2内部解析与性能优化
- 洪烨
- 13321字
- 2020-08-28 03:08:56
1.3 影响性能的因素
在已经有明确的目标时,就需要着手了解系统的整体结构(见图1-4)及应用程序运行的过程。在应用程序的执行过程中,任何一个环节都可能是引起性能问题的根本原因。
图1-4 系统整体结构
从图1-4中可以看到,系统就像建筑一样,其健康程度是由多种因素造成的。而这些因素是怎么发展为性能问题的呢?如果大家有在北京地铁4号线和2号线的换乘站宣武门换乘的经历就更简单了。接下来我就给大家详细讲讲早上坐地铁的经历。
人在北京,日常出行就离不开地铁。笔者住得离4号线地铁较近,所以经常搭乘4号线地铁进行换乘。在非早晚高峰的情况下,如图1-5所示,笔者可以按照箭头所指示的路线从地铁4号线换乘2号线。
图1-5 非高峰期地铁站内换乘路线
但是,如果在早晚高峰时段乘坐地铁4号线在宣武门站换乘2号线。就会发现和平时的情况完全不一样,工作人员会在换乘的必经之路用栅栏堵住,我们只能这样换乘地铁2号线了,如图1-6所示。
图1-6 高峰期地铁站内换乘路线
从图1-6中可以看到,每天早上笔者需要从4号线地铁到达2号线地铁,图中黑色箭头代表笔者每天早高峰时需要走的路线,灰色实体部分代表墙,黑色实线代表地铁工作人员用栅栏围成的区域。而前方就是最恐怖的密集的人流。而每次半分钟的路都要耗费十五分钟左右才能从4号线出口到达2号线入口。
接下来我们就探讨一下地铁宣武门站换乘性能问题的成因及地铁工作人员的措施。
首先,为什么会每天发生拥堵事件?大家可以看到,2号线地铁有两个较宽的入口,但只有一个较窄的出口,这种设计在高峰时期必定会出现排队堵塞。而地铁工作人员为什么用栅栏围出那么远一段路呢?这是因为工作人员将队列深度加大,缓解了大家在地铁2号线入口的堵塞。同时,在严重堵塞期间还会每隔一段时间限制人员流通,相当于设置了一段缓冲区,以避免更严重的性能问题。
上面这个案例中的性能问题是由于当初的设计原因导致的。早晚高峰期间,不管工作人员付出多少努力,也无法对地铁站进行重新设计及修改,也就无法从根本上解决这个性能问题。只能通过增加缓冲区、增加队列深度(软件编码,参数调整方法)等方法减少性能带来的影响。
同理,在IT系统中软硬件设计对性能的影响也是十分巨大的。如果最初的设计有诸多因素没有考虑周全,就会对以后的使用及运维带来很多问题,甚至造成不可挽回的损失。
在整体系统设计中,又分为应用设计、数据库设计及系统设计。其中的每个部分都包罗万象。稍有不慎就很有可能给以后的生产运维带来很多困扰。在这里我们简单谈下在设计过程中,对性能会产生影响的一些方面。
1.3.1 软件代码编写对性能的影响
由于各个系统开发周期较短,留给开发人员的时间越来越少,所以一般开发过程中只满足了业务需求,而不会过多考虑性能问题。并且SQL语言也不同于大家认知中的其他编程语言(C\C++\Java)等,SQL语言是直接面向结果集的,并非传统的按照代码流程执行的语言,这就给开发人员带来一定的难度。由于SQL语言的特殊性,结果集相同但写法不同的SQL语句在性能上可能会有上千倍的差别。比如下面这条语句:
select * from PIXPatient where PIXPatientTIDin ( select distinct PIXPatientTID from DomainPatient where DomainPatientTID in ( selectDomainPatientTID from DomainPatient where PatientBirthday='1994-01-09' or PatientBirthday='1994-01-01' union select DomainPatientTID from PersonName where FamilyName='倪' or GivenName ='界'));
通过分析不难得出,在这条SQL语句中引用了大量的子查询。为了对其进行优化,需要继续深入分析以便得出其中引用到的各表之间的逻辑关系。首先从中摘选出子查询进行详细分析,能够发现这条语句的最终目的是在DomainPatient表中找到符合下面语句的行,但是由于查询条件中又再次包含DomainPatient表,按照原来的写法会产生两次连接。
DomainPatientTID in ( SelectDomainPatientTID from DomainPatient where PatientBirthday='1994-01-09' or PatientBirthday='1994-01-01'union select DomainPatientTID from PersonName where FamilyName='倪' or GivenName ='界' )
根据上述分析,我们将原语句改写为以下形式:
select c.* from DomainPatienta,PersonNameb,PIXPatient c where a.DomainPatientTID=b.DomainPatientTID and (a.PatientBirthday='1994-01-09' or a.PatientBirthday='1994-01-01') and (b.FamilyName='倪' or b.GivenName='界') andc.PIXPatientTID=a.PIXPatientTID
这种做法会带来以下几方面好处:
● 减少连接次数;
● 方便创建合适的索引以保证扫描行数的缩减;
● 方便更改过滤条件的顺序以便进一步优化;
● 方便阅读和理解代码意图。
1.3.2 应用程序架构设计对性能的影响
应用软件作为整个系统中最接近用户的一环,设计的好坏会最直接地影响整个系统的性能。例如,应用程序每执行一条操作就要重新连接数据库,如果业务量较大,就会不断对数据库发起连接,从而占用了大量的CPU资源,导致整个系统的性能急剧下降。
在应用程序的设计中,一定要考虑数据量及事务的增长,以及各个模块之间并发性的影响,还有未来的用户个数及故障的判断处理等诸多因素。一个小小的疏忽都可能在未来的系统运行中产生重大影响。对于OLTP系统,一般会在数据库和应用之间架设应用服务器,避免应用程序直连数据库。比如前面提到的铁道部的订票系统,平时的并发量一定能够满足需求,但是每到“春节”、“五一”等业务高峰期,并发量由平时的几千、几万一下上涨到几亿,导致响应时间过长,这时就体现了当初设计时的考虑不周。
对于批量执行的语句,会占用大量的编译时间,在设计时直接使用静态语句或绑定变量的方式就可以完全避免此类问题的发生。或者在DB2 V9.7版本以后,语句集中器的使用也可以在一定程度上简化这类问题。
1.3.3 数据库设计对性能的影响
数据库作为整个系统中提供数据的部分,通常是对整体性能影响较大的一个环节。由于数据库对应用程序比较透明,所以大多数开发人员并不了解数据底层的存取模式,也导致了在设计过程中,往往会忽略关于数据库性能方面的设计。
1.代码页和整理顺序
代码页及整理顺序选项通常在数据库设计中是最容易被忽略的一个环节,它们除了能对数据库的行为产生影响外,还能对性能产生重大影响。Unicode代码集的使用非常广泛,这是因为与传统的单字节代码页相比,Unicode能够在数据库中表示更多的字符串,因此对于DB2 V9.5之后的版本而言,Unicode是缺省代码集。但是,由于Unicode代码集使用多个字节来表示某些单个的字符,因此会增加磁盘和内存需求。例如,UTF-8代码集(这是其中一种最常用的Unicode代码集)使用1~4个字节来表示每个字符。从单字节代码集迁移到UTF-8所引起的平均字符串扩展系数很难估算,这是因为此系数取决于多字节字符的使用频率。
除此之外,相对于单字节代码页而言,使用Unicode会导致耗用额外的CPU时间。首先,如果发生扩展,那么较长的字符串将要求执行更多的工作。其次,与单字节代码页所使用的典型SYSTEM整理顺序相比,更为复杂的Unicode整理顺序所使用的算法(例如UCA500R1_NO)的成本更高。成本提高的原因是对Unicode字符串进行的排序比较复杂。受影响的操作包括排序、字符串比较、LIKE处理和索引创建。
如果需要使用Unicode才能正确表示数据,那么请谨慎地选择整理顺序。(1)如果数据库将包含多种语言的数据,并且该数据的正确排序顺序极为重要,那么需选择其中一种基于字符集的整理顺序(例如UCA500R1_*)。根据数据和应用程序的不同,相对于IDENTITY顺序,这可能会导致性能开销提高1.5~3倍。(2)对于各个语言而言,整理顺序分为规范化版本及非规范化版本。规范化整理顺序(例如UCA500R1_NO)将执行附加的检查以处理格式不正确的字符,而非规范化整理顺序(例如UCA500r1_NX)不执行这些检查。除非处理格式不正确的字符将引起问题,否则请使用非规范化版本,这是因为避免执行规范化代码有助于提高性能。也就是说非规范化整理顺序的成本也非常高。
(3)如果正在将数据库从单字节环境移至Unicode环境,但对是否包含各种语言的内容没有严格要求(大多数部署都是这种情况),那么可感知语言的整理顺序可能比较适合。可感知语言的整理顺序(例如SYSTEM_819_BE)利用了许多Unicode数据库只包含一种语言的数据这一事实。它们与单字节整理顺序(例如SYSTEM_819)使用同一种基于查找表的整理算法,因此非常高效。通常,如果原始单字节数据库中的整理行为可接受,那么只要语言内容在移至Unicode后未显著更改,就应该考虑使用在文化方面有感知能力的整理顺序。相对于正确的整理顺序,这将产生非常大的性能增益。
2.表空间设计
磁盘I/O通常是影响响应时间的最大因素,良好的表空间设计会在一定程度上减少磁盘I/O操作的次数,以避免磁盘I/O产生的瓶颈。表空间的类型选择和参数设定可以在很大程度上决定表空间上I/O操作的执行效率。
1)表空间用途
表空间在日常工作中按照用途来分类,可以分为以下3种不同用途的表空间,不同的表空间装载着不同类型的数据,这样可以方便数据库及DBA对其进行管理。
(1)编目表空间
编目表空间包含数据库的所有系统编目表,其中存储着数据库的元数据信息。该表空间也被称为SYSCATSPACE,且不能被删除。
(2)用户表空间
用户表空间包含用户定义的表、索引和大对象。默认情况下,创建数据库后会创建用户表空间USERSPACE1。
(3)临时表空间
临时表空间存放数据库管理器在执行排序或连接之类的操作时所产生的临时数据,这是因为这些操作需要额外的空间来处理结果集。
临时表空间分为系统临时表空间及用户临时表空间。数据库必须至少有一个系统临时表空间,其页大小与编目表空间相同。在默认情况下,创建数据库时会创建一个名为TEMPSPACE1的系统临时表空间,TEMPSPACE1的页大小是在创建数据库时指定的。
默认情况下,创建数据库时不会创建用户临时表空间。如果需要存放一些表的临时数据或中间结果集,可以手动创建用户临时表空间。创建用户临时表空间之后可以使用DECLARE GLOBAL TEMPORARY TABLE或CREATE GLOBAL TEMPORARY TABLE语句创建临时表,定义的临时表会存放在用户临时表空间中。
一般情况下,不建议定义多个具有相同页大小的临时表空间,临时表空间的页大小也应该等于大多数用户表空间所使用的页大小。为了获得最佳性能,在创建临时表空间时应该考虑下列几点建议。
● 在大多数情况下,临时表空间是按顺序插入或读取的。因此较大的数据页尺寸通常会获得更好的性能,这是因为读取固定的数据量时需要发出的读取请求更少。
● 如果使用临时表空间对表进行重组,则临时表空间的页大小必须与该表的页大小匹配。
● 默认情况下,临时表空间的数据被删除时,系统临时表创建的文件将被截断。可以使用注册表变量DB2_SMS_TRUNC_TMPTABLE_THRESH来避免数据库访问文件系统,从而潜在地避免文件截断,这样可以防止反复扩展和截断文件对整体性能造成的影响。
● 当存在使用不同页大小的临时表空间时,优化器将自动选择最大的缓冲池的临时表空间。在这种情况下,比较聪明的做法是给一个临时表空间分配一个足够大的缓冲池,而给其余的临时表空间分配较小的缓冲池。例如编目表空间使用4KB的页大小,而其余表空间使用8KB页,那么最佳临时表空间配置是创建一个拥有大缓冲池的8KB临时表空间和一个具有小一些的缓冲池的4KB表空间。
2)表空间参数考虑事项
创建表空间时,不同的参数会带来不同的性能影响。让我们通过一个例子来深入讲解如何选择合适的参数给表空间带来性能的提升。
(1)页尺寸(PageSize)
每页中记录的数量也是需要考虑的内容。DB2提供了一些有关页尺寸的选项,例如4KB、8KB、16KB和32KB。比较好的起点是选择默认的4KB,特别是当前的尺寸相对较小,或者是对数据的访问比较随机的情况下。然而在一些情况下,也需要考虑较大的页尺寸。如果表中单个行的长度超过4KB,就需要使用大一些的页尺寸,因为DB2不支持跨行的记录,所以就不存在Oracle中行链接的情况。
这里用个生活中的例子来对数据库涉及的基本概念进行讲解。图书馆相信大家都去过,一个数据库就可以想象成一个图书馆。里面按照书籍类型划分了不同的阅览室(表空间),而每个阅览室中有一排排的书架(表)来存放图书(数据)。为了方便管理,图书馆规定,相同区域(表空间)内,书架的宽度(页尺寸PageSize)必须一致。书架的宽度在制作好后就不可以更改了。同样,表空间的页尺寸在表空间创建后就不可以更改。让我们用一个图书馆书库分布的例子来说明这些概念。
如图1-7所示,这个图书馆中,总共包含3个表空间:古籍书库、名人研究室、历史文献研究室。这3个表空间分布在8个容器中,其中古籍书库占4个容器(A601-A604),名人研究室占4个容器(A606、A607、A609),而历史文献研究室只占用一个容器(A608)。
图1-7 图书馆书库分布
接下来,在每个房间里面肯定摆放了很多书架,这些书架在数据库里就是表(Table),图书馆的书架分布图如图1-8所示。
图1-8 书架分布图
来看如图1-8所示的书架图,我们可以把这个书架想象成一张表(Table),里面每个格子代表一个数据页(Page),里面每本书就是一条记录。为了方便管理及说明,我们把这个书架按格子及坐标进行编号(A1-E7)。
当图书馆新买了一批同类型的书,并且需要放到这个书架中时,图书管理员(DB2实例)会把书按照顺序放置到书架的每一格中。
由于一个书架代表一张表,而书架中的每本书代表了表中的行。所以,书架中格子的宽度(PageSize)限制了书的厚度(行宽)。而图书管理员(DB2实例)又规定,为了方便管理,一个格子里的书的数量是有限制的,每个格子里可以放置至少一本书,最多可以放255本书(不能把书撕开了放一半)。但是各个书的厚度各不相同,如果图书馆买了一大堆超级厚的词典(已经超过了格子的一半宽度),那每个格子里只能放一本,格子中剩下的空间就浪费了。
为了满足各种需求,在图书馆(数据库)中总共有4种不同规格的书架,这4种书架的格子大小都不一样,分别是4KB、8KB、16KB、32KB。所以我们在选择书架时如果设计不当(没选好合适的),不仅会浪费页空间,还会导致很多的DB2操作消耗更多的资源。因此,对于上面描述的记录(厚词典)而言,你需要考虑使用较大的页尺寸(大格子书架),这样就会相对地少浪费一些空间。
页的尺寸需要在创建表空间(CREATE TABLESPACE)的语句中直接写明。
(2)扩展数据块大小(Extentsize)
扩展数据块这个东西听上去很抽象,但其实很简单。在DB2中,读写的最小单位是页(Page),当对一个表进行批量插入操作时,如果这个表在表空间中发生空闲空间不足,需要表空间分配给它更多的空间,按页给表分配多余的空间会非常麻烦。对于大量插入操作来讲,会不停地为这个表分配空间。
为了避免上面提到的这种情况,DB2为表空间专门设计了一个属性,就是EXTENT,每次需要给表分配空间时,就会一次性分配一个EXTENT设置的空间。比如若Extentsize是32,那么当该表需要分配空间时,表空间中就会一次性分配32个页给这个表。
对于频繁插入的表所在的表空间,如果扩展页太小会导致频繁地分配空间,会对性能起到一定的负面影响(除非容器类型为裸设备或者在创建表空间提前指定参数DB2_USE_FAST_PREALLOCATION=ON)。
另外一点,扩展数据块是表空间容器中的存储器块。它表示写下一个容器之前写入上一个容器的数据页数。在创建表空间时,可以根据对性能及存储器管理的要求来选择扩展数据块的大小。目前大多数生产系统都对存储进行了条带化,如果单个容器使用了多块磁盘,而表空间又使用了多个容器,那么我们就需要将扩展页大小设置为满足一个RAID条带宽度的值。例如使用5块磁盘组成RAID 5,实际存储数据的为4块磁盘,条带宽度(Stripe Size)为64KB。如果我们需要创建一个页大小为16KB的表空间,推荐将Extentsize设置为4*64KB/16KB=16,如图1-9所示。
图1-9 磁盘设计图
当选择扩展数据块大小时,应考虑表空间中表的大小和类型,以及扩展数据块的最小数目两个要素。
● 表的大小和类型
在SMS表空间中一次分配给表一个扩展数据块或者一页。当填充该表而一个扩展数据块或页变满时,会分配新的扩展数据块或页,直到用完文件系统中的所有空间为止。当使用SMS表空间时,允许进行多页文件分配,多页文件分配允许分配扩展数据块而不是一次分配一页。默认情况下会启用了多页文件分配功能。multipage_alloc数据库配置参数值将指示是否已启用多页文件分配功能,但多页文件分配功能不适用于临时表空间。
在DMS表空间中每次分配给表一个扩展数据块。当该表中的扩展数据块填满时,就会分配新的扩展数据块,直到容器中没有空闲空间为止。DMS表空间中的每个对象都是单独存储的,并且每个对象都包含一个特殊的扩展数据块,其中存放的是该表空间中属于该对象的所有扩展数据块的存放位置,这个扩展数据块称之为EMP。因此,当我们创建一个表对象时,DMS表空间中为该对象分配的初始空间最小为两个扩展数据块。
如果所在DMS表空间中有多个较小的表,那么可能要分配相对大的空间来存储相对少量的数据。在这种情况下,应该指定小的扩展数据块大小。另一方面,如果有一个增长速率很高的非常大的表,并且使用具有较小扩展数据块大小的DMS表空间,那么可能会产生与其他扩展数据块的频繁分配相关的不必要的开销。
● 扩展数据块的最小数目
如果容器中没有足够的空间以供表空间的5个扩展数据块使用,那么将无法创建表空间。
(3)预取数据块大小(PrefetchSize)
谈论预取块大小之前,我们首先要了解预取的概念:在一个查询引用某数据页之前对该页进行的读取称之为预取,预取的目的是缩短响应时间。无论何时,如果数据库管理器认为预取可以带来性能上的提升,就会执行读取操作。当检索顺序排列或部分顺序排列的数据时,通常会发生这种情况。在一个读取操作中读取的数据量取决于扩展数据块大小,扩展数据块越大,一次可以读取的页就越多。
如果可以将磁盘上的数据页从磁盘读入缓冲池内的连续页中,那么可以进一步提高顺序预取的性能。因为缺省情况下缓冲池是基于页分配的,所以从磁盘的连续页中读取时,不能保证会找到一组连续页。基于块的缓冲池可以用于此目的,因为它们不仅包含页区域,还包含可用于几组连续页的块区域。每一组连续页都命名为一个块,并且每个块都包含称为块大小的若干页。页和块区域的大小及每个块中的页的数目都是可配置的。
扩展数据块存储在磁盘上的方式影响I/O效率。在使用设备容器的DMS表空间中,数据往往在磁盘上是连续的,且可以在最短的搜索时间和磁盘等待时间内进行读取。如果使用的是文件,那么为了供DMS表空间使用而预分配的大文件在磁盘上也往往是连续的,尤其当该文件分配在一个干净的文件空间中时更是这样。但是,数据可能被系统文件分散,并存储在磁盘上的多个位置中。当使用一次将文件扩展一页的SMS表空间时(这样会使产生碎片的概率更高),最有可能发生这种情况。
可以指定CREATETABLESPACE或ALTER TABLESPACE语句中的PREFETCHSIZE选项来控制预取的范围,或者可以将预取大小设置为AUTOMATIC以让数据库管理器自动选择最适合的大小来使用(该数据库中所有表空间的缺省值由dft_prefetch_sz数据库配置参数设置)。PREFETCHSIZE参数告诉数据库管理器在触发预取时要读取的页数。通过在CREATETABLESPACE语句上将PREFETCHSIZE设置为EXTENTSIZE参数的倍数,可以并行读取多个扩展数据块(该数据库中所有表空间的缺省值由dft_extent_sz数据库配置参数设置)。EXTENTSIZE参数指定在跳至下一个容器之前将写入一个容器的4KB大小的页数。
如图1-10所示,在这个例子中,表空间使用两个容器。如果将PREFETCHSIZE设置为EXTENTSIZE的两倍,那么数据库管理器可以用并行方式从每个设备中执行大块读取,从而显著增大I/O吞吐量。此情况假定每个设备是一个单独的物理设备,且控制器具有足够的带宽来处理来自每个设备的数据流。请注意,数据库管理器可能需要根据查询速度、缓冲池利用率和其他因素在运行时动态调整预取参数。
图1-10 磁盘设计与PREFETCHSIZE的关系
某些文件系统使用自己的预取方法,例如在AIX上的“日志文件系统”。在某些情况下,文件系统的预取设置得比数据库管理器的预取更主动。这可能导致使用文件容器的SMS和DMS表空间的预取似乎比使用设备的DMS表空间的预取执行效率更高。但这是误导,因为它可能是在文件系统中发生的其他级别的预取的结果。DMS表空间应能比任何等价配置的执行效率更高。
为提高预取效率(甚至读取效率),必须存在足够数量的干净缓冲池页。例如,可能有一个预取请求需要从表空间容器中读取64个数据页,DB2会首先保证缓冲池中有足够数量的干净页面。如果缓冲池中的干净页面数量不满足要求,就会将缓冲池中的脏页信息写入表空间中,这会导致预取请求的等待时间增加,并降低了查询语句的响应速度。为了避免这种情况的发生,应配置足够数量的页清除程序,以满足预取请求。
(4)文件系统高速缓存配置
默认情况下,操作系统将高速缓存从磁盘读写的文件数据。一个典型的读操作涉及以下物理磁盘访问:将数据从磁盘读取到文件系统高速缓存中,然后将这些数据从高速缓存复制到应用程序缓冲区。同样,写操作涉及以下物理磁盘访问:将数据从应用程序缓冲区复制到文件系统高速缓存,然后将它从文件系统缓存区中复制到物理磁盘。
可以发现,由于两次高速缓存需要额外的CPU周期,所以在某些情况下,在文件系统级和缓冲池中进行高速缓存可能会导致性能下降。为了避免两次高速缓存,大多数文件系统都有在文件系统级禁用高速缓存的功能,此功能通常称为非缓冲I/O。在UNIX上,此功能通常称为直接I/O(或DIO)。在Windows上,此功能相当于使用FILE_FLAG_NO_BUFFERING标记打开文件。此外某些文件系统(如IBM的JFS2或Symantec的VERITAS VxFS)也支持高速执行的并行I/O(CIO)功能。数据库管理器通过NO FILE SYSTEM CACHING表空间选项支持此功能。设置此CIO功能后,数据库管理器自动利用具有CIO功能的文件系统上的此项功能。此项功能有助于降低文件系统高速缓存的内存需求,从而使得有更多内存用于其他用途,如图1-11所示。
图1-11 非缓冲I/O
可以使用在CREATETABLESPACE语句的FILE SYSTEM CACHING选项禁用文件系统级高速缓存数据的这种行为。数据库管理器会屏蔽文件系统缓存,无须在文件系统层面做任何设置(除了存放LOB数据的文件系统)。
3.缓冲池设计
在数据库中,磁盘I/O通常是影响性能的最关键因素。因此,DB2通过缓冲池尽可能地避免物理I/O的发生。
通常而言,数据从磁盘读取之后,会进入缓冲池并放置在其中,直到DB2缓冲管理器决定这些内存页面需要被其他数据页占用。被应用程序请求的数据从缓冲池内找到的次数越频繁,整体的性能就越好。因为本质上是直接读取内存中的数据,避免了磁盘I/O操作,使得应用程序等待磁盘I/O的时间缩短。如果条件允许,可以尽量将数据表空间、临时数据表空间和索引表空间分别采用单独的缓冲池,这样可以在一定程度上提高读写性能。
1)缓冲池的合适大小
缓冲池尺寸的指定取决于可用的内存及数据量大小,并且根据实际需要来分配缓冲池大小。比如数据库中仅有一张较小的表会被经常访问,其他表可能半年甚至一年才被访问一次,这种情况下,只需分配较小的缓冲池就可以满足日常的性能需求。
2)多缓冲池配置
如果在当前操作环境中允许为DB2缓存分配较大的内存,那么多缓冲池配置可以最大限度地为特定的应用程序或数据库提供改善的性能。但是需要注意由于采用多个缓冲池,监视缓冲池的性能变得更加重要。
普遍来讲,对配置多缓冲池有如下建议。
(1)将表空间和它们相联系的索引分离到不同的缓冲池,以便使索引I/O最小化。
(2)将具有不同数据访问模式的数据分别置于不同的缓冲池中。典型的批处理和查询应用程序含有大量的连续处理,而OLTP的数据访问在本质上往往比较随机。这就提供了一种方法,来开发不同的阈值以在一个缓冲池适应各种特定类型的数据访问。
(3)为了隔离应用程序,提供一个单独的缓冲池,这就提供了一种方法,来严密监视一个存在运行问题的应用程序,或是测试新的应用程序。
(4)对于相对较小但是更新很快的表,足够大的独立缓冲池可以同时消除读取和写入I/O操作。
(5)为只读表(小的、参考表)设立单独的缓冲池也可以提高性能。
经过深思熟虑而设计的数据库可以提供重大的性能优势,但是它必须在应用程序的开发过程中尽早开始。上述很多原则在DB2的早期就已经被明智的开发人员所利用,并且至今仍保持着它们的正确性。然而清楚DB2功能上的进步,以及影响当前和以后应用程序的其他领域内的硬件和软件技术的变化,同样也是至关紧要的。当数据库性能成为发展过程中的一个重要焦点时,数据库设计将为DB2应用程序提供最优化的性能。
3)数据库容量评估
需要在设计期间对数据库容量的大小及增长进行充分考虑,以避免系统正式上线后带来的各种意外风险,并且可以根据容量的大小及增长速度提前规划内存分配及备份策略,以保证正常稳定的系统运转。
对于数据库的大小,可以调用GET_DBSIZE_INFO存储过程来查看整个数据容量的增长,例如:
db2 “CALL GET_DBSIZE_INFO(?, ?, ?,-1)” Value of output parameters —— — — —- Parameter Name : SNAPSHOTTIMESTAMP Parameter Value : 2007-10-18-18.09.46.966185 Parameter Name : DATABASESIZE Parameter Value : 436064256 Parameter Name : DATABASECAPACITY Parameter Value : 3034959872 Return Status=0
可以看到,当前数据库的大小约为415MB(436064256字节),预先分配的空间约为3GB(3034959872字节)。仅仅通过查看整个数据库的大小不可能按照线性分析预计整个系统的增长。需要按照一定频率对各个表及索引的增长情况进行详细统计,才可以有效地制定合理方案。
可以通过db2pd-d dbname-tcb index统计表及索引的大小记录增长情况,如图1-12所示。
图1-12 表基本信息
而表的大小可以通过公式(DataSize+Lfsize+LobSize) * pagesize计算。
索引大小可以根据公式IndexObjSize*pagesize计算,如图1-13所示。
图1-13 索引基本信息
1.3.4 系统设计对性能的影响
通常,给定工作负载的性能可由一两种关键系统资源的可用性和速度决定。我们必须正确识别那些资源,否则会陷入无休止地尝试错误操作的冒险中。并且,作为生产环境中的系统,一定要对其高可用性、安全性及维护策略等因素在设计阶段加以考虑,否则可能会导致意外风险及灾难。
1.硬件设计
这里的硬件设计指的是磁盘、内存及CPU的分配策略。良好的硬件设计不仅满足了性能的需求,也可以有效地防止资源浪费。
1)磁盘设计
对于一个在系统中运行的程序而言,最慢的操作是从磁盘中取得代码或数据,这是因为有下列原因:
(1)必须引导磁盘控制器直接访问指定的块(排队延迟);
(2)磁盘臂必须寻道以找到正确的柱面(寻道等待时间);
(3)读/写磁头必须等候直到正确的块旋转到它们下面(旋转等待时间);
(4)数据必须传送到控制器(传送时间),然后传送到应用程式中(中断处理时间)。
在过去十年中,CPU在速度方面取得了难以置信的进步,但磁盘在其容量和降低成本方面取得的进步更大。磁盘寻道时间和传输率方面也有所改善,但却落后于CPU速度方面的进步。因此,为了实现现代系统所需的总体性能,使用多个磁盘比以往更加重要,对于将要执行大量随机磁盘I/O操作的系统而言更是如此。通常,我们总是希望使用尽量少的磁盘来存储系统中的全部数据,但这通常会导致性能非常差。
除了程序中显式的读或写请求外,还有许多原因导致磁盘操作缓慢。频繁的系统调整活动证明是不必要地跟踪了磁盘I/O操作。而在数据库系统中,由于需要对活动日志、镜像日志、归档日志、表空间容器、控制文件及应用程序所产生的文件等进行频繁地读写操作,会给磁盘I/O性能带来沉重负担,稍有不慎就会带来严重的性能瓶颈,所以在磁盘设计时需要格外重视。
最好为DB2事务日志预留一些专用(非共享)磁盘,这是因为日志的I/O特征与DB2容器有很大的不同,日志I/O与其他类型的I/O之间的竞争关系会引起日志记录瓶颈,在需要执行大量写活动的系统中尤其如此。
对于RAID存储器,或者对于可独立寻址的驱动器,经验法则是为每个处理器核心至少配置10~20个磁盘。对于存储服务器,建议采用类似的数目,但是,在这种情况下,需要更加小心谨慎。存储服务器上的空间分配通常与容量(而非吞吐量)更为相关,最好充分了解数据库存储器的物理布局,以确保逻辑上相分离的存储器不会意外重叠。例如,对于4路系统而言,合理的分配可能是8个各包含8个驱动器的阵列。但是,如果这8个阵列全部共享相同的8个底层物理驱动器,那么与8个阵列分布于64个物理驱动器的情况相比,此配置的吞吐量将大幅下降。
通常,RAID-1磁盘对每秒能够为多达400个具有合理写密度的DB2事务提供足够的日志记录吞吐量。吞吐率越高或者日志记录量越大(例如批量插入期间的情况),需要的日志吞吐量越大,此吞吐量可以由RAID-10配置中通过写高速缓存磁盘控制器连接到系统的附加磁盘提供。
下面为一个数据库系统磁盘子系统设计的示例,图1-14主要表示在LVM环境下,在数据库中对I/O的操作主要集中在日志、表空间容器等几部分。由于日志的完整度保证数据库的一致性,所以更需要在性能及可用性方面加以考虑,一般推荐将日志所在的阵列设为RAID 10。
图1-14 系统磁盘设计
2)系统内存评估
由于CPU与磁盘实际上按不同的时标工作(分别为纳秒和毫秒),因此,需要使它们相分离才能实现合理的处理性能,这就是内存所起的作用。在数据库系统中,内存的主要用途是避免执行I/O,因此在某种程度上,系统的内存越多,性能就越好。内存成本在过去几年中大幅下降,现在,带有数十到数百GB的RAM的系统已经很常见。通常,为每个CPU分配4~8GB的内存对大多数应用程序而言已足够。
内存不足会占用交换区,导致性能大量下降。对一个数据库系统而言,内存主要分为数据库所占用内存与应用程序所占用内存。根据数据容量在设计阶段对内存的使用进行评估,可以避免过度分配内存导致占用交换区空间,或者分配过少的内存导致资源浪费。
在DB2数据库中,内存主要由实例内存、数据库内存、应用共享内存及应用私有内存等几个部分组成。根据数据量及最频繁使用的表的大小来规划内存分配是一个比较通用的方法。在后面会详细介绍关于内存的分配。
通过db2mtrk我们可以看到当前系统中数据库分配的内存情况,如图1-15所示。
图1-15 数据库内存分配情况
其中,-i选项代表收集实例内存信息、-d选项代表收集数据库内存信息、-p选项代表收集应用私有内存信息。
3)CPU设计
对一个数据库系统而言,有大量消耗CPU的操作通常为:SQL语句编译、大量的连接和排序。对于不同的工作负载,需要提前分配合理的CPU数量以避免CPU被争用及CPU瓶颈的发生。
在配置系统以提高性能时,CPU容量是其中一项主要的独立变量。由于所有其他硬件配置通常都由CPU容量决定,因此,预测给定工作负载所需的CPU容量并不容易。在商业智能(BI)环境中,合理的估算是,每个处理器核心处理200~300GB的活动原始数据。对于其他环境而言,比较好的方法是根据一个或多个现有DB2系统来测量所需的CPU容量。例如,如果新系统需要处理的用户数增加50%,并且运行的每个SQL语句都至少与现有系统中的SQL语句一样复杂,那么假定所需的CPU容量也增加50%比较合理。同样,还应该考虑其他在CPU使用率方面预计有所变化的因素,例如不同的吞吐量需求或者在使用触发器或引用完整性方面的变动。
在根据可用的信息很好地认识CPU需求之后,就可以逐步确定硬件配置的其他方面。虽然我们必须考虑数以TB字节或PB字节计的所需系统磁盘容量,但性能方面的最重要因素是每秒的I/O次数,即每秒的传输数据的字节数。实际上,此因素由涉及的磁盘数目确定。
2.操作系统配置
1)AIX配置
在AIX需要性能调优的参数很少,但通常来讲需要注意以下几个方面。
(1)VMO参数LRU_FILE_REPAGE应该设置为0。此参数控制AIX是否牺牲计算页或文件系统高速缓存页,此外minperm应该设置为3。这两个值都是AIX6.1中的缺省值。
(2)可以保留AIO参数maxservers的缺省值,即每个CPU运行10个异步I/O服务器。在系统运行期间可以使用ps-elfk|grepaio命令收集异步I/O(AIO)的信息并对maxservers参数进行调整。
(3)AIO参数maxreqs应该设置为MAX(NUM_IOCLEANERS*256,4096),此参数控制异步I/O请求的最大数目。
(4)hdisk参数queue_depth控制磁盘的队列深度,缺省值为3。该参数应该基于阵列中的物理磁盘数进行调整,通常建议将这个值改为物理硬盘数量的3倍,如果使用高端存储,则无须考虑此参数的设置问题。
(5)磁盘适配器参数num_cmd_elems控制可以进行排队以便发送到适配器的请求的数目,该参数应该设置为所有与适配器相连接的设备的queue_depth之和。
(6)此外需注意实例用户限制,建议默认限制改为core=-1、rss=-1、fsize=-1、data=-1。
(7)推荐使用命令chdev-l sys0-a fullcore=true开启fullcore。
2)Solaris和HP-UX配置
对于在Solaris或HP-UX上运行的DB2而言,可以使用db2osconf实用程序来检查内核参数及根据系统大小提供建议。db2osconf程序会根据内存大小及CPU个数来指定内核参数,此外,也可以借助于将当前系统配置与预期的将来配置作比较的常规缩放因子来进行指定。通常,db2osconf为配置Solaris和HP-UX提供了良好的起始点,但提供的并不是最佳值,这是因为该程序无法考虑当前及将来的工作负载。
3)Linux配置
将Linux系统用作DB2服务器时,可能需要更改某些Linux内核参数。由于Linux分发有所变化,并且此环境高度灵活,因此我们将只考虑一些需要根据Linux实现进行验证的最重要的设置。
在64位系统上,必须将SHMMAX(共享内存段的最大大小)设置为最小值1GB (1073741824字节),并且应该将SHMALL参数设置为数据库服务器上可用内存量的90%。缺省情况下,SHMALL是8GB。对DB2而言,其他重要的Linux内核配置参数及其建议值如下所述。
(1)kernel.sem:指定4个内核信号并进行以下设置,即SEMMSL=250、SEMMNS=256000、SEMOPM=32、SEMMNI=1024;
(2)kernel.msgmni(消息队列标识的数目):1024;
(3)kernel.msgmax(消息的最大大小,以字节计):65536;
(4)kernel.msgmnb(消息队列的缺省大小,以字节计):65536。
3.维护策略
在数据库中选择不同的维护策略会对整体系统产生一定影响,日常使用到的维护策略分为自动维护策略、备份策略及停机策略。
1)自动维护策略
DB2中提供了自动维护功能,但是如果启用自动维护,可能会造成一定的性能影响。自动维护分为4层,可以通过查看数据库配置参数获取自动维护的策略信息。
Automatic maintenance (AUTO_MAINT)=ON Automatic database backup (AUTO_DB_BACKUP)=OFF Automatic table maintenance (AUTO_TBL_MAINT)=ON Automatic runstats (AUTO_RUNSTATS)=ON Automatic statement statistics (AUTO_STMT_STATS)=ON Automatic statistics profiling (AUTO_STATS_PROF)=OFF Automatic profile updates (AUTO_PROF_UPD)=OFF Automatic reorganization (AUTO_REORG)=OFF
自动维护(AUTO_MAINT)中包含了自动备份(AUTO_DB_BACKUP)、自动表维护(AUTO_TBL_MAINT)、自动统计信息配置文件(AUTO_STATS_PROF)及自动重组(AUTO_REORG)4项,其中自动表维护中包含了统计信息收集及同步runstats机制。自动统计信息配置文件中包含了自动配置文件更新子选项。
如果上一层的选项关闭,其中的子选项就会失去功能。比如,如果把AUTO_MAINT设置为OFF,不管下面的其他值设置成什么,都相当于OFF。
由于自动维护特性会占用一定的资源,所以需要充分了解其内部机制,并制定相应的策略,充分地测试,否则可能会影响正常业务的运行。
2)备份策略
备份策略在设计中需要提前考虑。由于不同的工作负载停机时间不同,数据量不同,备份时间也不同。联机备份会对性能产生一定的影响。如果备份时间过长,可能会影响正常的交易。而如果没有完善合理的备份,发生数据丢失,将无法把损失减少到最小,所以需要在设计时根据当前的工作负载,从操作系统、磁盘、数据库等多角度设计备份方案,以保证正常稳定的业务运行。
3)停机策略
根据工作负载的类型不同,可用时间也不一样,但是一定要在设计时考虑到停机维护的时间及提供可用性方式,在日常生产系统中,一个系统每年需要一定的维护,用来预防升级维护等计划内操作导致系统停机,例如一个7*24小时的系统,就需要设计为热备份的架构,以保证维护期间不影响正常交易的进行。