在 OceanBase 数据库的 MySQL 模式中处理含有 LIMIT 的 SQL 时,SQL 优化器都会为其生成一个 LIMIT 算子,但在一些特殊场景不会给与分配,例如 LIMIT 可以下压到基表的场景,就没有分配的必要性。

而对于 OceanBase 数据库的 Oracle 模式,以下两种场景会为其分配 LIMIT 算子:

  • ROWNUM 经过 SQL 优化器改写生成

  • 为了兼容 Oracle12c 的 FETCH 功能

示例 1:OceanBase 数据库的 MySQL 模式含有 LIMIT 的 SQL 场景

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

Q2 查询的执行计划展示中,虽然 SQL 中含有 LIMIT,但是并未分配 LIMIT 算子,而是将相关表达式下压到了 TABLE SCAN 算子上,这种下压 LIMIT 行为是 SQL 优化器的一种优化方式,详细信息请参见 。

由于 Oracle 模式含有 COUNT 的 SQL 改写为 LIMIT 场景在 COUNT 算子章节已经有过相关介绍,详细信息请参见 COUNT

示例 2:OceanBase 数据库的 Oracle 模式含有 FETCH 的 SQL 场景

  1. Query OK, 0 rows affected (0.12 sec)
  2. obclient>CREATE TABLE T1(c1 INT, c2 INT);
  3. Query OK, 0 rows affected (0.12 sec)
  4. obclient>INSERT INTO t1 VALUES(1, 1);
  5. Query OK, 1 rows affected (0.12 sec)
  6. obclient>INSERT INTO t1 VALUES(2, 2);
  7. Query OK, 1 rows affected (0.12 sec)
  8. obclient>INSERT INTO t1 VALUES(3, 3);
  9. Query OK, 1 rows affected (0.12 sec)
  10. obclient>INSERT INTO t2 VALUES(1, 1);
  11. Query OK, 1 rows affected (0.12 sec)
  12. obclient>INSERT INTO t2 VALUES(2, 2);
  13. Query OK, 1 rows affected (0.12 sec)
  14. obclient>INSERT INTO t2 VALUES(3, 3);
  15. Query OK, 1 rows affected (0.12 sec)
  16. Q3:
  17. FETCH NEXT 1 ROWS ONLY\G;
  18. *************************** 1. row ***************************
  19. Query Plan:
  20. |ID|OPERATOR |NAME|EST. ROWS|COST |
  21. -----------------------------------------------------
  22. |0 |LIMIT | |1 |238670 |
  23. |1 | NESTED-LOOP JOIN CARTESIAN| |2 |238669 |
  24. |2 | TABLE SCAN |T1 |1 |36 |
  25. |3 | MATERIAL | |100000 |238632 |
  26. |4 | TABLE SCAN |T2 |100000 |64066|
  27. =====================================================
  28. Outputs & filters:
  29. -------------------------------------
  30. 0 - output([T1.C1], [T1.C2], [T2.C1], [T2.C2]), filter(nil), limit(?), offset(?)
  31. 1 - output([T1.C1], [T1.C2], [T2.C1], [T2.C2]), filter(nil),
  32. conds(nil), nl_params_(nil)
  33. 2 - output([T1.C1], [T1.C2]), filter(nil),
  34. access([T1.C1], [T1.C2]), partitions(p0)
  35. 3 - output([T2.C1], [T2.C2]), filter(nil)
  36. 4 - output([T2.C1], [T2.C2]), filter(nil),
  37. access([T2.C1], [T2.C2]), partitions(p0)
  38. Q4:
  39. obclient>EXPLAIN SELECT * FROM t1 FETCH NEXT 1 ROWS ONLY\G;
  40. *************************** 1. row ***************************
  41. Query Plan:
  42. |ID|OPERATOR |NAME|EST. ROWS|COST|
  43. -----------------------------------
  44. ===================================
  45. Outputs & filters:
  46. -------------------------------------
  47. 0 - output([T1.C1], [T1.C2]), filter(nil),
  48. access([T1.C1], [T1.C2]), partitions(p0),
  49. limit(?), offset(nil)
  50. Q5:
  51. obclient>EXPLAIN SELECT * FROM t2 ORDER BY c1 FETCH NEXT 10
  52. PERCENT ROW WITH TIES\G;
  53. *************************** 1. row ***************************
  54. Query Plan:
  55. | =======================================
  56. |ID|OPERATOR |NAME|EST. ROWS|COST |
  57. ---------------------------------------
  58. |0 |LIMIT | |10000 |573070|
  59. |1 | SORT | |100000 |559268|
  60. |2 | TABLE SCAN|T2 |100000 |64066 |
  61. =======================================
  62. Outputs & filters:
  63. -------------------------------------
  64. 0 - output([T2.C1], [T2.C2]), filter(nil), limit(nil), offset(nil), percent(?), with_ties(true)
  65. 1 - output([T2.C1], [T2.C2]), filter(nil), sort_keys([T2.C1, ASC])
  66. access([T2.C1], [T2.C2]), partitions(p0)

上述示例中,Q3 和 Q4 的查询的执行计划展示中,与之前 MySQL 模式的 Q1 和 Q2 查询基本相同,这是因为 Oracle 12c 的 FETCH 功能和 MySQL 的 LIMIT 功能类似,两者的区别如 Q5 执行计划展示中所示。

执行计划展示中的 outputs & filters 详细列出了 LIMIT 算子的输出信息如下:

信息名称

含义

该算子输出的表达式。

filter

该算子上的过滤条件。

由于示例中 LIMIT 算子没有设置 filter,所以为 nil。

limit

限制输出的行数,是一个常量。

offset

距离当前位置的偏移行数,是一个常量。

percent

按照数据总行数的百分比输出,是一个常量。

with_ties

是否在排序后的将最后一行按照等值一起输出。

以上 LIMIT 算子的新增的计划展示属性,都是在 Oracle 模式下的 FETCH 功能特有的,不影响 MySQL 模式计划。关于 Oracle12c 的 FETCH 语法的详细信息,请参见 。