欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

Oracle ROWNUM的陷阱

发布时间:2023/12/18 编程问答 55 豆豆
生活随笔 收集整理的这篇文章主要介绍了 Oracle ROWNUM的陷阱 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

先抛出一个问题:

 

我有一张表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条记录的原因。

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

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

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

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

    会有多少条记录返回呢?

     

    答案是:一条也没有。

     

    结论:

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

    转载于:https://www.cnblogs.com/6yuhang/p/8253007.html

    总结

    以上是生活随笔为你收集整理的Oracle ROWNUM的陷阱的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。