一、问题描述
某大型国有银行的一套业务系统,近期由小型机迁移至X86环境。据项目组反映部分DB_LINK查询比原来小型机慢。这不对啊,相同的存储,CPU也更多,内存也更大。
于是 DBA随手挑出一张大表,做个简单的COUNT(*)查询,发现Linux比AIX慢了6倍 。重复执行多次,结果也类似。难道委屈项目组了,这套 X86 就是比小机慢? 于是找上中亦,深入分析下问题原因。
执行时间对比
AIX 下执行时间为 3 分 10 秒
Linux 下 执行 时间为 19分 3 秒
相同 SQL 语句在, AIX 环境下执行时间为 Linux 下执行时间快 6 倍。
二、问题排查
环境有何差异
现场的环境配置如下表:
看得出, Linux配置确实比AIX 来的高 。
其他表试试?
既然每次 执行 TAB1 , Linux 都会比AIX慢6 ~7 倍,那不如我们换张表试试,这边我随机测试了5 张 表,结果 Linux 都会比 AIX 快20 % 。那么问题肯定和这张表有关。
是不是 Linux 环境上该表上碎片太多了?不对,我们先看执行计划和等待事件 。
执行计划
检查 2 个 环境的执行计划是否一致,都是走 Index Fast Full Scan
等待事件应该为“ db file scattered read ”
AWR
对比分析
抓取当时的 AWR 报告进行对比 分析 :
AIX 环境:
多块读仅仅等待了
694
次,每次
11
毫秒。
Linux环境:
多块读等待了 98921 次,单次等待 9 毫秒 。
现场真实执行一次
在 AIX 和 Linux 环境, 同时对 TAB1 表执行 COUNT(*) 查询,观察ASH视图。
Linux 环境:
首先查询到此次执行的 SQL_EXEC_ID 。 11 g 引入该字段真的是太好用了,标记出每个连接在执行相同的 SQL 语句时候的执行序号
AS H 默认 抓取间隔是 1 秒 ,该次执行 花费 了至少 943 秒
考虑到 db file scattered read 等待事件可能受到参数 db_file_multiblock_read_count 的影响,当数据存储不够连续时候,可能增加多块读等待次数。
该等待事件 P3 代表 BLOCKS , 其含义可以从 P3TEXT 列看出,为此次等待请求读取的数据块数目。
该次执行中, P3 的平均值为 31.96 ,接近主机参数 db_file_multiblock_read_count=32 ,可以判断出数据存储,基本是连续的。
AIX 环境:
查询到此次执行的 SQL_EXEC_ID, 继续查看该次执行等待多块读的次数
在AIX环境下没有进行一次多块读, 让我们看看等待事件是什么?
不对, AIX和 Linux 环境好像都开启了 EVENT 10949 ,不应该出现直接路径读 。
三、寻找规律
多块读的执行方式
在Oracle 11.2版本,对表或者索引的大小存在2个界限。
进行
全表扫描
(
Table Full Scan)
或者索引
快速全
扫描(
Index Fast Full Scan)
时候
,
会
将对象的大小
,和
STT
和
VLOT
进行对比
。所以
当表
或者
索引的大小超过
某个
阈值,
即使
设置
了
EVENT 10949
,
仍然
会
出现直接路径读
。
为了验证 Oracle 数据库 如何选择多块读的执行方式,我们开启的 NSMTIO 跟踪,从 Trace 文件 中可以看到 VLOT 的计算值 。
生成 的 Trace文件 示例如下 , 包含了 Object Size和 VLOT ,其单位都是 BLOCK 。
验证
_small_table_threshold
参数
这次 需要查询 Oracle 数据库 的隐藏参数, 可以建立 视图 方便 查询:
从 H$PARAMETER 视图的 DESCRIPTION 列 ,我们可以 得知参数信息 :
在
测试环境,
调整
SGA
大小,计算
STT
值:
计算公式如下 :
这里隐藏
参数
“
_db_block_buffers
”,
是
在数据库实例
启动时候
自动
生成的
。早期版本
ORACLE
数据库
通过“
db_block_buffers
”参数用来
调整
BufferCache
大小
的
参数,单位是
BLOCK
,在
ORACLE 9
时代
变成
隐藏
参数,
ORACLE
数据库内部的一些参数计算
仍然
可能使用到
。
验证
_very_large_object_threshold
参数
查询
H$PARAMETER视图,
参数描述
如下
,
默认值为
500
。
百度 一番 ,存在 下面 2种 说法:
1. VLOT 就是 5倍 的 Buffer Cache 大小 , 那么 这参数 存在 什么意义。
2. 单位为 MB,在当今 单表容量随便 过 TB 的 时代 , 500 MB的上限, 基本 是错误的 。
在测试环境,通过调整SGA的大小,开启跟踪测试VLOT计算值 :
通过计算得知,其单位应该为百分比 , 计算公式如下:
相
关参数_serial_direct_read
查询H$PARAMETER视图,该参数决定是否使用直接路径读,相当于总开关
参数_direct_read_decision_statistics_driven
查询H$PARAMETER视图,参数描述如下 :
ORACLE 采用表上统计信息来决定是否使用 DPR ,而不是 DBA_SEGMENTS 里面真实记录数。该参数在 ORACLE 11.2 .0.2 以后版本默认为 TRUE 。
所以直接修改表的统计信息,可以直接影响的DPR的选择
。
测试执行
DPR
规则
测试环境: ORACLE 11.2.0.4 + Linux
开启跟踪
建立测试表
隐藏参数查询视图
系统参数
计算各个阈值
收集统计信息
修改统计信息
测试结果汇总:
可以看到在
11.2
版本下,小于
SST
不走
DirectRead
,大于
VLOT
一定走
DirectRead
,介于
SST
和
VLOT
的表,需要考虑是否为本地表或者压缩表
MTT
在
11.2
版本已经淘汰。
DPR
算法总结
Oracle 11.2版本,全表扫描或者索引快速全扫描,是否走直接路径读,与STT和VLOT值有关
总结出执行规律:
参数验证
回到 案例中,为什么在 AIX环境下选择了直接路径读,而Linux环境选择 进入 Buffer Cache 缓存;
该SQL语句采用对索引PK_TAB1进行Index Fast Full Scan,这边我列举出2套环境各个参数的真实值,并且开启跟踪验证了VLOT计算值 ;
IX 环境 :索引 大小 94716MB > VLOT 大小 39920MB
Linux环境 :索引 大小 94632MB < VLOT大小160040MB
这下终于搞清楚真相了,因为Linux环境的Buffer Cache内存配置较大,小于VLOT大小,所以不执行Direct Path Read;而在AIX环境下,Buffer Cache内存配置较小,超过了VLOT大小,所以执行Direct Path Read 。
四、问题延伸
分区表如何计算
前面我们已经知道普通表或者索引的VLOT算法和DRP选择机制,那么如果是分区表,ORACLE怎么进行选择呢?
测试环境: ORACLE 11.2.0.4 + Linux
相关系统参数
计算各个阈值
收集统计信息
通过不断 的修改 表 的 统计信息, 进行测试验证
测试结果汇总 :
可以看出 DPR 的评估,不会考虑分区的格式,只是取整个分区表的统计信息
如果 将每个分区的 BLOCKS 修改到最大值,表级别的 BLOCK 修改为较小值, 会出现什么情况?
重复刚才的测试,发现其执行规则没有发生改变。分区级别的统计信息不会影响 DPR 的判断 。
索引快速全扫描如何计算
测试环境: ORACLE 11.2.0.4 + Linux;
建立测试表, 4 个 HASH 分区,建立普通索引;
修改索引的统计信息
再次查询索引统计信息
确认执行计划走上 IFFS
测试结果汇总:
可以看出DPR在评估IFFS时候不会考虑STT参数。超过VOLT大小,就走直接路径读,也就是说EVENT 10949 与索引快速全扫描无关 。
新版本改进
+
+
思考一个问题,为什么很多客户的ORACLE数据库中,EVENT 10949变成必调参数?
个人见解:理想情况下,OLTP系统中大于2% Buffer Cache的表,应该大部分会走索引扫描,偶尔一两次大表全表查询走直接路径读,这样可以让Buffer Cache中的内容保持稳定,提高Buffer Cache的命中率;
但是很多客户都遇到过,开发商没有建立合适的索引,导致SQL查询走上全表查询,同时该SQL执行较为频繁,没有Buffer Cache做缓冲,大量高并发的直接路径读很容易将一台存储压垮,导致业务系统出现严重的性能问题。
可是设置了10949一定有益吗?经常进行大表全表扫描,可能拉低的Buffer Cache的命中率,也会影响其他SQL语句的执行效率;并且全扫描的问题一直被忽视,不容易被发现。
除了对问题SQL进行优化,还有没有其他方法解决?在ORACLE 12.1.0.2 引入了Automatic Big Table Caching (ABTC)为功能,数据库将Buffer Cache中的一部分划分为大表缓存,并且统计哪些大表或者索引的热度,将其存放到ABTC中,避免了频繁的Direct Path Read。
+
+
ABTC测试
在 RAC 环境中启用 ABTC 前提条件是参数 parallel_degree_policy 设置为 AUTO 或 ADAPTIVE 。
在单机环境,不依赖 parallel_degree_policy 参数;
配置ABTC参数,同时需要确认force_full_db_caching是关闭的
配置参数db_big_table_cache_percent_target,为ABTC占Buffer Cache的比例,最大值为90
该 特性存在 2张相关视图:
视图v$bt_scan_cache统计ABTC的使用情况,里面MEMORY_BUF_ALLOC列显示消耗CACHE的大小
视图 v$bt_scan_obj_temp s存放 ABTC中对象信息 ,可以查询到ABTC中缓存表信息, TEMPERATURE 列 , 描述 对象的 热度。每执行一次全表扫描,TEMPERATURE列值加1000。
POLICY 列 , 显示对象在 ABTC中的状态 : MEM_ONLY 、 MEM_PART 、 DISK 、 INVALID
在大内存环境中,配置了ABTC后,当表大小超过STT时,不会执行直接路径读,而是进入ABTC中进行缓存,这样就可以节省很多物理IO 。
总结:
小型机迁移至X86平台是行业大趋势。迁移过程评估平台优缺点、性能差异、迁移方案、维护成本等因素;不仅需要全面的知识,更需要参考业内成功案例,不妨联系中亦科技,帮您达成目标!
