是否可以在不完全扫描的情况下执行跳过 N 行并获取 M 行

Mik*_*yev 2 oracle optimization oracle-11g row

假设我有这个查询:

SELECT EMP_ID,LAST_NAME FROM EMPLOYEES
   WHERE POSITIONID IN (1,3) ORDER BY POSITIONID,LAST_NAME;
Run Code Online (Sandbox Code Playgroud)

现在如果我只想显示 50 到 60 之间的前十行,我能想到的唯一方法是首先使用 ROWNUM 伪列运行上面的查询,然后从这个查询的结果中进行选择。像这样的东西:

SELECT EMP_ID,LAST_NAME FROM 
 (SELECT  ROWNUM RNUM,EMP_ID,LAST_NAME FROM
  (SELECT EMP_ID,LAST_NAME FROM EMPLOYEES
     WHERE POSITIONID IN (1,3) ORDER BY POSITIONID,LAST_NAME))
  WHERE RNUM BETWEEN 50 AND 60;    
Run Code Online (Sandbox Code Playgroud)

但是这样,我最终会首先获取职位为 1 或 3 的所有员工,然后提取其中的 10 行。我觉得这有点低效。有没有办法在不先进行全面扫描的情况下实现这一目标?

Jus*_*ave 5

获取行 N 到 M的标准方法是执行类似的操作

SELECT *
  FROM (SELECT a.*, rownum rnum
          FROM (SELECT emp_id, last_name
                  FROM employees
                 WHERE positionID in (1,3)
                 ORDER BY <<something>>) a
         WHERE rownum <= 60) b
 WHERE rnum > 50
Run Code Online (Sandbox Code Playgroud)

请注意,您需要order by在查询中包含以使其有意义。Oracle 可能会使用表扫描(取决于是否positionID和/或order by索引中的列),但会有一个停止键限制器,因此 Oracle 知道一旦 60 行有,它就可以停止扫描表(或索引)被阅读。

在 12.1 及更高版本中,您可以稍微简化一下

SELECT emp_id, last_nae
  FROM employees
 WHERE positionID in (1,3)
 ORDER BY val
OFFSET 50 ROWS
 FETCH NEXT 10 ROWS ONLY
Run Code Online (Sandbox Code Playgroud)

12.1中使用新行限制子句的更多示例