查看: 7554|回复: 29

[笔记] Oracle 10.2.0.4的bug?

[复制链接]
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
跳转到指定楼层
1#
发表于 2008-9-20 22:07 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Test Case:
+++++++++++++++++++++++++++++++++
CREATE TABLE TestCode
(
  ID   VARCHAR2(5),
  VAL  NUMBER(1)
);

select * from (
select rownum id, decode(sign(dbms_random.value-0.9),-1,0,1) val
from dual connect by rownum<=100
)
where  val>0;

insert into testcode select * from (
select rownum id, decode(sign(dbms_random.value-0.9),-1,0,1) val
from dual connect by rownum<=100
)
where  val>0;

select * from testcode;
+++++++++++++++++++++++++++++++++



运行一下,偶这里的情况是:

  1. SQL> select * from (
  2.   2  select rownum id, decode(sign(dbms_random.value-0.9),-1,0,1) val
  3.   3  from dual connect by rownum<=100
  4.   4  )
  5.   5  where  val>0;

  6.         ID        VAL
  7. ---------- ----------
  8.         30          1
  9.         40          1
  10.         54          1
  11.         75          1
  12.         91          1

  13. SQL> /

  14.         ID        VAL
  15. ---------- ----------
  16.          1          1
  17.          3          1
  18.          5          1
  19.         13          1
  20.         22          1
  21.         24          1
  22.         29          1
  23.         37          1
  24.         38          1
  25.         54          1
  26.         60          1

  27.         ID        VAL
  28. ---------- ----------
  29.         62          1
  30.         93          1
  31.         96          1

  32. 已选择14行。


  33. 插入到表中
  34. SQL> insert into testcode select * from (
  35.   2  select rownum id, decode(sign(dbms_random.value-0.9),-1,0,1) val
  36.   3  from dual connect by rownum<=100
  37.   4  )
  38.   5  where  val>0;

  39. 已创建6行。


  40. 查询一下看看
  41. SQL> select * from testcode;

  42. ID           VAL
  43. ----- ----------
  44. 18             0
  45. 21             0
  46. 22             0
  47. 33             0
  48. 60             0
  49. 94             0

  50. 已选择6行。
复制代码




VAL值有问题,插入到表中的数据,VAL值应该都是1才对


似乎问题和调用dbms_random有关
请看下面的测试例子

  1. SQL> select * from (select rownum+100 id, decode(sign(12-rownum),-1,1,0) val fro
  2. m dual connect by rownum<20) where val>0;

  3.         ID        VAL
  4. ---------- ----------
  5.        113          1
  6.        114          1
  7.        115          1
  8.        116          1
  9.        117          1
  10.        118          1
  11.        119          1

  12. 已选择7行。

  13. SQL>  insert into testcode select * from (select rownum+100 id, decode(sign(12-r
  14. ownum),-1,1,0) val from dual connect by rownum<20) where val>0;

  15. 已创建7行。

  16. SQL> select * from testcode;

  17. ID           VAL
  18. ----- ----------
  19. 18             0
  20. 21             0
  21. 22             0
  22. 33             0
  23. 60             0
  24. 94             0
  25. 113            1
  26. 114            1
  27. 115            1
  28. 116            1
  29. 117            1

  30. ID           VAL
  31. ----- ----------
  32. 118            1
  33. 119            1

  34. 已选择13行。
复制代码







系统环境:Windows XP SP2/Windows 2003 Server SP2下的Oracle10.2.0.4

[ 本帖最后由 lastwinner 于 2008-9-21 18:52 编辑 ]
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
2#
 楼主| 发表于 2008-9-20 22:12 | 只看该作者

使用道具 举报

回复
论坛徽章:
87
2015年新春福章
日期:2015-03-06 11:58:182010广州亚运会纪念徽章:轮滑
日期:2010-09-23 17:19:212010年世界杯参赛球队:乌拉圭
日期:2010-07-14 17:54:242010年世界杯参赛球队:美国
日期:2010-06-30 13:13:582010年世界杯参赛球队:墨西哥
日期:2010-06-25 12:49:452010年世界杯参赛球队:墨西哥
日期:2010-04-05 10:23:502010新春纪念徽章
日期:2010-03-01 11:06:232010新春纪念徽章
日期:2010-01-04 08:33:08生肖徽章2007版:龙
日期:2009-11-12 16:31:13参与WIN7挑战赛纪念
日期:2009-11-09 11:50:09
3#
发表于 2008-9-21 10:18 | 只看该作者
关注!

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
4#
 楼主| 发表于 2008-9-21 19:06 | 只看该作者
要是用 create table as ..........
就没事了


SQL> create table testcode2 as
  2  select * from (
  3  select rownum id, decode(sign(dbms_random.value-0.9),-1,0,1) val
  4  from dual connect by rownum<=100
  5  )
  6  where  val>0;

表已创建。

SQL> select * from testcode2;

        ID        VAL
---------- ----------
        13          1
        15          1
        23          1
        24          1
        54          1
        71          1
        83          1
        92          1
        96          1
        99          1

已选择10行。

使用道具 举报

回复
论坛徽章:
69
生肖徽章2007版:羊
日期:2008-11-14 14:42:19复活蛋
日期:2011-08-06 08:59:05ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:542012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20版主4段
日期:2012-05-15 15:24:11
5#
发表于 2008-9-21 21:49 | 只看该作者
自个电脑上暂时没装 10G, 明天到公司试试, 我觉得应该是 Oracle 优化器的BUG
对SQL的执行计划做了在某种极端条件下不等价的变换.

使用道具 举报

回复
论坛徽章:
69
生肖徽章2007版:羊
日期:2008-11-14 14:42:19复活蛋
日期:2011-08-06 08:59:05ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:542012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20版主4段
日期:2012-05-15 15:24:11
6#
发表于 2008-9-22 09:01 | 只看该作者
测试发现 insert 语句的结果中依然会包括 VAL=1 的结果, 请看:
SQL> set serverout on
SQL>
SQL> declare
  2    ln number;
  3    ln_cnt number;
  4  begin
  5    delete testcode;
  6    commit;
  7    for i in 1..20 loop
  8      insert into testcode
  9        select *
10          from (select rownum id,
11                       decode(sign(dbms_random.value - 0.9), -1, 0, 1) val
12                  from dual
13                connect by rownum <= 100)
14         where val > 0;
15      select count(0),sum(val) into ln_cnt,ln from testcode;
16      rollback;
17      if ln > 0 then
18        dbms_output.put_line('Total Lines:' || ln_cnt || '  Val=1: ' || ln || ' line(s)');
19      end if;
20    end loop;
21  end;
22  /

Total Lines:7  Val=1: 1 line(s)
Total Lines:11  Val=1: 2 line(s)
Total Lines:8  Val=1: 1 line(s)
Total Lines:10  Val=1: 1 line(s)
Total Lines:14  Val=1: 2 line(s)
Total Lines:14  Val=1: 1 line(s)
Total Lines:8  Val=1: 1 line(s)
Total Lines:11  Val=1: 2 line(s)
Total Lines:7  Val=1: 1 line(s)
Total Lines:10  Val=1: 1 line(s)
Total Lines:11  Val=1: 2 line(s)
Total Lines:10  Val=1: 1 line(s)

PL/SQL procedure successfully completed

使用道具 举报

回复
论坛徽章:
69
生肖徽章2007版:羊
日期:2008-11-14 14:42:19复活蛋
日期:2011-08-06 08:59:05ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:542012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20版主4段
日期:2012-05-15 15:24:11
7#
发表于 2008-9-22 09:04 | 只看该作者
这很大程度上说明, 在 INSERT 中的 where val > 0 的执行, 被替换成了 decode(sign(dbms_random.value - 0.9), -1, 0, 1) > 0
但是尚无证据表明, 不会使用 SQL Trace, 不知道这个能不能 Trace 出什么东东来.

使用道具 举报

回复
论坛徽章:
69
生肖徽章2007版:羊
日期:2008-11-14 14:42:19复活蛋
日期:2011-08-06 08:59:05ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:542012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20版主4段
日期:2012-05-15 15:24:11
8#
发表于 2008-9-22 09:08 | 只看该作者
根据INSERT的资料来看:
ID    VAL
----- ---
22      0
29      0
36      0
57      0
82      1
91      0

6 rows selected

从这个结果看: 基本上可以说明, 是 INSERT 语句中的 WHERE 筛选被改写为 decode(sign(dbms_random.value - 0.9), -1, 0, 1) > 0
导致的.

使用道具 举报

回复
论坛徽章:
69
生肖徽章2007版:羊
日期:2008-11-14 14:42:19复活蛋
日期:2011-08-06 08:59:05ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:542012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20版主4段
日期:2012-05-15 15:24:11
9#
发表于 2008-9-22 09:14 | 只看该作者
但是又不完全等价于将 where 条件直接改写. 直接改写后的执行结果中出现要么有100条记录, 要么一条也没有.

使用道具 举报

回复
论坛徽章:
69
生肖徽章2007版:羊
日期:2008-11-14 14:42:19复活蛋
日期:2011-08-06 08:59:05ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:542012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20版主4段
日期:2012-05-15 15:24:11
10#
发表于 2008-9-22 09:18 | 只看该作者
insert into testcode
  select *
    from (select level id,
                 decode(sign(dbms_random.value - 0.9), -1, 0, 1) val
            from dual
          connect by rownum <= 100)
   where val > 0;
此语句中的 where val > 0 被改写成了 decode(sign(dbms_random.value - 0.9), -1, 0, 1) > 0,
但是这个改写后的条件是以
(select level id,
                 decode(sign(dbms_random.value - 0.9), -1, 0, 1) val
            from dual
          connect by rownum <= 100)
结果集中的每一行记录都会执行一次 decode(sign(dbms_random.value - 0.9), -1, 0, 1) > 0 筛选.
如果直接将 where val > 0 改写成 decode(sign(dbms_random.value - 0.9), -1, 0, 1) > 0 的话, 那么这个 where 语句将只会执行一次.
难以琢磨, 呵呵...

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表