《让DB2跑得更快——DB2内部解析与性能优化》

DB2数据库领域的精彩强音,DB2技巧精髓的热心分享,资深数据专家牛新庄、干毅民、成孜论、唐志刚联袂推荐!

本书作者在DB2China数据库论坛担任热点讨论版块版主,主持多次热点讨论以及专家现场诊断,擅长DB2数据库及相关产品的性能调优及故障分析,对DB2技能及实践经验有多年积累,并且近年来与多位业界专家一直在积极推动DB2领域的技术交流,真正理解DB2技术人员真正的需求与痛楚,是DB2系统知识及技巧精髓的热心分享者及贡献者。

作者本人出于对DB2的*与追求,通过长期的凝练与汇聚,将DB2知识系统化,把DB2数据库调优技巧的精髓热心地分享给广大读者,并且凭借深厚而扎实的理论及经验,对DB2数据库的内部进行了深入解析,这是对数据库领域所做出的重要贡献与精彩强音!

单看“内部解析”四个字,就已经能体现本书的宝贵价值,在“内部解析”的基础上进行“性能优化”,定会让您的DB2“跑得更快”!

《让DB2跑得更快——DB2内部解析与性能优化》

内容提要

本书以优化为主题,根据数据库内部原理将DB2数据库对SQL语句及其他操作的内部机制进行详细剖析,并将RDSDMSIXMBPSDB2内部组件不为人知的一面展现给大家,以期做到对数据库的调优过程知其然并知其所以然。同时本书结合响应时间与资源瓶颈两种性能问题的现象,对数据库调优的整体思路进行详细讲解,对原来老式的调优思路进行整理和改动,结合了DB2 V10.1版本的一些新的监控工具特性,以一种全新的方式阐述DB2数据库性能调优的基本思路及实践方法。本书适合DB2数据库管理员、数据库相关应用程序开发人员、系统管理员、系统架构师及有一定数据库基础的用户自学和参考,也可作为DB2培训的参考用书。


本书结构

全书分为5大篇共13章。第1篇主要对性能问题的定义、影响性能问题的因素、DB2的整体组件结构,以及对于各种类型语句的处理机制进行详细的探讨;第2篇主要针对DB2提供的各个监控工具进行阐述,并提供了一些监控建议;第3篇主要阐述DB2的内部运行机制及各个组件的原理;第4篇包含DB2中内部工具的优化与运行机制,以及DB2在各个平台中需要注意的性能参数;第5篇对性能优化思路进行了概括性的总结。

第1篇性能定义及整体架构第 1 章主要对性能问题的目标进行了阐述和定义,并描述了可能影响各个工作负载的特征,以及可能对其产生性能影响的因素。第2章对DB2的体系结构进行了基本介绍,并描述了DB2各个组件处理SQL语句的基本原理与机制。

第2篇性能监控工具及监控技巧第3章按照监控特性对DB2提供的监控工具进行了基本介绍,并介绍了一些基本的监控技巧。

第3篇性能分析及内部原理剖析第4章对优化器的原理进行了探讨,阐述了优化器的重写机制、优化原理及编译原理,并介绍了如何检查优化器的估算结果的两种方法。第5章介绍了解决优化器编译问题的的7种性能优化武器,以及何时且如何才能有效地使用这些武器解决实际问题。第6章描述了为了避免性能问题应该如何对数据库表及索引进行有效设计,针对合适的场景使用适合的技术才能更有效地避免性能问题的发生。第7章详细描述了DB2数据库的I/O原理,I/O性能通常是数据库运行过程中最为耗时的一环,本章详细介绍了DB2相关I/O情景,以及如何有效地提高I/O性能。第8章详细介绍了DB2中各个内存池的分配以及作用,并讲述了怎样定位及修复内存泄露的方法。第9章对数据库的物理结构进行了详细剖析,并讲解了各种情况下物理结构对于数据库性能的负面影响及避免方法。第10章对DB2中锁及latch等待事件进行了描述与分析,并分享部分等待事件解决案例及心得。

第4篇实用工具调优及操作系统优化第11章讲述了backup、restore、export、import、load、reorg、runstats等DB2提供的多种实用工具的执行原理以及性能调优方法。第12章介绍了AIX及Windows平台上CPU、内存、磁盘I/O及网络等方面的相关优化参数。

第5篇性能分析思路及优化总结第13章对性能分析思路进行了归纳与总结,并按照资源占用问题及响应时间缓慢的问题对数据库性能问题提供了整体分析的思路与解决方案。


精彩内容

SQL语句分类

一个SQL请求发送给DB2实例时,DB2实例会创建一个代理线程(db2agent)为该语句服务,db2agent首先调用RDS组件对该语句进行优化并编译,然后发送给RTI组件执行这些编译后的section,并调用DMS组件申请对于表或索引的访问要求,DMS在接受数据读取请求后,从缓冲池中读取数据并将结果集返回给RDS组件。RDS组件将DMS返回的结果集进行最终处理(比如排序等操作),处理完成后返回给客户端

RDS组件和DMS组件都会执行评估SQL谓词的操作并过滤部分数据。但从性能角度来讲,相对于RDS而言,DMS对性能更为重要,因为DMS可以提前过滤掉无效的数据,避免RDS重复处理无效数据。

盛水的木桶是由许多块木板箍成的,盛水量也是由这些木板共同决定的。若其中一块木板很短,则此木桶的盛水量就被短板所限制。这块短板就成了这个木桶盛水量的“限制因素”(或称“短板效应”)。而DB2数据库也是由各个组件组成的,当我们面对一个数据库性能问题时,首先要了解最短的木板到底发生在哪个组件上,才能有针对性地解决性能问题。


我们开始面对一个数据库性能问题时,首先要弄明白当前系统究竟发生了什么,是什么动作引起了性能问题,进而根据动作判断引发性能问题的瓶颈。就像之前提到的水管,我们首先要了解当前的水量,进而判断水管中的瓶颈。


了解DB2的机制前,我们首先来讨论下SQL语句的分类。SQL语句主要分为以下5类。

1)数据查询语言(DQL):其语句也称为“数据检索语句”,用以从表中获得数据,确定数据怎样由应用程序给出。保留字SELECTDQL(也是所有SQL)用得最多的动词,其他DQL常用的保留字有WHEREORDER BYGROUP BYHAVING。这些DQL保留字常与其他类型的SQL语句一起使用。

2)数据操作语言(DML):其语句包括动词INSERTUPDATEDELETE。它们分别用于添加、修改和删除表中的行。也称为动作查询语言。

3)事务处理语言(TPL):它的语句能确保被DML语句影响的表的所有行得以及时更新。TPL语句包括COMMITROLLBACK

4)数据控制语言(DCL):它的语句通过GRANTREVOKE获得许可,确定单个用户和用户组对数据库对象的访问。某些RDBMS可用GRANTREVOKE控制对表单个列的访问。

5)数据定义语言(DDL):其语句可在数据库中创建新表(CREAT TABLE)、为表加入索引等。DDL包括许多与数据库目录中获得数据有关的保留字。它也是动作查询的一部分。

一条Select语句丛生到死的处理过程

以一条普通的“select * from table order by …”语句为例。图2-21中显示为该语句在数据库中各个组件之间的处理过程,各个步骤分别代表:

1select语句通过网络传送给代理线程;

2SQL语句经过重写及编译,将编译结果存放在Package cache中;

3)协调代理线程(coordinating agent)按照执行计划执行语句,将预取请求发送给预取线程;

4)预取线程在容器间并行执行异步I/O,将数据页放入缓冲池中(如果没有发生预取,则略过第4步);

5)将容器中的数据页放入缓冲池中;

6)将需要排序的数据移动到排序堆中;

7)如果排序堆不够,则将排序数据放到临时表空间中;

8)排序完成的行被子代理送回客户端。

执行过程中要注意以下几个细节,这些细节也是影响性能的关键因素:

1SQL语句的执行计划可能会极端影响性能;

2)如果发生预取,预取线程会从磁盘中取出连续的数据页,此时代理线程处于等待状态;

3)如果没发生预取,则协调代理会并行地从磁盘中取出数据。

到此为止,一条select语句就彻底执行完了,我们可以看到,一条最基本的查询语句在DB2中经过各个组件的协调,历经了8个步骤最终完成。在遇到一个性能问题时,任何一个环节都可能成为性能瓶颈。

索引分裂
当事务向索引中最后一个叶子节点数据块上插入一条大于或等于(ROWID大于最大值的ROWID)数据块上最大值的数据,且该数据块上不存在其他未提交事务时,如果没有足够空间,就会发生 9-1 分裂,即分裂时,绝大部分数据保留在原有节点数据块上,仅少量数据被转移到新数据块上。假设当前有一个根节点及PAGE1PAGE2PAGE3三个叶子节点,如图7-24所示。当叶子节点PAGE1或者PAGE3进行分裂时,都会选择9-1分裂方式。

向索引中插入大于、等于最大值的数据时,PCTFREE会被忽略。如果叶子节点分裂导致枝节点也分裂,枝节点的分裂比例和叶子节点的分裂比例是相同的。

实际上,无论是9-1分裂还是5-5分裂,其目的都是减少分裂,因为索引分裂是一个代价高昂的操作。发生9-1分裂时,通常索引的键值是递增的,且表上的主要操作是插入操作且事务并发量比较低的情况,应保证新的数据块上有最大的空闲空间插入新值,以减少了分裂的发生。发生5-5分裂时,通常表上的并发事务较多,且插入、删除的数据比较分散,因此需要保持分裂的新、老数据块上有相当的空闲空间以容纳新事务、新数据。当我们持续不断地对叶子节点进行插入操作时,就会引发叶子节点分裂,可以使用db2pd工具进行查看。

内存泄露检测

寻找内存泄漏时,这部分的输出结果通常没有用处。我们不关心内存块从哪分配,只关心相关内存块耗费了多少内存。所以只需搜索“Memory blocks sorted”关键字,每个内存池中都会有这样的一部分,例如DBMS内存集中的kernelheap部分:

《让DB2跑得更快——DB2内部解析与性能优化》



输出结果已经按照大小进行了排序,我们可以很容易地看到在该内存堆中消耗最大的内存块。此时需要关注两件事情,分配的整体大小及内存块分配的频率。“TotalCount”的数值是我们在检测内存泄漏中最关注的事情,“TotalCount”通常来说应该非常小,或者与当前线程数成比例(除了基于缓存的内存池,例如package cachebufferpool等),在上面的例子中,可以看到sqlowlst.C的第566行分配了36次内存块,通过db2pd -edus查看当前数据库内的线程,可以看到每个线程都会对应一次分配。假设发现当前分配的次数远远超过当前数据库内的线程数量,则可以说明当线程中断时数据库没有释放对应的内存。这样的话,就可以继续查看内存泄漏是由哪部分组件引起的。