Menghe

导航

浅析 DB2 中的并行处理

并行处理与并发控制

说起数据库中的并行处理(Parallel Processing In Database),往往容易让人理解为众所周知的并发处理(Concurrent Processing)。从中文的字面意思来看,二者似乎并没有什么区别,但事实上,他们并不是一回事,并发处理只是并行处理的一个方面。

并行处理,指的是在数据库系统中,多个任务在某段时间内同时运行。从不同层次来看,有应用程序 / 事务之间的并行处理、应用 / 事务内部不同数据库分区间的并行处理,以及数据库分区内部的并行处理。

通常来说,不同应用程序 / 事务的并行处理,被称作并发处理。数据库中的并发处理(也叫并发控制,Concurrent Control),指的是在一个数据库系统中,多个事务(Transactions)能够同时运行。一般而言,这些同时运行的事务是通过数据库中的锁机制(Locking Mechanism)和隔离级(Isolation Level)别来实现彼此之间的独立、隔离,从而保证数据的完整性和有效性。

例如,事务 1 在对表 T1 进行更新的同时,事务二在对表 T1 进行查询。根据业务的需要,可以对查询设置不同的隔离级别,在互不影响的前提下,两个事务都能完成得到相应的结果。并发处理和控制是关系型数据库的重要特征和功能之一。关于事务、隔离级别,有很多相应的文档和教程,因此本文不针对这部分内容进行讨论。如果读者需要了解这部分内容,请参考“参考资源”部分关于这方面内容的文章。

同时,在一个事务内部,为了更快地处理数据,数据库系统也可以有并行处理。例如,我们提交一个查询(Query)给数据库,在这个查询的执行中需要对一个表进行全表扫描(Full Table Scan),如果该数据库处于数据库分区环境中,那么该表的数据将会按照一定规则分布在不同的数据库分区中,对于不同数据库分区中数据的访问是可以同时进行的,因此该全表扫描的任务会被拆分成为数据库分区个数的子任务,分发给各个数据库分区,各分区独立地同时运行自己的子任务,这就是上文提到的数据库分区间的并行处理。

在一个数据库分区(数据库分区环境下的一个数据库分区,或者非数据库分区环境下的普通数据库)内部,一个任务也可以被拆分成若干子任务。数据库管理器(Database Manager)可以把任务拆分成若干逻辑独立的子任务,并将各个子任务交给不同的子进程或者子线程,让这些子进程 / 线程同时执行这些子任务,在所有子任务都完成之后,把这些进程或者线程的处理结果组装在一起,进行后续处理。这类的并行处理,正是本文要讨论的重点。

DB2 LUW 中事务内部的并行处理

在 DB2 LUW 中,事务内部的并行处理分为两类,一类是数据库分区之间的并行处理(Inter-Partition Parallel Processing),另一类是数据库分区内的并行处理(Intra-Partition Parallel Processing)。这里的分区(Partition),指的是 DB2 数据库分区(Data Partition Feature,DPF)环境下的数据库分区,而不是分区表(Range Partition Table)的数据分区(Data Partition)。在澄清了这一点之后,这两类并行处理就很容易区分和理解了。

数据库分区之间的并行处理

在数据库分区(Data Partition Feature,DPF)环境下,通常来说,一张表中的数据会被数据库存放在不同的数据库分区(也称作数据库节点,Database Nodes)。而 DB2 中的 DPF 环境是一种无共享的环境(Share Nothing Environment),也就是说不同的数据库分区之间并没有共享存储,因此,DPF 环境下一个表的不同部分是独立存在于不同的数据库分区之中的。这样的分布存储,为数据库分区间的并行处理创造了天然条件。

还是之前的例子,对于一个需要进行表扫描的查询而言,在 4 个数据库分区的 DPF 环境下,该扫描工作就会被分割成为对于该表的 4 个扫描任务,分别同时运行在这 4 个数据库分区上,在这 4 个扫描任务都完成之后,DB2 将结果组装在一起,返回给用户,或者进行下一步处理。

数据库分区内部的并行处理

在 DPF 环境下的单个数据库分区中,或者非 DPF 环境下的数据库中,同样存在的并行处理,只不过这一类的并行处理并不像数据库分区之间的并行处理那么简单。数据库分区之间的相对独立,为数据库分区之间的并行处理提供了天然有利的前提条件,一个任务的分解与分配都是基于数据库分区的特征由数据库管理器(Database Manager,DBM)自己完成的。然而,在数据库分区内部,并行处理并不是天然存在的,这一特性需要用户来配置和维护。

回页首

DB2 的进程模型和并行处理机制

在介绍如何配置和使用 DB2 的数据库分区内部并行处理特性之前,有必要了解其实现机制,这就不得不从 DB2 的进程模型说起。

从 DB2 V9.1 开始,DB2 使用了线程取代了之前的进程实现。关于详细的 DB2 进线程模型,请读者参考本文末尾处参考资源的相关内容。在众多的 DB2 线程中,与数据库分区内并行处理相关的线程是 db2agent、db2agntp 和 db2agnta。db2agent 是用来接收并处理用户请求的,在一个 DB2 客户端(Client)程序连接到 DB2 的时候,数据库管理器会将该连接与一个 db2agent 线程相关联,而后,该客户端程序的所有任务请求都由该 db2agent 线程来处理。通常而言,在单一数据库分区的环境下,未启用数据库分区内的并行处理特性时,db2agent 自己去请求并完成全部任务,例如编译 SQL 语句,对语句进行优化并生成访问计划(Access Plan)以及执行访问计划,返回结果等;在启用了数据库分区内的并行处理后,db2agent 在执行 SQL 语句的访问计划时,并不会自己去执行相应的操作,而会按照访问计划中的内容,将该任务的子任务分发(Dispatch)给子代理线程(Sub-agent),由子代理线程去执行,最后,db2agent 线程将各个子代理线程的结果进行汇总,返回给客户端程序或者进行下一步处理。一个子代理进程处于空闲状态时,它被命名为 db2agnta;在 db2agent 分配子任务给一个空闲的子代理线程(也就是 db2agnta)之后,该子代理线程进入“正在执行”状态,线程名就变为 db2agntp。在一个 db2agntp 执行完相应的指令之后,会进入“空闲”状态,线程名将被改为 db2agnta。在未启用数据库分区内的并行处理特性的环境中,只有 db2agent 线程,没有 db2agnta 和 db2agntp 线程。

要查看 DB2 中的线程信息,可以使用如下的 db2pd 命令:


清单 1.使用 db2pd 查看 DB2 中的线程
				  => db2pd -edus    Database Partition 0 -- Active -- Up 0 days 00:00:35 -- Date 10/30/2011 13:41:08    List of all EDUs for database partition 0    db2sysc PID: 12044   db2wdog PID: 12042   db2acd  PID: 12061    EDU ID    TID            Kernel TID     EDU Name                           …  =========================================================================== …  54        47116793669952 12104          db2agnta (TESTDB) 0                …  53        47116797864256 12103          db2agnta (TESTDB) 0                …  52        47116802058560 12102          db2agnta (TESTDB) 0                …  51        47116806252864 12101          db2agnta (TESTDB) 0                … … 

回页首

使用数据库分区内并行

在介绍如何配置实用数据库分区内单一查询的并行处理之前,先引入查询并行度(Degree of Parallelism)的概念。查询并行度是一个数字,指的是一个查询在一个数据库分区内并分割成为的子任务的个数。例如,一个查询在数据库节点 0 上的并行度是 6,指的是该查询在该数据库分区上运行的部分将被分成 6 个独立的、可同时执行的子任务。

要配置使用 DB2 数据库分区内的并行处理特性,首先,要在数据库实例的配置参数中打开 INTRA_PARALLEL 这一选项,这意味着该实例启用了数据库分区内部并行处理的功能,查询可以被分割成并行处理的子任务。如清单 2 所示:


清单 2. 启用数据库分区内的并行处理
				  => db2 UPDATE DBM CFG USING INTRA_PARALLEL YES   DB20000I  The UPDATE DATABASE MANAGER CONFIGURATION command completed   successfully.  

由于这是一个数据库实例级别(Instance Level)的配置参数,如果该实例下的任意数据库处于活动状态,在更新后需要重新启动数据库才能生效。在缺省状态下,该配置参数是关闭(NO),在执行查询是不会启用数据库分区内的并行处理特性。因此,要启用数据分区内的并行处理特性,必须显示打开该参数。

第二步,设置数据库实例参数最大查询并行度(MAX_QUERY_DEGREE),如清单 3 所示:


清单 3. 设置最大查询并行度(可选)
				  => db2 UPDATE DBM CFG USING MAX_QUERYDEGREE 16   DB20000I  The UPDATE DATABASE MANAGER CONFIGURATION command completed   successfully.  

顾名思义,该参数为数据库分区内部查询并行度的最大值,任何一个查询都不能被拆分成为超过该数值数量的子任务。这个参数的设置是可选的,其默认值是 -1(或者 ANY),也就是说在启用了数据库分区内的并行处理特性之后,系统将由优化器来决定并行度。

第三步,设置数据库参数缺省查询并行度(DFT_DEGREE,Default Degree of Parallelism),如清单 4 所示:


清单 4. 设置缺省查询并行度(可选)
				  => db2 UPDATE DB CFG FOR TESTDB USING DFT_DEGREE 8   DB20000I  The UPDATE DATABASE CONFIGURATION command completed successfully.  

该参数指定了查询在一个分区内的缺省并行度,在查询中没有指定并行度的时候,该参数会被用作为并行度。该参数的默认值是 1,也就是说任何查询在缺省状态下是不会被并行运行的。该参数除了可以被设置为一个整数之外,还可以设置成 ANY,这时候,查询的并行度由优化器来决定。

接下来,就是对于查询指定并行度了。对于静态 SQL(Static SQL),可以在 PREP 和 BIND 命令指定 DEGREE 参数;对于动态 SQL,可以设置变量 CURRENT DEGREE。对于静态 SQL 和动态 SQL 的相关概念,请读者查询相应的文档,此处不再赘述,仅以动态 SQL 为例。

要设置 CURRENT DEGREE 变量,可以使用如清单 5 的语句:


清单 5. 设置 CURRENT DEGREE 变量
				  => db2 SET CURRENT DEGREE \'4\'  DB20000I  The SQL command completed successfully.  

要查询当前 CURRENT DEGREE,可以使用 VALUES 语句,如清单 6 所示:


清单 6. 检查 CURRENT DEGREE 变量
				  => db2 VALUES CURRENT DEGREE    1      -----   4        1 record(s) selected.   

一个查询的并行度在编译器对该语句进行优化时确定,并记录在访问计划(Access Plan)中。要检查一个查询被拆分成为多少个子任务,可以使用 db2expln 工具将其访问计划格式化并输出,进而就能看到该查询被执行时的并行度了。请参考清单 7 中的黑体字部分。


清单 7. 验证数据库分区内的并行处理
				  => db2expln -database testdb -terminal -statement "select * from t1 where C1 > 0"   DB2 Universal Database Version 9.7, 5622-044 (c) Copyright IBM Corp. 1991, 2009   Licensed Material - Program Property of IBM   IBM DB2 Universal Database SQL and XQUERY Explain Tool    DB2 Universal Database Version 9.7, 5622-044 (c) Copyright IBM Corp. 1991, 2009   Licensed Material - Program Property of IBM   IBM DB2 Universal Database SQL and XQUERY Explain Tool    ******************** DYNAMIC ***************************************    ==================== STATEMENT ==========================================           Isolation Level          = Cursor Stability          Blocking                 = Block Unambiguous Cursors          Query Optimization Class = 5           Partition Parallel       = No          Intra-Partition Parallel = Yes (Bind Degree = 4    )          SQL Path                 = "SYSIBM", "SYSFUN", "SYSPROC", "SYSIBMADM",                                     "XUJING"    Statement:       select *    from t1    where C1 > 0    Intra-Partition Parallelism Degree = 4   Section Code Page = 1208    Estimated Cost = 7.603910   Estimated Cardinality = 3.000000    Process Using 4 Subagents  |  Access Table Name = XUJING.T1  ID = 2,4   |  |  #Columns = 1   |  |  Parallel Scan   |  |  Skip Inserted Rows   |  |  Avoid Locking Committed Data   |  |  Currently Committed for Cursor Stability   |  |  May participate in Scan Sharing structures   |  |  Scan may start anywhere and wrap, for completion   |  |  Fast scan, for purposes of scan sharing management   |  |  Scan can be throttled in scan sharing management   |  |  Relation Scan   |  |  |  Prefetch: Eligible   |  |  Lock Intents   |  |  |  Table: Intent Share   |  |  |  Row  : Next Key Share   |  |  Sargable Predicate(s)   |  |  |  #Predicates = 1   |  Insert Into Asynchronous Local Table Queue  ID () = q1   Access Local Table Queue  ID () = q1  #Columns = 1   Return Data to Application   |  #Columns = 1    End of section   

回页首

总结

在多处理器(Multiple Processors)环境下,使用数据库分区内的并行处理特性,能大大提高 CPU 的利用率,进而提高数据库查询的性能。通常来说,在 DB2 中,启用 INTRA_PARALLEL 之后,其他配置均采用默认值(MAX_QUERY_DEGREE 为 -1 或 ANY,DFT_DEGREE 为 -1 或 ANY),即可使系统达到最优状态。在某些情况下,如果 DB2 的并行性能未能达到最优,可根据数据分布特性、查询的特征等手工配置相应的并行度,使查询性能得到优化。


参考资料

学习

posted on 2012-01-26 21:25  孟和  阅读(1183)  评论(0编辑  收藏  举报