zoukankan      html  css  js  c++  java
  • 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条记录的原因。

    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不能持续分配的操作、函数,均有可能导致类似现象。

  • 相关阅读:
    绘图与滤镜全面解析
    排序算法——快速排序
    IOS QuartzCore核心动画框架
    const 笔记
    operation 多线程
    指针 总结
    问题 H: 老管家的忠诚(线段树)
    问题 H: 老管家的忠诚(线段树)
    Python——numpy(python programming)
    Python——numpy(python programming)
  • 原文地址:https://www.cnblogs.com/6yuhang/p/8253007.html
Copyright © 2011-2022 走看看