LIMIT 述语は、データ出力の行数を制限するために使用されます。これはMySQLの LIMIT 述語と同じ機能です。
OceanBaseデータベースのMySQLモードで LIMIT を含むSQL文を処理する際、SQLオプティマイザーは常に LIMIT 述語を生成しますが、一部の特殊なシナリオでは割り当てません。例えば、LIMIT をベーステーブルにプッシュダウンできる場合は、割り当てる必要はありません。
OceanBaseデータベースのOracleモードでは、以下の2つのシナリオで LIMIT 述語が割り当てられます:
ROWNUMがSQLオプティマイザーによって書き換えられた場合Oracle12cの
FETCH機能との互換性のため
MySQLモードにおけるLIMITを含むSQLのシナリオ
例1:OceanBaseデータベースのMySQLモードにおける LIMIT 述語を含むSQLのシナリオ
obclient> CREATE TABLE t1(c1 INT, c2 INT);
Query OK, 0 rows affected
obclient> CREATE TABLE t2(c1 INT, c2 INT);
Query OK, 0 rows affected
obclient> INSERT INTO t1 VALUES(1, 1);
Query OK, 1 rows affected
obclient> INSERT INTO t1 VALUES(2, 2);
Query OK, 1 rows affected
obclient> INSERT INTO t1 VALUES(3, 3);
Query OK, 1 rows affected
obclient> INSERT INTO t2 VALUES(1, 1);
Query OK, 1 rows affected
obclient> INSERT INTO t2 VALUES(2, 2);
Query OK, 1 rows affected
obclient> INSERT INTO t2 VALUES(3, 3);
Query OK, 1 rows affected
Q1:
obclient> EXPLAIN SELECT t1.c1 FROM t1,t2 LIMIT 1 OFFSET 1;
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;
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クエリの実行計画表示における outputs & filters が LIMIT 述語の出力情報を詳細に示しています:
情報名 |
意味 |
|---|---|
| output | この述語が出力する式。 |
| filter | この述語のフィルター条件。例では LIMIT 述語に filter が設定されていないため、nil です。 |
| limit | 出力行数の上限。定数です。 |
| offset | 現在の位置からのオフセット行数。定数です。 |
Q2クエリの実行計画表示では、SQLに LIMIT が含まれているものの、LIMIT 述語は割り当てられず、関連する式が TABLE SCAN 述語にプッシュダウンされています。例のSQLには offset が含まれていないため、生成された計画では nil となっています。このような LIMIT のプッシュダウンは、SQLオプティマイザーの最適化手法の一つです。詳細については、TABLE SCANを参照してください。
OracleモードにおけるCOUNTを含むSQLのLIMIT述語への書き換え
OracleモードでCOUNTを含むSQLをLIMITに書き換えるシナリオについては、COUNT述語の章で既に紹介しています。詳細については、COUNTを参照してください。
OracleモードにおけるFETCHを含むSQLのシナリオ
例2:OceanBaseデータベースのOracleモードにおける FETCH を含むSQLのシナリオ
obclient> CREATE TABLE T1(c1 INT, c2 INT);
Query OK, 0 rows affected
obclient> CREATE TABLE T2(c1 INT, c2 INT);
Query OK, 0 rows affected
obclient> INSERT INTO t1 VALUES(1, 1);
Query OK, 1 rows affected
obclient> INSERT INTO t1 VALUES(2, 2);
Query OK, 1 rows affected
obclient> INSERT INTO t1 VALUES(3, 3);
Query OK, 1 rows affected
obclient> INSERT INTO t2 VALUES(1, 1);
Query OK, 1 rows affected
obclient> INSERT INTO t2 VALUES(2, 2);
Query OK, 1 rows affected
obclient> INSERT INTO t2 VALUES(3, 3);
Query OK, 1 rows affected
Q3:
obclient> EXPLAIN SELECT * FROM t1,t2 OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY;
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;
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;
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クエリの実行計画表示は、前述のMySQLモードのQ1およびQ2クエリと基本的に同じです。これは、Oracle 12cの FETCH 機能がMySQLの LIMIT 機能と類似しているためです。両者の違いは、Q5の実行計画表示に示されています。
実行計画表示の outputs & filters が LIMIT 述語の出力情報を詳細に示しています:
情報名 |
意味 |
|---|---|
| output | この述語が出力する式。 |
| filter | この演算子におけるフィルター条件です。例では LIMIT 演算子に filter が設定されていないため、nil となります。 |
| limit | 出力する行数の上限を指定します。これは定数です。 |
| offset | 現在の位置からのオフセット行数を指定します。これは定数です。 |
| percent | データ総行数の割合に応じて出力する行数を指定します。これは定数です。 |
| with_ties | ソート後に最後の行を同値でまとめて出力するかどうかを指定します。例えば、最後の行を出力するよう指定しても、ソート後に値が1の行が2行ある場合、このオプションを有効にすると、その2行がまとめて出力されます。 |
上記の LIMIT 演算子に追加された実行計画表示プロパティは、すべてOracleモードの FETCH 機能独自のものであり、MySQLモードの実行計画には影響しません。Oracle12cの FETCH 構文の詳細については、Oracle 12c Fetch Rowsを参照してください。