sql - Oracle中分页查询的速度

标签 sql performance oracle11g rownum window-functions

对我来说,这是一个永无止境的话题,我想知道我是否会忽略某些事情。本质上,我在应用程序中使用两种类型的SQL语句:

  • 带有“后备”限制的常规查询
  • 排序和分页查询

  • 现在,我们讨论的是针对具有几百万条记录的表的一些查询,再加上另外五个具有几百万条记录的表的查询。显然,我们几乎不希望全部获取它们,这就是为什么我们有上述两种方法来限制用户查询的原因。

    情况1 非常简单。我们只是添加了一个附加的ROWNUM过滤器:
    WHERE ...
      AND ROWNUM < ?
    

    这是相当快的,因为Oracle的CBO会在执行计划中考虑此过滤器,并可能应用FIRST_ROWS操作(类似于/*+FIRST_ROWS*/提示所强制执行的操作)。

    情况2 ,但是对于Oracle来说比较棘手,因为没有像其他RDBMS中那样LIMIT ... OFFSET子句。因此,我们将“业务”查询嵌套在技术包装中,如下所示:
    SELECT outer.* FROM (
      SELECT * FROM (
        SELECT inner.*, ROWNUM as RNUM, MAX(ROWNUM) OVER(PARTITION BY 1) as TOTAL_ROWS
        FROM (
          [... USER SORTED business query ...]
        ) inner
      ) 
      WHERE ROWNUM < ?
    ) outer
    WHERE outer.RNUM > ?
    

    请注意,计算TOTAL_ROWS字段是为了知道即使不获取所有数据,我们将拥有多少页。现在,此分页查询通常非常令人满意。但是有时(如我所说,当查询5M +记录时(可能包括未索引的搜索)),此过程将持续2-3分钟。

    编辑:请注意,潜在的瓶颈并不是那么容易解决,因为在分页之前必须进行排序!

    我想知道,是LIMIT ... OFFSET的最新模拟,包括Oracle中的TOTAL_ROWS,还是有更好的解决方案,可以通过设计更快地完成,例如通过使用ROW_NUMBER()窗口函数而不是ROWNUM伪列?

    最佳答案

    情况2的主要问题是,在许多情况下,必须先获取整个查询结果集,然后在之前对进行排序,然后才能返回前N行-除非对ORDER BY列进行了索引并且Oracle可以使用索引来避免种类。对于复杂的查询和大量数据,这可能需要一些时间。但是,您可以采取一些措施来提高速度:

  • 尝试确保内部SQL中没有调用任何函数-仅返回前20行,它们可能被调用500万次。如果您可以将这些函数调用移至外部查询,则将减少它们的调用。
  • 使用FIRST_ROWS_n提示来插入Oracle优化,以使您永远不会返回所有数据。

  • 编辑:

    另一个想法:您当前正在向用户显示可以返回数千或数百万行的报告,但是用户从不现实地翻阅所有行。您能不能强制他们选择较少的数据量,例如通过将选择的日期范围限制为3个月(或其他日期)?

    关于sql - Oracle中分页查询的速度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6033080/

    相关文章:

    mysql - 如何设置 MySQL 唯一行?

    mysql - 一个基本的 sql 查询示例

    .net - ConvertEmptyStringToNull 属性

    jquery - 如何让jquery动画快一些?

    sql - Regexp_replace 添加额外的字符

    sql - 在哪里可以找到有关第六范式的信息

    java - 为什么我的Java程序启动后性能会明显下降?

    MySQL ORDER BY - 减慢查询速度

    sql - 如何使用分层子查询构建层次结构路径

    oracle - PL/SQL - 计算重叠时间段之间的不同天数