先抛出一个问题:

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

最新文章

  1. CString用法小结《转载》
  2. 表单验证 jQuery Validate
  3. IOS时间戳
  4. A script job for rebuild DB in AX 2012
  5. 图文教程:手把手教你用U盘安装Ubuntu
  6. Phpcms v9系统类库与函数库调用方法
  7. css 中文字体 unicode 对照表
  8. 解决Timer回调方法重复调用的问题
  9. android中Imageview的布局和使用
  10. Redis作为lru缓存作用
  11. python类中的内置函数
  12. PHPCMS9.6.0最新版SQL注入和前台GETSHELL漏洞分析 (实验新课)
  13. Java EE业务处理流程与XML的引入
  14. LSTM CNN GRU DGA比较
  15. Google Android API官网封杀了,没法查android技术资料的3种解决方式
  16. ajax的历史
  17. linux 相关命令
  18. oracle,sqlserver,mysql常见数据库jdbc连接
  19. 摘:常用函数(包括:宽字符函数、普通C函数 )
  20. Python入妖4-----Request库的基本使用

热门文章

  1. Python 简单批量请求接口实例
  2. git提交项目到已有库
  3. 如何有效使用Project(1)&mdash;&mdash;编制进度计划、保存基准
  4. 性能:Output层面
  5. springboot 打成的jar包在ClassLoader().getResource方法读取文件为null
  6. python - django 实现文件下载功能
  7. 洛谷 P1250 种树 题解
  8. BZOJ 1034: [ZJOI2008]泡泡堂BNB 贪心+排序
  9. LibreOJ #517. 「LibreOJ β Round #2」计算几何瞎暴力
  10. 守护进程daemon.c