暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle 当先前的获取停止重复值中间时返回的已获取行

ASKTOM 2019-06-07
384

问题描述

亲爱的团队,

我们有一个有点复杂的SQL,包括一个外部连接,我们在多次获取期间看到保留行顺序的问题。

SQL的结构如下。

SELECT
FROM
OUTER JOIN
ORDER BY ASC


ORDER BY在非键栏上。我们有duplicate values对于这个非键列。

当我们运行语句以获取从rownum 10到25的行时,重复值的集合按预期排序。
偏移0行仅获取前25行

当你运行语句时,你会得到前16行; 按预期工作。
偏移0行仅获取前16行


但是,当您运行相同的语句以获取接下来的50行时,some of the rows already listed in previous query is resulted which is not the expected outcome

偏移量17行仅获取前50行


Note that this happens only when the sorting column contains few duplicate values & the previous fetch stops at the middle of the duplicate values。


然而,当我们remove the outer join, this works as expected。 i。e。 50 rows from rownum 17 does not include items populated in previous step 1-16。 Row order is preserved in that case。

当涉及到外部连接存在的情况时,这可能是一个错误吗?
Expert advice is welcome here。

谢谢 & 致以最诚挚的问候,
纳文思

专家解答

在封面下,我们将 “提取/偏移” 子句重新映射到简单的排序函数,例如

SQL> select * from scott.emp
  2  或者der by ename
  3  offset 0 rows fetch first 10 rows only;

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7876 ADAMS      CLERK           7788 12-JAN-83       1100                    20
      7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300         30
      7698 BLAKE      MANAGER         7839 01-MAY-81       2850                    30
      7782 CLARK      MANAGER         7839 09-JUN-81       2450                    10
      7902 FORD       ANALYST         7566 03-DEC-81       3000                    20
      7900 JAMES      CLERK           7698 03-DEC-81        950                    30
      7566 琼斯      MANAGER         7839 02-APR-81       2975                    20
      7839 KING       PRESIDENT            17-NOV-81       5000                    10
      7654 MARTIN     SALESMAN        7698 28-SEP-81       1250       1400         30
      7934 MILLER     CLERK           7782 23-JAN-82       1300                    10

10 rows selected.

SQL> select * from dbms_xplan.display_curs或者();

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------
SQL_ID  5ujdsh6ztybn2, child number 0
-------------------------------------
select * from scott.emp 或者der by ename offset 0 rows fetch first 10
rows only

Plan hash value: 3291446077

---------------------------------------------------------------------------------
| Id  | Operation                | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT         |      |       |       |     4 (100)|          |
|*  1 |  VIEW                    |      |    10 |  1070 |     4  (25)| 00:00:01 |
|*  2 |   WINDOW SORT PUSHED RANK|      |    14 |   518 |     4  (25)| 00:00:01 |
|   3 |    TABLE ACCESS FULL     | EMP  |    14 |   518 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------------

Predicate Inf或者mation (identified by operation id):
---------------------------------------------------

   1 - filter(("from$_subquery$_002"."rowlimit_$$_rownumber"<=10 AND
              "from$_subquery$_002"."rowlimit_$$_rownumber">0))
   2 - filter(ROW_NUMBER() OVER ( ORDER BY "EMP"."ENAME")<=10)
复制


所以查询相当于

select *
from (
  select e.*, row_number() over ( 或者der by "emp"."ename" ) x
  from scott.emp e
)
where x between 0 and 10
复制


每当你有重复,然后分配 “row_number” 到这些重复是任意的,例如,如果我有enames:

棕色
琼斯
琼斯
琼斯
史密斯

然后根据执行计划,我可以得到 * 任何 * 以下排序:

棕色 1
琼斯 2
琼斯 3
琼斯 4
史密斯 5

或者

棕色 1
琼斯 4
琼斯 3
琼斯 2
史密斯 5

或者

棕色 1
琼斯 2
琼斯 4
琼斯 3
史密斯 5

etc etc...This is the same with *any* 或者der by clause by the way. The only way to ensure deterministic results is to 或者der by something that does not have duplicates. The easiest way is to use something unique as a tie-breaker, eg

SQL> select * from scott.emp
  2  或者der by ename, empno     <=== primary key added as tie-breaker
  3  offset 0 rows fetch first 10 rows only;
复制

文章转载自ASKTOM,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论