OceanBase LIMIT

2021-06-29 17:39 更新

LIMIT 算子用于限制數(shù)據(jù)輸出的行數(shù),與 MySQL 的 LIMIT 算子功能相同。

在 OceanBase 數(shù)據(jù)庫的 MySQL 模式中處理含有 LIMIT 的 SQL 時,SQL 優(yōu)化器都會為其生成一個 LIMIT 算子,但在一些特殊場景不會給與分配,例如 LIMIT 可以下壓到基表的場景,就沒有分配的必要性。

而對于 OceanBase 數(shù)據(jù)庫的 Oracle 模式,以下兩種場景會為其分配 LIMIT 算子:

  • ROWNUM 經(jīng)過 SQL 優(yōu)化器改寫生成
  • 為了兼容 Oracle12c 的 FETCH 功能

MySQL 模式含有 LIMIT 的 SQL 場景

示例 1:OceanBase 數(shù)據(jù)庫的 MySQL 模式含有 LIMIT 的 SQL 場景

obclient>CREATE TABLE t1(c1 INT, c2 INT);
Query OK, 0 rows affected (0.12 sec)

obclient>CREATE TABLE t2(c1 INT, c2 INT);
Query OK, 0 rows affected (0.12 sec)

obclient>INSERT INTO t1 VALUES(1, 1);
Query OK, 1 rows affected (0.12 sec)

obclient>INSERT INTO t1 VALUES(2, 2);
Query OK, 1 rows affected (0.12 sec)

obclient>INSERT INTO t1 VALUES(3, 3);
Query OK, 1 rows affected (0.12 sec)

obclient>INSERT INTO t2 VALUES(1, 1);
Query OK, 1 rows affected (0.12 sec)

obclient>INSERT INTO t2 VALUES(2, 2);
Query OK, 1 rows affected (0.12 sec)

obclient>INSERT INTO t2 VALUES(3, 3);
Query OK, 1 rows affected (0.12 sec)

Q1: 
obclient>EXPLAIN SELECT t1.c1 FROM t1,t2 LIMIT 1 OFFSET 1\G;
*************************** 1. row ***************************
Query Plan:
| =====================================================
|ID|OPERATOR                   |NAME|EST. ROWS|COST |
-----------------------------------------------------
|0 |LIMIT                      |    |1        |39   |
|1 | NESTED-LOOP JOIN CARTESIAN|    |2        |39   |
|2 |  TABLE SCAN               |t1  |1        |36   |
|3 |  TABLE SCAN               |t2  |100000   |59654|
=====================================================

Outputs & filters: 
-------------------------------------
  0 - output([t1.c1]), filter(nil), limit(1), offset(1)
  1 - output([t1.c1]), filter(nil), 
      conds(nil), nl_params_(nil)
  2 - output([t1.c1]), filter(nil), 
      access([t1.c1]), partitions(p0)
  3 - output([t2.__pk_increment]), filter(nil), 
      access([t2.__pk_increment]), partitions(p0)

Q2: 
obclient>EXPLAIN SELECT * FROM t1 LIMIT 2\G;
*************************** 1. row ***************************
Query Plan:
| ===================================
|ID|OPERATOR  |NAME|EST. ROWS|COST|
-----------------------------------
|0 |TABLE SCAN|t1  |2        |37  |
===================================

Outputs & filters: 
-------------------------------------
  0 - output([t1.c1], [t1.c2]), filter(nil), 
      access([t1.c1], [t1.c2]), partitions(p0), 
      limit(2), offset(nil)
     

上述示例中,Q1 查詢的執(zhí)行計劃展示中的 outputs & filters 詳細(xì)列出了 LIMIT 算子的輸出信息如下:

信息名稱

含義

output

該算子輸出的表達(dá)式。

filter

該算子上的過濾條件。

由于示例中 LIMIT 算子沒有設(shè)置 filter,所以為 nil。

limit

限制輸出的行數(shù),是一個常量。

offset

距離當(dāng)前位置的偏移行數(shù),是一個常量。

由于示例中的 SQL 中不含有 offset,因此生成的計劃中為 nil。

Q2 查詢的執(zhí)行計劃展示中,雖然 SQL 中含有 LIMIT,但是并未分配 LIMIT 算子,而是將相關(guān)表達(dá)式下壓到了 TABLE SCAN 算子上,這種下壓 LIMIT 行為是 SQL 優(yōu)化器的一種優(yōu)化方式,詳細(xì)信息請參見 TABLE SCAN。

Oracle 模式含有 COUNT 的 SQL 改寫為 LIMIT 場景

由于 Oracle 模式含有 COUNT 的 SQL 改寫為 LIMIT 場景在 COUNT 算子章節(jié)已經(jīng)有過相關(guān)介紹,詳細(xì)信息請參見 COUNT。

Oracle 模式含有 FETCH 的 SQL 場景

示例 2:OceanBase 數(shù)據(jù)庫的 Oracle 模式含有 FETCH 的 SQL 場景

obclient>CREATE TABLE T1(c1 INT, c2 INT);
Query OK, 0 rows affected (0.12 sec)

obclient>CREATE TABLE T1(c1 INT, c2 INT);
Query OK, 0 rows affected (0.12 sec)

obclient>INSERT INTO t1 VALUES(1, 1);
Query OK, 1 rows affected (0.12 sec)

obclient>INSERT INTO t1 VALUES(2, 2);
Query OK, 1 rows affected (0.12 sec)

obclient>INSERT INTO t1 VALUES(3, 3);
Query OK, 1 rows affected (0.12 sec)

obclient>INSERT INTO t2 VALUES(1, 1);
Query OK, 1 rows affected (0.12 sec)

obclient>INSERT INTO t2 VALUES(2, 2);
Query OK, 1 rows affected (0.12 sec)

obclient>INSERT INTO t2 VALUES(3, 3);
Query OK, 1 rows affected (0.12 sec)

Q3: 
obclient>EXPLAIN SELECT * FROM t1,t2 OFFSET 1 ROWS 
           FETCH NEXT 1 ROWS ONLY\G;
*************************** 1. row ***************************
Query Plan:
| =====================================================
|ID|OPERATOR                   |NAME|EST. ROWS|COST |
-----------------------------------------------------
|0 |LIMIT                      |    |1        |238670   |
|1 | NESTED-LOOP JOIN CARTESIAN|    |2        |238669   |
|2 |  TABLE SCAN               |T1  |1        |36   |
|3 |  MATERIAL               |    |100000  |238632   |
|4 |  TABLE SCAN               |T2  |100000   |64066|
=====================================================

Outputs & filters: 
-------------------------------------
  0 - output([T1.C1], [T1.C2], [T2.C1], [T2.C2]), filter(nil), limit(?), offset(?)
  1 - output([T1.C1], [T1.C2], [T2.C1], [T2.C2]), filter(nil), 
      conds(nil), nl_params_(nil)
  2 - output([T1.C1], [T1.C2]), filter(nil), 
      access([T1.C1], [T1.C2]), partitions(p0)
  3 - output([T2.C1], [T2.C2]), filter(nil)
  4 - output([T2.C1], [T2.C2]), filter(nil), 
      access([T2.C1], [T2.C2]), partitions(p0)
      
      
 Q4: 
obclient>EXPLAIN SELECT * FROM t1 FETCH NEXT 1 ROWS ONLY\G;
*************************** 1. row ***************************
Query Plan:
 | ===================================
|ID|OPERATOR  |NAME|EST. ROWS|COST|
-----------------------------------
|0 |TABLE SCAN|T1  |1        |37  |
===================================

Outputs & filters: 
-------------------------------------
  0 - output([T1.C1], [T1.C2]), filter(nil), 
      access([T1.C1], [T1.C2]), partitions(p0), 
      limit(?), offset(nil)
 
 
 Q5: 
obclient>EXPLAIN SELECT * FROM t2 ORDER BY c1 FETCH NEXT 10 
            PERCENT ROW WITH TIES\G;
*************************** 1. row ***************************
Query Plan:
| =======================================
|ID|OPERATOR    |NAME|EST. ROWS|COST  |
---------------------------------------
|0 |LIMIT       |    |10000    |573070|
|1 | SORT       |    |100000   |559268|
|2 |  TABLE SCAN|T2  |100000   |64066 |
=======================================

Outputs & filters: 
-------------------------------------
  0 - output([T2.C1], [T2.C2]), filter(nil), limit(nil), offset(nil), percent(?), with_ties(true)
  1 - output([T2.C1], [T2.C2]), filter(nil), sort_keys([T2.C1, ASC])
  2 - output([T2.C1], [T2.C2]), filter(nil), 
      access([T2.C1], [T2.C2]), partitions(p0)

上述示例中,Q3 和 Q4 的查詢的執(zhí)行計劃展示中,與之前 MySQL 模式的 Q1 和 Q2 查詢基本相同,這是因為 Oracle 12c 的 FETCH 功能和 MySQL 的 LIMIT 功能類似,兩者的區(qū)別如 Q5 執(zhí)行計劃展示中所示。

執(zhí)行計劃展示中的 outputs & filters 詳細(xì)列出了 LIMIT 算子的輸出信息如下:

信息名稱

含義

output

該算子輸出的表達(dá)式。

filter

該算子上的過濾條件。

由于示例中 LIMIT 算子沒有設(shè)置 filter,所以為 nil。

limit

限制輸出的行數(shù),是一個常量。

offset

距離當(dāng)前位置的偏移行數(shù),是一個常量。

percent

按照數(shù)據(jù)總行數(shù)的百分比輸出,是一個常量。

with_ties

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

例如,要求輸出最后一行,但是排序之后有兩行的值都為 1,如果設(shè)置了最后一行按照等值一起輸出,那么這兩行都會被輸出。

以上 LIMIT 算子的新增的計劃展示屬性,都是在 Oracle 模式下的 FETCH 功能特有的,不影響 MySQL 模式計劃。關(guān)于 Oracle12c 的 FETCH 語法的詳細(xì)信息,請參見 Oracle 12c Fetch Rows


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號