当前位置:Gxlcms > 数据库问题 > Oracle ROWNUM的陷阱

Oracle ROWNUM的陷阱

时间:2021-07-01 10:21:17 帮助过:14人阅读

我们通过一个实验来说明一下。

 

创建一个具有百万条记录的表:

技术分享图片

 

使用mod(rownum,4)=1作谓词,计划更新全表1/4的记录

技术分享图片

这张表有百万条记录,但该SQL操作feedback的结果竟然是"1 row updated",只有1条记录被更新。开什么玩笑?

 

UPDATE不行,那我换成查询怎么样呢?

技术分享图片

仍然只有1条被查询到。那到底是什么原因导致了这个结果呢?为什么不是预期的1/4的记录呢?

 

这与ROWNUM伪列的实现机制有关。来看看Oracle官方是如何解释它的:

技术分享图片

ROWNUM是指从表或集合中返回某条记录的顺序值,它只对最终返回的记录进行分配,未返回的记录不予分配(返回即表示将结果呈现给客户端)

 

这句话实际上仍然没有把它说清楚。下面是我自己的理解:类似于rownum<10或mod(rownum,4)=1这样的谓词是属于FILTER(过滤型)谓词,这种谓词需要对侯选集合(例如全表扫描后的侯选集合)进行过滤得到最终结果。在进行过滤操作时,每fetch一条记录,根据当前的返回顺序值预分配ROWNUM,当这条记录通过FILTER过滤并返回给客户端,该ROWNUM才实际分配给该条记录,并使当前返回值+1;如果这条记录未能通过过滤条件,该记录被丢弃,当前的返回顺序值不变化。

 

现在,我们用上面这段描述来说明上述案例仅返回1条记录的原因。

  1. 首先通过T表的全表扫描得到了侯选集合(不一定就是全表扫描,只是本例是通过全表扫描方式得到侯选集合。如下图)

    技术分享图片

  2. 从侯选集合中fetch一条记录,预分配ROWNUM=1,此时mod(1,4)=1,符合FILTER条件(mod(rownum,4)=1),该记录返回,并将ROWNUM=1实际分配给该记录,当前ROWNUM变为2
  3. 从侯选集合中fetch下一条记录,预分配ROWNUM=2,此时mod(2,4)=2,不符合FILTER条件,该记录被丢弃,当前ROWNUM不变化
  4. 此后将一直重复步骤3,直至侯选集合被完全遍历。
  5. 最终只有1条记录被返回。

 

可以通过一个微调进一步验证上述过程。如果把SQL改为:

select count(*) from t where mod(rownum,4)=2;

会有多少条记录返回呢?

 

答案是:一条也没有。

技术分享图片

 

结论:

1、凡是涉及使用ROWNUM作为谓词条件的,一定要当心上述陷阱:凡是有可能使ROWNUM不能持续分配的操作、函数,均有可能导致类似现象。

Oracle ROWNUM的陷阱

标签:客户   9.png   需要   技术   过滤   进一步   记录   重复   feed   

人气教程排行