说明:这个例子转自老白的DBA日记
刚刚坐下,电话就响了,一个客户打过来的,说是碰到一个很奇怪的问题。 在一张上千万记录的大表里,做一个SELECT * FROM <TAB_NAME> WHERE ROWNUM<100,居然十多秒钟才出来。 我问他这张表是不是碎片很厉害,他所不可能有碎片,昨天才IMP进去的,昨天还没问题,今天就出问题了。 而且这张是话单表,不可能会做删除操作的,不会有碎片。 我让他马上做个10046发过来。
--相关知识点参考:
http://www.cndba.cn/Dave/article/1452
10分钟后,他通过QQ把TRACE发过来了: SELECT * FROM ttt where rownum<100
调用计数 CPU 已用磁盘查询当前行
------- ------ -------- ---------- -------------------- ---------- ----------
帕秒 1 0.14 0.17 44 198 0 0
执行 1 0.00 0.00 0 0 0 0
获取 8 3.71 5.86 67489 68340 0 99
------- ------ -------- -------------------- ---------- ---------- ----------
合计 10 3.85 6.03 67533 68538 0 99
从这上面看,确实产生了67533个物理读和68538个逻辑读。 执行时间为6.03秒。 从等待事件来看:
绑定 #39:
EXEC #39:c=0,e=88,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=1422207486718
等待 #39: nam='SQL*Net Message to client'ela= 7 driver id=1650815232 #bytes=1 p3=0 obj#=206418 tim=1422207486810
等待 #39: nam='SQL*将更多数据 net 到 client'ela= 203 驱动程序 id=1650815232 #bytes=2002 p3=0 obj#=206418 tim=1422207487071
等待 #39: nam='SQL*将更多数据 net 到 client'ela= 66 驱动程序 id=1650815232 #bytes=2020 p3=0 obj#=206418 tim=1422207487175
等待 #39: nam='db 文件分散读取' ela=515 文件#=146 块#=92900 块=5 obj#=206418 tim=1422207488208
等待 #39: nam='db 文件分散读取' ela=918 文件#=146 块#=92905 块=8 obj#=206418 tim=1422207489579
等待 #39: nam='db 文件分散读取' ela=2121 文件#=146 块#=92914 块=7 obj#=206418 tim=1422207492091
等待 #39: nam='db 文件分散读取' ela=617 文件#=146 块#=92921 块=8 obj#=206418 tim=1422207493135
等待 #39: nam='db 文件分散读取' ela=493 文件#=146 块#=92930 块=7 obj#=206418 tim=1422207494016
等待 #39: nam='db 文件分散读取' ela=1666 文件#=147 块#=897417 块=8 obj#=206418 tim=1422207496049
等待 #39: nam='db 文件分散读取' ela=1026 文件#=147 块#=897426 块=7 obj#=206418 tim=1422207497350
等待 #39: nam='db 文件分散读取' ela=378 文件#=147 块#=897433 块=8 obj#=206418 tim=1422207498049
等待 #39: nam='db 文件分散读取' ela=1075 文件#=147 块#=897442 块=7 obj#=206418 tim=1422207499416
等待 #39: nam='db 文件分散读取' ela=1649 文件#=147 块#=897449 块=3 obj#=206418 tim=1422207501237
等待 #39: nam='db 文件分散读取' ela=2768 文件#=147 块#=897453 块=4 obj#=206418 tim=1422207504191
等待 #39: nam='db 文件分散读取' ela=653 文件#=147 块#=897458 块=7 obj#=206418 tim=1422207505141
等待 #39: nam='db 文件分散读取' ela=1588 文件#=147 块#=897465 块=8 obj#=206418 tim=1422207507029
等待 #39: nam='db 文件分散读取' ela=460 文件#=147 块#=897474 块=7 obj#=206418 tim=1422207507787
等待 #39: nam='db 文件分散读取' ela=608 文件#=147 块#=897481 块=8 obj#=206418 tim=1422207508697
等待 #39: nam='db 文件分散读取' ela=564 文件#=147 块#=897490 块=7 obj#=206418 tim=1422207509571
等待 #39: nam='db 文件分散读取' ela=832 文件#=147 块#=897497 块=8 obj#=206418 tim=1422207510668
等待 #39: nam='db 文件分散读取' ela=846 文件#=148 块#=102411 块=16 obj#=206418 tim=1422207512030
等待 #39: nam='db 文件分散读取' ela=4872 文件#=148 块#=102427 块=16 obj#=206418 tim=1422207517488
等待 #39: nam='db 文件分散读取' ela=1624 文件#=148 块#=102443 块=16 obj#=206418 tim=1422207520062
确实存在大量的DB FILE SCATTERD READ。 这更加坚信了我的观点,表里存在大量的碎片。 找第一个SCATTERD READ的参数 file#=146 block#=92900,让客户执行alter system dump datafile 146 block min 92900 block max 92904。
--相关知识点参考:
Oracledatafile block 格式 说明
http://www.cndba.cn/Dave/article/1375
获得的结果如下:
data_block_dump,数据标头 at0x6000000000208e64
===============
tsiz: 0x1f98
hsiz: 0x4c
pbl: 0x6000000000208e64
bdba: 0x24816ae4 76543210
标志 = --------
ntab=1
nrow=29
frre=0
fsbo=0x4c
fseo=0xf7
avsp=0x1f4c
拓扑=0x1f4c
0xe:pti[0] nrow=29 offs=0
0x12:pri[0] sfll=1
0x14:pri[1] sfll=2
0x16:pri[2] sfll=3
0x18:pri[3] sfll=4
0x1a:pri[4] sfll=5
0x1c:pri[5] sfll=6
0x1e:pri[6] sfll=7
0x20:pri[7] sfll=8
0x22:pri[8] sfll=9
0x24:pri[9] sfll=10
0x26:pri[10] sfll=11
0x28:pri[11] sfll=12
0x2a:pri[12] sfll=13
0x2c:pri[13] sfll=14
0x2e:pri[14] sfll=15
0x30:pri[15] sfll=16
0x32:pri[16] sfll=17
0x34:pri[17] sfll=18
0x36:pri[18] sfll=19
0x38:pri[19] sfll=20
0x3a:pri[20] sfll=21
0x3c:pri[21] sfll=22
0x3e:pri[22] sfll=23
0x40:pri[23] sfll=24
0x42:pri[24] sfll=25
0x44:pri[25] sfll=26
0x46:pri[26] sfll=27
0x48:pri[27] sfll=28
0x4a:pri[28] sfll=-1
block_row_dump:
end_of_block_dump
里面全部是空块。 建议客户做一个ALTER TABLE <table> MOVE; 表重组后,发现原来12G的表只剩下800M了。 再执行这个SQL,只有12个BUFFER GET了:
统计学
----------------------------------------------------------
1 个递归调用
0 db 块获取
12 个一致
1 物理读取
0 重做大小
18921 字节通过 SQL*Net 发送到客户端
从客户端通过 SQL*Net 接收 558 字节
8 个 SQL*往返客户端的净往返
老白的这个小例子很简单,但是从这个例子里可以看到优化的一个流程。 遇到SQL 的问题,可以做10046 事件,获取详细的信息,通过trace,分析原因,找到原因后,就可以解决问题,这里发现是碎片的问题,通过Move table 后,表从原来的12G 变成了800M,解决了碎片的问题,SQL 的性能得到提高。
-------------------------------------------------------------------------------------------------------
版权所有,文章允许转载,但必须以链接方式注明源地址,否则追究法律责任!