oracle select between and,oracle中的between和and的问题 | 学步园

一般而言,between和and的这种简单至极的东东是不会出错的,但是我还就试出了这个简单的东东的错误,暂且先这么叫,因为现在还不清楚oracle的内部实现机制,毕竟PL/SQL是第四代语言,怎么解析怎么编译怎么实现是oracle自己的事情。

背景:

一个表中有3000多万的数据需要迁移,以前的迁移脚本100W作为一个数据区间同步,相同的存储的过程就分了3000/100 = 30个,第一个存过的区间就写死成为BETWEEN 1 AND 1000000,第二个存过的区间就写死成为BETWEEN 1000001 AND 2000000,第3个第4个到第30都依此类推,稍微有点code常识的人看到这种代码都会悲从中来吧,提2个参数出来,能省多少活啊,大家一定要注意啊,不要只是简单的复制粘贴,这种代码写出来和只穿着三角裤上街没啥区别。

现在这种代码过了我手,我自然不能让这种东东继续丢人现眼,所以整了一下,提取了起始号和终止号作为入参,同样精简了另外2个同步700W数据和同步2000W数据的存过。

现在看起来就很美妙了,传参有更多的灵活性,重新测试700W和2000W数据的存过,发现一切OK,但是,注意,重点来了,在同步这个3000W数据的时候,我发现除了第一个[1,1000000]区间的存过能运行,其余的都hang那儿了,wait class 为 application,如果是I/Owait,还情有可原,但是application这种类型的wait,按照oracle给出的解释:

Waits resulting from user application code (for example, lock waits caused by row level locking or explicit lock commands)

可是我有给传参啊,所以可能就是行级锁了,出现行级锁,那就是可能有区间重合了,但是怎么可能重合呢,又仔细检查了存过,眼睛都看成斗鸡眼了,又请了几个同事帮忙看,还是没有发现有错误,再接着赋值测试,发现[1,1000000]和[1000001,2000000]果然有区间重合,在后者的区间居然把ID值为523456的找出来了,这个是怎么回事?又单独把sql语句拎出来查询,单独查询的就是好的,在[1000001,2000000]范围内...真是让人吐血啊,后来又修改表名,修改列的别名,修改表的别名一系列折腾,均告无果。

最后又怀疑是不是数据量太大导致溢出,于是又把3000W的表找了300W数据出来做测试,还是同样的问题,between and 越界,我现在已经非常非常想知道这个有参数的sql语句执行的时候到底是怎么回事了

SELECT M.ID,DECODE(M.TYPE,1,5,6) PORTSPEC,

M.NO CODE,M.MONIKERCODE AssembleCode,

M.PHYSTATUS,M.USESTATUS,M.SERVICESTATUS,

M.MDFPANELID,MP.COMMONMDFID,

1 CZLX, 'MDFCONNECTOR' NMSPEC,LS.ID syncid

FROM MDFCONNECTOR M,MDFPANEL MP,LRR_R3_MDFCONNECTOR LS

WHERE M.MDFPANELID = MP.ID

AND MP.CATEGORY IN (2,4)  --只有 2:横列,4:设备侧 下的端子同步到telant

AND M.TYPE IN(1,2)

AND M.ID = LS.NMID

AND LS.ISSYNC=2

AND LS.ID BETWEEN startNO

AND endNO

;

万幸的是新建的表由于没建索引,在执行的时候会锁一下,我总算能在sqlText中看oracle到底是怎么折腾这个sql语句的,如下:

SELECT M.ID,DECODE(M.TYPE,1,5,6) PORTSPEC,

M.NO CODE,M.MONIKERCODE AssembleCode,

M.PHYSTATUS,M.USESTATUS,M.SERVICESTATUS,

M.MDFPANELID,MP.COMMONMDFID,

1 CZLX, 'MDFCONNECTOR' NMSPEC,LS.ID syncid

FROM MDFCONNECTOR M,MDFPANEL MP,LRR_R3_MDFCONNECTOR LS

WHERE M.MDFPANELID = MP.ID

AND MP.CATEGORY IN (2,4)  --只有 2:横列,4:设备侧 下的端子同步到telant

AND M.TYPE IN(1,2)

AND M.ID = LS.NMID

AND LS.ISSYNC=2

AND LS.ID BETWEEN startNO

AND:B1

;

没错,我的2个参数,为毛只有1个参数了?starNO这个是要用1000001来代替的啊,应该是变量啊,而且更为诡异的是,这个语句丫居然不抛错,又把这个语句拎出去,把:B1替换为2000000执行了一下,居然能搜出值。但是单独找表 用select * from tablename where id between  startNO

and 2000000 来执行, 则会出错, 现在可以确认startNO

不是保留的数据了,难道是某一张表中的字段?果然,我的MDFPANEL表中有startNO字段,oracle随便找了这个字段中的第一值作为我的起始值了,所以所有的存过都是从相同的起始值开始的,行锁了.

这个问题现在就显得清晰,总结来说就是between and中有参数的话,要看这个参数名和表中的字段有没有重合的,如果重合了,以表列优先。

这个问题出现的偶然性很强,我个人觉得这种情况,oracle应该也抛出'有歧义'的错误,我不知道pl/sql的语法有没有详细阐述变量名和表列名的作用域谁大谁小的,今天花了一个下午解决这个问题,不想白白浪费,所以记之共享。

你可能感兴趣的:(oracle,select,between,and)