问题描述
考虑以下简单场景:
准备工作:
1) 假设我们有一个具有一个列名的表用户: 创建表用户 (名称varchar(100));
2) 让我们在那里放一些值:
插入用户 (名称) 值 ('user1');
插入用户 (名称) 值 ('user2');
插入用户 (名称) 值 ('user3');
插入用户 (名称) 值 ('user4');
插入用户 (名称) 值 ('user5');
插入用户 (名称) 值 ('user6');
插入用户 (名称) 值 ('user7');
插入用户 (名称) 值 ('user8');
插入用户 (名称) 值 ('user9');
插入用户 (名称) 值 ('user10');
插入用户 (名称) 值 ('user11');
插入用户 (名称) 值 ('user12');
...
高达10 000 000个值...
问题:
我使用的是旧的但有点 “标准” 的分页方式,没有结束,这里是 (0,5> 用户的分页示例:
选择 * 从 (选择名称,来自用户的ROWNUM r,其中rownum <= 5) 其中r> 0;
有些用户被退回,比方说:
名称R
用户1 1
用户2 2
用户3 3
用户4 4
用户5 5
但 “问题?” 发生时,我改变边界,让我们说 (0,8> 用户:
选择 * from (选择名称,来自用户的ROWNUM r,其中rownum <= 8) 其中r> 0;
名称R
用户3 1
用户4 2
用户5 3
用户6 4
用户7 5
用户8 6
用户9 7
用户10 8
如您所见,返回不同的用户,例如User1不会返回,即使它是在第一个查询中返回的。
这个问题不能用这样简单的数据集复制,但我用13百万行的集合复制。
(0,2 000 000> 的返回结果不包含在 (0,10 000 000) 的返回集中
问题:
正如你所看到的查询没有排序,所以基于定义的结果可以在任何排序,rownum只是剪切结果时谓词应用-所以从我的理解,它不是bug,但需要从你,专家的确认。假设Oracle optimiser只是决定对边界使用不同的执行方式 (0,2 000 000> 与边界为 (0,10 000 000>) 的情况相比,是否有效?如果是这样,唯一的方法是如何在某些排序上使用ROW_NUMBER来修复它,或者在任何rownum之前通过排序?
非常感谢你的回答。
注:
我正在使用Oracle 12.1.0.2。表没有主键。问题总是在一个环境中可以复制,而在具有相同数据,Oracle版本和补丁程序的另一个环境中永远不能复制...
准备工作:
1) 假设我们有一个具有一个列名的表用户: 创建表用户 (名称varchar(100));
2) 让我们在那里放一些值:
插入用户 (名称) 值 ('user1');
插入用户 (名称) 值 ('user2');
插入用户 (名称) 值 ('user3');
插入用户 (名称) 值 ('user4');
插入用户 (名称) 值 ('user5');
插入用户 (名称) 值 ('user6');
插入用户 (名称) 值 ('user7');
插入用户 (名称) 值 ('user8');
插入用户 (名称) 值 ('user9');
插入用户 (名称) 值 ('user10');
插入用户 (名称) 值 ('user11');
插入用户 (名称) 值 ('user12');
...
高达10 000 000个值...
问题:
我使用的是旧的但有点 “标准” 的分页方式,没有结束,这里是 (0,5> 用户的分页示例:
选择 * 从 (选择名称,来自用户的ROWNUM r,其中rownum <= 5) 其中r> 0;
有些用户被退回,比方说:
名称R
用户1 1
用户2 2
用户3 3
用户4 4
用户5 5
但 “问题?” 发生时,我改变边界,让我们说 (0,8> 用户:
选择 * from (选择名称,来自用户的ROWNUM r,其中rownum <= 8) 其中r> 0;
名称R
用户3 1
用户4 2
用户5 3
用户6 4
用户7 5
用户8 6
用户9 7
用户10 8
如您所见,返回不同的用户,例如User1不会返回,即使它是在第一个查询中返回的。
这个问题不能用这样简单的数据集复制,但我用13百万行的集合复制。
(0,2 000 000> 的返回结果不包含在 (0,10 000 000) 的返回集中
问题:
正如你所看到的查询没有排序,所以基于定义的结果可以在任何排序,rownum只是剪切结果时谓词应用-所以从我的理解,它不是bug,但需要从你,专家的确认。假设Oracle optimiser只是决定对边界使用不同的执行方式 (0,2 000 000> 与边界为 (0,10 000 000>) 的情况相比,是否有效?如果是这样,唯一的方法是如何在某些排序上使用ROW_NUMBER来修复它,或者在任何rownum之前通过排序?
非常感谢你的回答。
注:
我正在使用Oracle 12.1.0.2。表没有主键。问题总是在一个环境中可以复制,而在具有相同数据,Oracle版本和补丁程序的另一个环境中永远不能复制...
专家解答
是的 .... 没有某种排序子句 (row_number,或order by等),你可以安全地假设rownum给你一个 “伪随机” 的行集。
仅指定行数请求的rownum就会影响优化器,例如
即使没有索引等,在一个简单的普通堆表上,从 * just * rownum查询回来的行基本上是在如何执行和调度操作系统的突发奇想,以及在插入行的时候发生了什么。下一个删除/插入可以移动行。因此,“随机”,因为rownum并不是真正的列-它是一个计数器: “我得到了符合我的标准的行,很酷,将1添加到rownum。”
这就是为什么
从表中选择 *,其中rownum = 2
永远不会有结果。它变成:
-我们吵了一架,
-它 “潜在” 的行数为1。
-等于2吗?
-不,拿到下一行
-它 “潜在” 的行数为1。
-等于2吗?
-它 “潜在” 的行数为1。
-等于2吗?
等等
仅指定行数请求的rownum就会影响优化器,例如
SQL> create table t as 2 select mod(rownum,2) col, d.* from dba_objects d; Table created. SQL> SQL> create index ix on t ( col ); Index created. SQL> SQL> set autotrace traceonly explain SQL> select * from t where col = 0 and rownum <= 1; Execution Plan ---------------------------------------------------------- Plan hash value: 658510075 --------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 135 | 2 (0)| 00:00:01 | |* 1 | COUNT STOPKEY | | | | | | | 2 | TABLE ACCESS BY INDEX ROWID BATCHED| T | 1 | 135 | 2 (0)| 00:00:01 | |* 3 | INDEX RANGE SCAN | IX | | | 1 (0)| 00:00:01 | --------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(ROWNUM<=1) 3 - access("COL"=0) SQL> select * from t where col = 0 and rownum <= 100000; Execution Plan ---------------------------------------------------------- Plan hash value: 508354683 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 39201 | 5168K| 432 (1)| 00:00:01 | |* 1 | COUNT STOPKEY | | | | | | |* 2 | TABLE ACCESS FULL| T | 39201 | 5168K| 432 (1)| 00:00:01 | --------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(ROWNUM<=100000) 2 - filter("COL"=0)复制
即使没有索引等,在一个简单的普通堆表上,从 * just * rownum查询回来的行基本上是在如何执行和调度操作系统的突发奇想,以及在插入行的时候发生了什么。下一个删除/插入可以移动行。因此,“随机”,因为rownum并不是真正的列-它是一个计数器: “我得到了符合我的标准的行,很酷,将1添加到rownum。”
这就是为什么
从表中选择 *,其中rownum = 2
永远不会有结果。它变成:
-我们吵了一架,
-它 “潜在” 的行数为1。
-等于2吗?
-不,拿到下一行
-它 “潜在” 的行数为1。
-等于2吗?
-它 “潜在” 的行数为1。
-等于2吗?
等等
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。
评论
相关阅读
Oracle DataGuard高可用性解决方案详解
孙莹
509次阅读
2025-03-26 23:27:33
Oracle RAC 一键安装翻车?手把手教你如何排错!
Lucifer三思而后行
492次阅读
2025-04-15 17:24:06
墨天轮个人数说知识点合集
JiekeXu
406次阅读
2025-04-01 15:56:03
XTTS跨版本迁移升级方案(11g to 19c RAC for Linux)
zwtian
403次阅读
2025-04-08 09:12:48
Oracle SQL 执行计划分析与优化指南
Digital Observer
384次阅读
2025-04-01 11:08:44
【纯干货】Oracle 19C RU 19.27 发布,如何快速升级和安装?
Lucifer三思而后行
379次阅读
2025-04-18 14:18:38
Oracle 19c RAC更换IP实战,运维必看!
szrsu
348次阅读
2025-04-08 23:57:08
oracle定时任务常用攻略
virvle
318次阅读
2025-03-25 16:05:19
3月“墨力原创作者计划”获奖名单公布
墨天轮编辑部
317次阅读
2025-04-15 14:48:05
Oracle数据库一键巡检并生成HTML结果,免费脚本速来下载!
陈举超
313次阅读
2025-04-20 10:07:02