用Oracle并行查询发挥多CPU的威力

在一个单独的服务器中安装更多的CPU成为目前的一个趋势。使用对称多处理服务器(SMP)的情况下,一个Oracle服务器拥有8个、16个或32个CPU以及几吉比特RAM的SGA都不足为奇。
    Oracle跟上了硬件发展的步伐,提供了很多面向多CPU的功能。从Oracle8i开始,Oracle在每个数据库函数中都实现了并行性,包括SQL访问(全表检索)、并行数据操作和并行恢复。对于Oracle专业版的挑战是为用户的数据库配置尽可能多的CPU。

    在Oracle环境中实现并行性最好的方法之一是使用Oracle并行查询(OPQ)。我将讨论OPQ是如何工作的和怎样用它来提升大的全表检索的响应时间以及调用并行事务回滚等等。

    使用OPQ

    当在Oracle中进行一次合法的、大型的全表检索时,OPQ能够极大地提高响应时间。通过OPQ,Oracle将表划分成如图A所示的逻辑块。

    图 A

用Oracle并行查询发挥多CPU的威力

    由OPQ划分的表

    一旦表被划分成块,Oracle启用并行的子查询(有时称为杂务进程),每个子查询同时读取一个大型表中的一块。所有子查询完毕以后,Oracle将结果会传给并行查询调度器,它会重新安排数据,如果需要则进行排序,并且将结果传递给最终用户。OPQ具有无限的伸缩性,因此,以前需要花费几分钟的全表检索现在的响应时间却不到1秒。

    OPQ严重依赖于处理器的数量,通过并行运行之所以可以极大地提升全表检索的性能,其前提就是使用了N-1个并行进程(N=Oracle服务器上CPU的数量)。

    必须注意非常重要的一点,即Oracle9i能够自动检测外部环境,包括服务器上CPU的数量。在安装时,Oracle9i会检查服务器上CPU的数量,设置一个名为cpu_count的参数,并使用cpu_count作为默认的初始化输入参数。这些初始化参数会影响到Oracle对内部查询的处理。

    下面就是Orale在安装时根据cpu_count而设置的一些参数:

    fast_start_parallel_rollback
    parallel_max_servers
    log_buffer
    db_block_lru_latches

参数    

    让我们进一步看看CPU的数量是如何影响这些参数的。

    参数fast_start_parallel_rollback

    Oracle并行机制中一个令人兴奋之处是在系统崩溃时调用并行回滚得能力。当Oracle数据库发生少有的崩溃时,Oracle能自动检测未完成的事务并回滚到起始状态。这被称为并行热启动,而Oracle使用基于cpu_count的fast_start_parallel_rollback参数来决定未完成事务的秉性程度。

    并行数据操纵语言(DML)恢复能够在Oracle数据库崩溃后极大地加快其重新启动的速度。此参数的默认值是系统CPU数量的两倍,但是一些DBA们认为应该将这个值设置为cpu_count的四倍。

    参数parallel_max_servers_parameter

    Oracle一个显著的加强是自动决定OPQ并行的程度。由于Oracle清楚服务器中CPU的数量,它会自动分配合适的子进程的数量来提升并行查询的响应时间。当然,会有其它的外部因素,比如表的划分以及磁盘输入/输出子系统的布局等,但是根据cpu_count来设置parallel_max_servers参数将给Oracle一个合理的依据来选择并行的程度。

    由于Oracle的并行操作严重依赖服务器上CPU的数量,parallel_max_servers会被设置成服务器上CPU的数量。如果在一台服务器上运行多个实例,则默认值太大了,会导致过度的页面交换和严重的CPU负担。并行的程度还依赖于目标表中分区的数量,因此parallel_max_servers应该设置成足够大以允许Oracle为每个查询选择最佳数量的并行子查询。

    参数log_buffer

    参数log_buffer定义了供即刻写入redo日志信息的保留RAM的数量,这个参数受cpu_count的影响。Oracle推荐log_buffer最大为cpu_count乘以500KB或128KB。CPU的数量对于log_buffer来说非常重要,因为Oracle会生成多日志写入(LGWR)进程来异步释放redo信息。

    log_buffer是Oracle中最易误解的的RAM参数之一,通常存在下面几个配置错误:

    log_buffer被设置得太高(例如,大于1MB),这回引起性能问题,因为大容量的结果会使得写入同步进行(例如,日志同步等待事件非常高)。log_buffer不是db_block_size的倍数。在的Oracle9i中,log_buffer应该是2048字节的倍数。

    参数db_block_lru_latches

    LRU锁的数量是在Oracle数据库内部用来管理数据库缓冲的,这严重依赖于服务器上CPU的数量。

    很多聪明的Oracle9i的DBA使用多冲数据缓冲(例如db_32k_cache_size),他们推荐将这个未公开声明的参数重设置为默认的最大值。db_block_lru_latches参数在Oracle8i中使用得很多,但是在Oracle9i中变成了一个未公开声明的参数,因为Oracle现在根据数据库拥有的CPU数量设置了一个合理的默认值。

    db_block_lru_latches默认被设置为服务器上cpu_count的一半(例如服务器上只有一个Oracle数据库)。Oracle推荐db_block_lru_latches千万不要超过cpu_count的两倍或三倍,或db_block_buffers的五十分之一。

    如果使用多缓冲池则这种计算方法有一个问题,因为不能控制分配给每个数据缓冲池的锁的数量。如果db_writers参数大于1,则默认值或许显得太小。

    加强服务器

    Oracle数据库总是在提升性能,根据外部服务器环境检测cpu_count和基本参数设置的能力对于Oracle软件来说是一个重要的加强。

    随着更多的Oracle系统转移到SMP上来,当客户要采取增强措施并将众多的数据库转移到拥有32个或64个CPU的巨大服务器上来的时候,这些参数显得愈发重要。

 

 

 

并行查询并行度Degree与instances 设置

在DBA_TABLES字典表中有一个degree字段,这个字段代表并行查询在数据表上的并行度,在RAC环境中,这个参数还和实例有关。
以下生活文档中对于 DEGREE 和 INSTANCES 参数的说明:
DEGREE VARCHAR2(10) Number of threads per instance for scanning the table
INSTANCES VARCHAR2(10) Number of instances across which the table is to be scanned

但是注意,当你使用类似如下查询时,你可能无法获得返回值:
SQL> select table_name from dba_tables where degree='1' or degree='DEFAULT';

no rows selected

我们看一下Degree以及instances的记录方式:
SQL> select degree,length(degree) from dba_tables
2 group by degree;
DEGREE LENGTH(DEGREE)
-------------------- --------------
DEFAULT 10
1 10

SQL>select instances,length(instances) from dba_tables
2 group by instances;
INSTANCES LENGTH(INSTANCES)
-------------------- -----------------
DEFAULT 10
1 10
0 10
Degree和Instances实际上记录了10个字符,左端用空格补齐。
在 dba_tables 的创建语句中,我们可以找到根本原因,以下是这两个字段的定义来源:
lpad(decode(t.degree, 32767, 'DEFAULT', nvl(t.degree,1)),10),
lpad(decode(t.instances, 32767, 'DEFAULT', nvl(t.instances,1)),10),

以上信息来自Oracle10gR2数据库:
SQL> select table_name,owner from dba_tables where degree=' DEFAULT' or instances=' DEFAULT';

TABLE_NAME OWNER
------------------------------ ------------------------------
TEST_EXT2 SYS

SQL> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
PL/SQL Release 10.2.0.1.0 - Production
CORE 10.2.0.1.0 Production
TNS for Linux: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 - Production

以下收录dba_tables视图的创建语句:
CREATE OR REPLACE VIEW dba_tables (owner,
table_name,
tablespace_name,
cluster_name,
iot_name,
status,
pct_free,
pct_used,
ini_trans,
max_trans,
initial_extent,
next_extent,
min_extents,
max_extents,
pct_increase,
FREELISTS,
freelist_groups,
LOGGING,
backed_up,
num_rows,
blocks,
empty_blocks,
avg_space,
chain_cnt,
avg_row_len,
avg_space_freelist_blocks,
num_freelist_blocks,
DEGREE,
INSTANCES,
CACHE,
table_lock,
sample_size,
last_analyzed,
partitioned,
iot_type,
TEMPORARY,
secondary,
NESTED,
BUFFER_POOL,
row_movement,
global_stats,
user_stats,
DURATION,
skip_corrupt,
MONITORING,
cluster_owner,
dependencies,
compression,
dropped
)
AS
SELECT u.NAME, o.NAME,
DECODE (BITAND (t.property, 2151678048), 0, ts.NAME, NULL),
DECODE (BITAND (t.property, 1024), 0, NULL, co.NAME),
DECODE ((BITAND (t.property, 512) + BITAND (t.flags, 536870912)),
0, NULL,
co.NAME
),
DECODE (BITAND (t.trigflag, 1073741824),
1073741824, 'UNUSABLE',
'VALID'
),
DECODE (BITAND (t.property, 32 + 64),
0, MOD (t.pctfree$, 100),
64, 0,
NULL
),
DECODE (BITAND (ts.flags, 32),
32, TO_NUMBER (NULL),
DECODE (BITAND (t.property, 32 + 64),
0, t.pctused$,
64, 0,
NULL
)
),
DECODE (BITAND (t.property, 32), 0, t.INITRANS, NULL),
DECODE (BITAND (t.property, 32), 0, t.MAXTRANS, NULL),
s.iniexts * ts.BLOCKSIZE,
DECODE (BITAND (ts.flags, 3),
1, TO_NUMBER (NULL),
s.extsize * ts.BLOCKSIZE
),
s.minexts, s.maxexts,
DECODE (BITAND (ts.flags, 3), 1, TO_NUMBER (NULL), s.extpct),
DECODE (BITAND (ts.flags, 32),
32, TO_NUMBER (NULL),
DECODE (BITAND (o.flags, 2),
2, 1,
DECODE (s.lists, 0, 1, s.lists)
)
),
DECODE (BITAND (ts.flags, 32),
32, TO_NUMBER (NULL),
DECODE (BITAND (o.flags, 2),
2, 1,
DECODE (s.GROUPS, 0, 1, s.GROUPS)
)
),
DECODE (BITAND (t.property, 32 + 64),
0, DECODE (BITAND (t.flags, 32), 0, 'YES', 'NO'),
NULL
),
DECODE (BITAND (t.flags, 1), 0, 'Y', 1, 'N', '?'), t.rowcnt,
DECODE (BITAND (t.property, 64), 0, t.blkcnt, NULL),
DECODE (BITAND (t.property, 64), 0, t.empcnt, NULL), t.avgspc,
t.chncnt, t.avgrln, t.avgspc_flb,
DECODE (BITAND (t.property, 64), 0, t.flbcnt, NULL),
LPAD (DECODE (t.DEGREE, 32767, 'DEFAULT', NVL (t.DEGREE, 1)), 10),
LPAD (DECODE (t.INSTANCES, 32767, 'DEFAULT', NVL (t.INSTANCES, 1)),
10
),
LPAD (DECODE (BITAND (t.flags, 8), 8, 'Y', 'N'), 5),
DECODE (BITAND (t.flags, 6), 0, 'ENABLED', 'DISABLED'),
t.samplesize, t.analyzetime,
DECODE (BITAND (t.property, 32), 32, 'YES', 'NO'),
DECODE (BITAND (t.property, 64),
64, 'IOT',
DECODE (BITAND (t.property, 512),
512, 'IOT_OVERFLOW',
DECODE (BITAND (t.flags, 536870912),
536870912, 'IOT_MAPPING',
NULL
)
)
),
DECODE (BITAND (o.flags, 2), 0, 'N', 2, 'Y', 'N'),
DECODE (BITAND (o.flags, 16), 0, 'N', 16, 'Y', 'N'),
DECODE (BITAND (t.property, 8192),
8192, 'YES',
DECODE (BITAND (t.property, 1), 0, 'NO', 'YES')
),
DECODE (BITAND (o.flags, 2),
2, 'DEFAULT',
DECODE (s.cachehint,
0, 'DEFAULT',
1, 'KEEP',
2, 'RECYCLE',
NULL
)
),
DECODE (BITAND (t.flags, 131072), 131072, 'ENABLED', 'DISABLED'),
DECODE (BITAND (t.flags, 512), 0, 'NO', 'YES'),
DECODE (BITAND (t.flags, 256), 0, 'NO', 'YES'),
DECODE (BITAND (o.flags, 2),
0, NULL,
DECODE (BITAND (t.property, 8388608),
8388608, 'SYS$SESSION',
'SYS$TRANSACTION'
)
),
DECODE (BITAND (t.flags, 1024), 1024, 'ENABLED', 'DISABLED'),
DECODE (BITAND (o.flags, 2),
2, 'NO',
DECODE (BITAND (t.property, 2147483648),
2147483648, 'NO',
DECODE (ksppcv.ksppstvl, 'TRUE', 'YES', 'NO')
)
),
DECODE (BITAND (t.property, 1024), 0, NULL, cu.NAME),
DECODE (BITAND (t.flags, 8388608), 8388608, 'ENABLED', 'DISABLED'),
DECODE (BITAND (t.property, 32),
32, NULL,
DECODE (BITAND (s.spare1, 2048),
2048, 'ENABLED',
'DISABLED'
)
),
DECODE (BITAND (o.flags, 128), 128, 'YES', 'NO')
FROM SYS.user$ u,
SYS.ts$ ts,
SYS.seg$ s,
SYS.obj$ co,
SYS.tab$ t,
SYS.obj$ o,
SYS.obj$ cx,
SYS.user$ cu,
x$ksppcv ksppcv,
x$ksppi ksppi
WHERE o.owner# = u.user#
AND o.obj# = t.obj#
AND BITAND (t.property, 1) = 0
AND BITAND (o.flags, 128) = 0
AND t.bobj# = co.obj#(+)
AND t.ts# = ts.ts#
AND t.file# = s.file#(+)
AND t.block# = s.block#(+)
AND t.ts# = s.ts#(+)
AND t.dataobj# = cx.obj#(+)
AND cx.owner# = cu.user#(+)
AND ksppi.indx = ksppcv.indx
AND ksppi.ksppinm = '_dml_monitoring_enabled'

你可能感兴趣的:(oracle,sql,linux,cache,配置管理)