跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

Oracle读取事件的命名理由

db file sequential read与db file scattered read这两个等待事件在今天又让我们重温了一下2年前的一次争论, 大家对于这两个事件以及其名称的理解进行了多个角度的解读, 我觉得我有责任将Jeff Holt在多年前的这篇旧文翻译出来, 以助后来者理解这两个让人迷惑 db file sequential read与db file scattered read这两个等待事件在今天又让我们重温了一下2年前的一次争论, 大家对于这两个事件以及其名称的理解进行了多个角度的解读, 我觉得我有责任将Jeff Holt在多年前的这篇旧文翻译出来, 以助后来者理解这两个让人迷惑的概念. 翻译的比较仓促, 不足之处尽情谅解 Why are Oracle’s Read Events Named Backwards? 原文版权归Jeff Holt以及Hotsos公司所有. 为什么Oracle的读取事件使用”向后兼容的命名方式”? By Jeff Holt Translated by Jametong 在几乎所有的 oracle 跟踪文件中,都有两个出现频繁的事件: db file sequential read 与 db file scattered read .这些事件表明oracle内核请求从磁盘读取数据块. 当我们想到磁盘时,我们熟悉的 顺序访问(sequential read) 的概念是,一个进程从磁盘读取大块的连续数据.当Oracle执行一次全表扫描时,会在一次大I/O中读取多个Oracle数据块的数据,它是一次顺序读取.当然,在我们想到磁盘时,也会习惯于 随机访问(random access) 这个概念. 在一个有合理设计的索引的查询中,SQL 语句通常会使用随机访问来完成单块读取(single block read)调用. 然而,如果你曾经读过任何关于Oracle等待事件的内容,都会发现 db file sequential read 是用来表示随机读取(例如,索引扫描), db file scattered read 是用来表示顺序读取(例如,全表扫描). Oracle使用这个术语表示确实不是很直观. 这使得部分猜测Oracle的事件命名是一种不经意的向后兼容命名. 嗯,这个理论很有意思,不过事实不是这样. 这些事件之所以如此命名确实有个很好的理由. 事件名db file sequential read与db file scattered read描述的是如何将数据块存储到内存中的,而不是如何从磁盘进行读取 . Oracle对这两个事件的命名类似于Unix对两类读取调用的命名,函数read()与readv()是其中的代表. Unix的read()函数读取文件中的一段连续的内容,并将数据的不同片段存储到不同的内存区域,此区域由一个内存应用数组所支配. 由类似于read()调用执行的Oracle磁盘读被记录为 db file sequential read 事件,由类似于readv()调用执行的磁盘读被记录为 db file scattered read 事件. 如果填充磁盘读取的内容的内存是连续的,发生的磁盘读就是db file sequential read. Oracle 为所有的单块读取生成 db file sequential read 事件.Oracle始终将单个数据块存储在单个缓存缓冲块(cache buffer)中,因此单块读取永远不会产生 db file scattered read 事件. 在Oracle 7.3以及后期版本中,当一个独占进程从磁盘中读取临时段时,Oracle会产生多块(multi-block) db file sequential read 事件. Oracle早期版本会使用db file scattered read读取临时段的数据到数据库的高速缓冲池. 更新的版本发现临时段的数据几乎无法被共享或被重新访问到,因此就将其直接读取到服务器进程的程序全局区( PGA, Program Global Area )中了. 当填充从磁盘读取的数据的内存的连续性无法被保证的时候,发生的磁盘读就是db file scattered read. 为了填充一次read()调用读取的数据,Oracle内核可能要花费更多的时间来寻找一组连续的内存.只有当read()调用于readv()调用相对readv()调用的速度优势足够抵消这部分额外的时间消耗时,使用这种方式才会有净收益. 找到连续缓冲块(buffer)的代价可能远远超过read()调用相对于readv()调用带来的好处,推动Oracle的内核开发者选择了他们现在使用的这种算法. oracle知识库 oracle知识库下载 下载 在大部分情况下,全表扫描与快速全索引扫描都会产生一次或多次db file scattered read. 不过,有时,这些扫描只会产生db file sequential read. 例如: 从一个Oracle跟踪文件摘录的如下片段显示,一个全表扫描仅仅使用到了 db file sequential read . 这个表存储在文件2的块2到20的连续块中,它的高水位线在第16个块上. 数据库的块大小(block size)是8KB. 由于在此查询执行之前,所有的偶数块都已经存在于数据库高速缓冲池(buffer cache)中,这次扫描的读操作全都是单块读取.
01
PARSING
IN
CURSOR
#1 len=31 dep=0 uid=18 oct=3 lid=18 tim=26532087 hv=2854987545 ad=
'82061e04'
02
select
count
(1)
from
test_tab
03
END
OF
STMT
04
PARSE #1:c=0,e=0,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=4,tim=26532087
05
EXEC
#1:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4,tim=26532087
06
WAIT #1: nam=
'db file sequential read'
ela= 0 p1=2 p2=3 p3=1
07
WAIT #1: nam=
'db file sequential read'
ela= 0 p1=2 p2=5 p3=1
08
WAIT #1: nam=
'db file sequential read'
ela= 0 p1=2 p2=7 p3=1
09
WAIT #1: nam=
'db file sequential read'
ela= 0 p1=2 p2=9 p3=1
10
WAIT #1: nam=
'db file sequential read'
ela= 0 p1=2 p2=11 p3=1
11
WAIT #1: nam=
'db file sequential read'
ela= 0 p1=2 p2=13 p3=1
12
WAIT #1: nam=
'db file sequential read'
ela= 0 p1=2 p2=15 p3=1
13
FETCH
#1:c=1,e=1,p=7,cr=14,cu=3,mis=0,r=1,dep=0,og=4,tim=26532088
下面这些来自Solaris truss 命令的输出结果展示了这个查询执行的系统调用.第23行到27行展示了文件是如何打开,以及如何以文件句柄409进行引用的.第31行显示了一次 pread ()系统函数的调用,除了不会与 read ()一样移动文件指针外, pread ()的行为与 read ()完全一致,它接收文件偏移量作为它的第四个参数.它的返回值是成功读取的字节的大小. 由于 timed_statistices 实例参数为true, times ()调用提供了计时信息.
01
*** SUID: ruid/euid/suid = 4076 / 108 / 108 ***
02
read
(10, 0x010ACACE, 2064)  (sleeping...)
03
read
(10,
"\097\0\006\0\0\0\0\003 ^"
.., 2064) = 151
04
times(0xEFFFE360)   = 162380015
05
times(0xEFFFDA80)   = 162380015
06
times(0xEFFFD9C0)   = 162380015
07
times(0xEFFFD9C0)   = 162380015
08
time
()  = 948902570
09
brk(0x010E9A60) = 0
10
brk(0x010EBA60) = 0
11
brk(0x010EBA60) = 0
12
brk(0x010EDA60) = 0
13
times(0xEFFFD9C0)   = 162380015
14
times(0xEFFFD9C0)   = 162380015
15
times(0xEFFFC4A0)   = 162380015
16
times(0xEFFFC4A0)   = 162380015
17
time
()  = 948902570
18
times(0xEFFFD7A8)   = 162380015
19
times(0xEFFFD760)   = 162380015
20
times(0xEFFFC5D8)   = 162380015
21
times(0xEFFFC578)   = 162380015
22
times(0xEFFFBE90)   = 162380015
23
open64(
"/home/jeffh/test/data/tools01.dbf"
, O_RDWR|O_DSYNC) = 15
24
getrlimit(RLIMIT_NOFILE, 0xEFFFBE98)    = 0
25
fstat64(409, 0xEFFFBE00)    Err#9 EBADF
26
fcntl(15, F_DUP2FD, 0x00000199) = 409
27
close
(15)   = 0
28
fcntl(409, F_SETFD, 0x00000001) = 0
29
ioctl(409, 0x0403, 0xEFFFBE5C)  Err#25 ENOTTY
30
times(0xEFFFBE48)   = 162380016
31
pread(409,
"0602\0\0\080\003\0\0 + B"
.., 8192, 24576) = 8192
32
times(0xEFFFC530)   = 162380016
33
times(0xEFFFC5D8)   = 162380016
34
times(0xEFFFC5D8)   = 162380016
35
times(0xEFFFC5D8)   = 162380016
36
times(0xEFFFC578)   = 162380016
37
pread(409,
"0602\0\0\080\005\0\0 + V"
.., 8192, 40960) = 8192
38
times(0xEFFFC530)   = 162380016
39
times(0xEFFFC5D8)   = 162380016
40
times(0xEFFFC5D8)   = 162380016
41
times(0xEFFFC5D8)   = 162380016
42
times(0xEFFFC578)   = 162380016
43
pread(409,
"0602\0\0\080\007\0\0 + V"
.., 8192, 57344) = 8192
44
times(0xEFFFC530)   = 162380016
45
times(0xEFFFC5D8)   = 162380016
46
times(0xEFFFC5D8)   = 162380016
47
times(0xEFFFC5D8)   = 162380016
48
times(0xEFFFC578)   = 162380016
49
pread(409,
"0602\0\0\080\0\t\0\0 + V"
.., 8192, 73728) = 8192
50
times(0xEFFFC530)   = 162380016
51
times(0xEFFFC5D8)   = 162380016
52
times(0xEFFFC5D8)   = 162380016
53
times(0xEFFFC5D8)   = 162380016
54
times(0xEFFFC578)   = 162380016
55
pread(409,
"0602\0\0\080\0\v\0\0 + V"
.., 8192, 90112) = 8192
56
times(0xEFFFC530)   = 162380016
57
times(0xEFFFC5D8)   = 162380016
58
times(0xEFFFC5D8)   = 162380016
59
times(0xEFFFC5D8)   = 162380016
60
times(0xEFFFC578)   = 162380016
61
pread(409,
"0602\0\0\080\0\r\0\0 + V"
.., 8192, 106496) = 8192
62
times(0xEFFFC530)   = 162380016
63
times(0xEFFFC5D8)   = 162380016
64
times(0xEFFFC5D8)   = 162380016
65
times(0xEFFFC5D8)   = 162380017
66
times(0xEFFFC578)   = 162380017
67
pread(409,
"0602\0\0\080\00F\0\0 + V"
.., 8192, 122880) = 8192
68
times(0xEFFFC530)   = 162380017
69
times(0xEFFFC5D8)   = 162380017
70
times(0xEFFFC5D8)   = 162380017
71
times(0xEFFFDB40)   = 162380017
72
times(0xEFFFE3A8)   = 162380017
73
write(13,
"\0B0\0\006\0\0\0\0\010\0"
.., 176) = 176
74
read
(10,
"\0 y\0\006\0\0\0\0\003 ^"
.., 2064) = 121
75
times(0xEFFFE360)   = 162380017
76
times(0xEFFFDA80)   = 162380017
77
times(0xEFFFDB40)   = 162380017
78
times(0xEFFFE3A8)   = 162380017
79
times(0xEFFFE360)   = 162380017
80
lseek(14, 37376, SEEK_SET)  = 37376
81
read
(14,
"\0\v04E2\0\0\0 J04E3\0\0"
.., 512) = 512
82
times(0xEFFFE3A8)   = 162380017
83
write(13,
"\0 U\0\006\0\0\0\0\004\0"
.., 85) = 85
84
read
(10, 0x010ACACE, 2064)  (sleeping...)
下表描述了Oracle产生 db file sequential read 与 db file scattered read 事件的相关情况. Oracle 事件产生单块读取事件的操作(p3=1)产生多块读取事件的操作(p3>1)db file sequential read索引扫描,在区间内跳过块进行读取的全表扫描,根据rowid进行的表访问等临时段读取db file scattered read绝对不会全表扫描,快速全索引扫描等. 引用: HOLT, JEFF. 2000. “Predicting Multi-Block Read Call Sizes,” Hotsos Journal, (Jan. 2000): 8–9. http://www.hotsos.com. Jeff Holt是位于得克萨斯州盐湖城的Hotsos LLC公司的一位系统性能优化专家. No related posts.

相关文章