说明:这个例子转自老白的DBA日记

 

刚刚坐下,电话就响了,一个客户打过来的,说是碰到一个很奇怪的问题。 在一张上千万记录的大表里,做一个SELECT * FROM <TAB_NAME> WHERE ROWNUM<100,居然十多秒钟才出来。 我问他这张表是不是碎片很厉害,他所不可能有碎片,昨天才IMP进去的,昨天还没问题,今天就出问题了。 而且这张是话单表,不可能会做删除操作的,不会有碎片。 我让他马上做个10046发过来。

 

--相关知识点参考:

​OracleSQLTrace 和 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 的性能得到提高。

 

 

 

 

 

 

 

-------------------------------------------------------------------------------------------------------

版权所有,文章允许转载,但必须以链接方式注明源地址,否则追究法律责任!