码迷,mamicode.com
首页 > 数据库 > 详细

Oracle ROWNUM的陷阱

时间:2018-01-09 20:11:27      阅读:201      评论:0      收藏:0      [点我收藏+]

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

先抛出一个问题:

 

我有一张表T,现在我想对表中1/4的记录作UPDATE操作,我的SQL如下:

Update t set col1=‘123‘ where mod(rownum,4)=1

我能够得到想要的结果吗?

 

答案是:不能。

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

 

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

技术分享图片

 

使用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   

原文地址:https://www.cnblogs.com/6yuhang/p/8253007.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!