在一般场景下,当 SQL 查询含有 ROWNUM 时,SQL 优化器就会在生成执行计划的时候分配一个 COUNT 算子。当然在一些情况下,SQL 优化器会将含有 ROWNUM 的 SQL 改写为 LIMIT 算子,这时就不会再分配 COUNT 算子。

    示例 1:含有 ROWNUM 的 SQL 查询正常分配 COUNT 算子场景。

    上述示例中,执行计划展示中的 outputs & filters 详细展示了 COUNT 算子的输出信息如下:

    从上述执行计划示例的输出结果可以发现,ROWNUM 对应的表达式的初始值为 1,每通过一次 COUNT 算子,COUNT 算子就会为 ROWNUM 对应的表达式的值加上 1,实现 ROWNUM 表达式的自增操作。

    不分配 COUNT 算子的场景

    示例 2:含有 rownum 的 SQL 改写为 LIMIT 后,不分配 COUNT 算子的场景。

    1. obclient>EXPLAIN SELECT 1 FROM DUAL WHERE ROWNUM < 2\G;
    2. *************************** 1. row ***************************
    3. Query Plan:
    4. ------------------------------------
    5. |0 |LIMIT | |1 |1 |
    6. |1 | EXPRESSION| |1 |1 |
    7. ====================================
    8. Outputs & filters:
    9. -------------------------------------
    10. 0 - output([1]), filter(nil), limit(?), offset(nil)
    11. 1 - output([1]), filter(nil)

    从上述执行计划示例的输出结果可以发现,虽然 SQL 中含有 ROWNUM,但是经过 SQL 优化器改写之后,已经将涉及含有 ROWNUM 的表达式转换为了等价的 LIMIT 表达式,转换的好处在于可以做更多的优化,详细信息请参见 LIMIT