[转帖]Oracle提示的优先级最高?—次坏块处理的详细记录_MySQL, Oracle及数据库讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  MySQL, Oracle及数据库讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 4555 | 回复: 0   主题: [转帖]Oracle提示的优先级最高?—次坏块处理的详细记录        下一篇 
kim
注册用户
等级:中校
经验:1729
发帖:222
精华:0
注册:2011-7-21
状态:离线
发送短消息息给kim 加好友    发送短消息息给kim 发消息
发表于: IP:您无权察看 2011-9-21 7:46:45 | [全部帖] [楼主帖] 楼主

所有的ORACLE文档在提到HINT时,都会指出,HINT的优先级最高。但是今天却发现了意外情况。

今天开发人员报告测试库出现一个错误:

ORA-01578: ORACLE data block corrupted (file # 39, block # 24961)
ORA-01110: data file 39: '/oracle/oradata/test/ndmain09.dbf'


由于是测试库,因此没有做热备。测试库中的数据本身并不很重要,丢失一个BLOCK的数据是可以接受的。所以打算直接丢弃坏块中的数据。

由于没有必要尝试修复数据,没有必要使用DBMS_REPAIR包,利用设置EVENT导出的方式又相对比较麻烦,打算采用最简单的利用ROWID绕过坏块的方式来重建表。

首先,找到有问题的表:

SQL> SELECT SEGMENT_TYPE, OWNER, SEGMENT_NAME FROM DBA_EXTENTS
2 WHERE FILE_ID = 39
3 AND 24961 BETWEEN BLOCK_ID AND BLOCK_ID+BLOCKS -1
4 ;
SEGMENT_TYPE OWNER SEGMENT_NAME
------------------ ------------------------------ ------------------------------
TABLE DATA CAT_ZONE_PRODUCT


下面构造坏块的ROWID:

SQL> CONN DATA
Enter password:
Connected.
SQL> SELECT DATA_OBJECT_ID FROM USER_OBJECTS WHERE OBJECT_NAME = 'CAT_ZONE_PRODUCT';
DATA_OBJECT_ID
--------------
54649
SQL> SELECT DBMS_ROWID.ROWID_CREATE(1, 54649, 39, 24961, 0) FROM DUAL;
DBMS_ROWID.ROWID_C
------------------
AAANV5AAnAAAGGBAAA


我们已经找到坏块的ROWID了,下面只需要将除了这个BLOCK以外的数据读出来就可以了:

SQL> CREATE TABLE CAT_ZONE_PRODUCT_BAK AS
2 SELECT /*+ ROWID(CAT_ZONE_PRODUCT) */ * FROM CAT_ZONE_PRODUCT
3 WHERE ROWID < CHARTOROWID('AAANV5AAnAAAGGBAAA')
4 OR ROWID >= CHARTOROWID('AAANV5AAnAAAGGCAAA')
5 ;
CREATE TABLE CAT_ZONE_PRODUCT_BAK AS
*
ERROR at line 1:
ORA-01578: ORACLE data block corrupted (file # 39, block # 24961)
ORA-01110: data file 39: '/oracle/oradata/test/ndmain09.dbf'


奇怪,明明已经通过提示告诉Oracle跳过坏块了,怎么还报这个错误呢?看看执行计划吧:

SQL> EXPLAIN PLAN FOR
2 SELECT /*+ ROWID(CAT_ZONE_PRODUCT) */ * FROM CAT_ZONE_PRODUCT
3 WHERE ROWID < CHARTOROWID('AAANV5AAnAAAGGBAAA')
4 OR ROWID >= CHARTOROWID('AAANV5AAnAAAGGCAAA')
5 ;
Explained.
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY());
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------
--------------------------------------------------------------------------
Id Operation Name Rows Bytes Cost
--------------------------------------------------------------------------
0 SELECT STATEMENT 164K 1175M 1985
1 TABLE ACCESS FULL CAT_ZONE_PRODUCT 164K 1175M 1985
--------------------------------------------------------------------------
Note: cpu costing is off, PLAN_TABLE' is old version
9 rows selected.
SQL> ALTER SESSION SET OPTIMIZER_MODE = FIRST_ROWS;
Session altered.
SQL> EXPLAIN PLAN FOR
2 SELECT /*+ ROWID(CAT_ZONE_PRODUCT) */ * FROM CAT_ZONE_PRODUCT
3 WHERE ROWID < CHARTOROWID('AAANV5AAnAAAGGBAAA')
4 OR ROWID >= CHARTOROWID('AAANV5AAnAAAGGCAAA')
5 ;
Explained.
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY());
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------
--------------------------------------------------------------------------
Id Operation Name Rows Bytes Cost
--------------------------------------------------------------------------
0 SELECT STATEMENT 164K 1175M 1985
1 TABLE ACCESS FULL CAT_ZONE_PRODUCT 164K 1175M 1985
--------------------------------------------------------------------------
Note: cpu costing is off, PLAN_TABLE' is old version
9 rows selected.
SQL> ALTER SESSION SET OPTIMIZER_MODE = CHOOSE;
Session altered.


看来HINT没有起左右,可是从语法上看是没有任何问题的。难道是or的问题:

SQL> EXPLAIN PLAN FOR
2 SELECT /*+ ROWID(CAT_ZONE_PRODUCT) */ * FROM CAT_ZONE_PRODUCT
3 WHERE ROWID < CHARTOROWID('AAANV5AAnAAAGGBAAA')
4 ;
Explained.
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY());
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
Id Operation Name Rows Bytes Cost
------------------------------------------------------------------------------
0 SELECT STATEMENT 84208 602M 1985
1 TABLE ACCESS BY ROWID RANGE CAT_ZONE_PRODUCT 84208 602M 1985
-------------------------------------------------------------------------------
Note: cpu costing is off, PLAN_TABLE' is old version
9 rows selected.


这回结果对了,看来果然是or出的问题,不过既然HINT的优先级最高,为什么加上一个OR的条件,就导致Oracle的执行计划改变了呢,看来不是HINT优先级最高是有疑问的,就是这里出现了bug。

问题找到了,剩下的就简单了,将查询语句简单变形,再次执行:

SQL> CREATE TABLE CAT_ZONE_PRODUCT_BAK AS
2 SELECT /*+ ROWID(CAT_ZONE_PRODUCT) */ * FROM CAT_ZONE_PRODUCT
3 WHERE ROWID < CHARTOROWID('AAANV5AAnAAAGGBAAA')
4 UNION ALL
5 SELECT /*+ ROWID(CAT_ZONE_PRODUCT) */ * FROM CAT_ZONE_PRODUCT
6 WHERE ROWID >= CHARTOROWID('AAANV5AAnAAAGGCAAA')
7 ;
Table created.
SQL> TRUNCATE TABLE CAT_ZONE_PRODUCT DROP STORAGE;
Table truncated.
SQL> INSERT INTO CAT_ZONE_PRODUCT SELECT * FROM CAT_ZONE_PRODUCT_BAK;
157186 rows created.
SQL> COMMIT;
Commit complete.




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论