ルールに基づくパス選択の後、複数のパスが選択可能な場合、OceanBaseデータベースは各パスのコストを計算し、その中からコストが最小のパスを最終的に選択します。
OceanBaseデータベースのコストモデルでは、CPUコスト(例えば、ある述語を処理するためのCPUオーバーヘッド)とIOコスト(例えば、マクロブロックおよびマイクロブロックの順次読み取りやランダム読み取りのコスト)が考慮されており、CPUコストとIOコストを合計して総コストが求められます。
説明
複雑なSQLクエリにおいて、複数の MATCH ... AGAINST ... およびその他のフィルター条件が含まれる場合、データベースはスキャンオーバーヘッドを削減するために最適なインデックスパスをインテリジェントに選択します。詳細については、MATCH AGAINST を参照してください。
OceanBaseデータベースでは、各アクセスパスのコストは実行計画に表示されます。以下の例を参照してください:
obclient> CREATE TABLE t1(a INT PRIMARY KEY, b INT, c INT, INDEX k1(b));
Query OK, 0 rows affected
/* 主表パスのコスト */
obclient>EXPLAIN SELECT/*+INDEX(t1 PRIMARY)*/ * FROM t1 WHERE b < 10;
+-----------------------------------------------------------------+
| Query Plan |
+-----------------------------------------------------------------+
| ===================================
|ID|OPERATOR |NAME|EST. ROWS|EST.TIME(us)|
-----------------------------------
|0 |TABLE SCAN|t1 |200 |622 |
===================================
Outputs & filters:
-------------------------------------
0 - output([t1.a], [t1.b], [t1.c]), filter([t1.b < 10]),
access([t1.b], [t1.a], [t1.c]), partitions(p0)
/* k1 パスのコスト */
obclient> EXPLAIN SELECT/*+INDEX(t1 k1)*/ * FROM t1 WHERE b < 10;
+--------------------------------------------------------------------+
| Query Plan |
+--------------------------------------------------------------------+
| =====================================
|ID|OPERATOR |NAME |EST. ROWS|EST.TIME(us)|
-------------------------------------
|0 |TABLE SCAN|t1(k1)|200 |1114|
=====================================
Outputs & filters:
-------------------------------------
0 - output([t1.a], [t1.b], [t1.c]), filter(nil),
access([t1.b], [t1.a], [t1.c]), partitions(p0)
アクセスパスのコストは、主にアクセスパスのスキャンコストとテーブルへのアクセスコストの2部分で構成されます。アクセスパスでテーブルへのアクセスが不要な場合、テーブルへのアクセスコストは発生しません。
OceanBaseデータベースでは、アクセスパスのコストは、スキャンする行数、テーブルへのアクセス行数、投影する列数、述語の数など、多くの要因によって決まります。しかし、アクセスパスにとってコストは大きく行数に依存するため、以下の例では主に行数という観点からこれら2つのコストを説明します。
アクセスパスのスキャンコスト
アクセスパスのスキャンコストは、スキャンする行数に比例します。理論的には、スキャンする行数が多いほど、実行時間も長くなります。アクセスパスにおいて、Query Range はスキャン範囲を決定し、それによってスキャンする行数が決まります。Query Range のスキャンメカニズムは順次IOです。
テーブルへのアクセスコスト
テーブルへのアクセスコストは、テーブルへのアクセス行数に正比例します。テーブルへのアクセス行数が多いほど(テーブルへのアクセス行数とは、インデックス上で実行可能なすべての述語を満たす行数を指します)、実行時間も長くなります。テーブルへのアクセスのスキャンメカニズムはランダムIOであるため、テーブルへのアクセス1行のコストは、Query Range スキャン1行のコストよりもはるかに高くなります。
アクセスパスのパフォーマンスを分析する際には、取得したQuery Range スキャン行数とテーブルへのアクセス行数に基づいて分析できます。これら2つの行数は通常、SQL文を実行することで取得できます。
以下の例のように、クエリ SELECT * FROM t1 WHERE c2 > 20 AND c2 < 800 AND c3 < 200 の場合、インデックス k1 のアクセスパスは、通常計画が最初に示され、Query Range を抽出するための述語を取得します。述語 c2 > 20 AND c2 < 800 はQuery Range を抽出するために使用され、述語 c3 < 200 はテーブルへのアクセス前の述語として扱われます。例の2つのクエリを使用して、Query Range から抽出される行数とテーブルへのアクセス後の行数を確認できます。
obclient> CREATE TABLE t1(c1 INT PRIMARY KEY, c2 INT, c3 INT, c4 INT, c5 INT, INDEX k1(c2,c3));
Query OK, 0 rows affected
obclient> EXPLAIN EXTENDED_NOADDR SELECT/*+INDEX(t1 k1)*/ * FROM t1 WHERE
c2 > 20 AND c2 < 800 AND c3 < 200;
+--------------------------------------------------------------+
| Query Plan |
+--------------------------------------------------------------+
| =====================================
|ID|OPERATOR |NAME |EST. ROWS|EST.TIME(us)|
-------------------------------------
|0 |TABLE SCAN|t1(k1)|156 |1216|
=====================================
Outputs & filters:
-------------------------------------
0 - output([t1.c1], [t1.c2], [t1.c3], [t1.c4], [t1.c5]), filter([t1.c3 < 200]),
access([t1.c2], [t1.c3], [t1.c1], [t1.c4], [t1.c5]), partitions(p0),
is_index_back=true, filter_before_indexback[true],
range_key([t1.c2], [t1.c3], [t1.c1]), range(20,MAX,MAX ; 800,MIN,MIN),
range_cond([t1.c2 > 20], [t1.c2 < 800])
/* Query Range スキャンの行数 */
obclient> SELECT/*+INDEX(t1 k1)*/ COUNT(*) FROM t1 WHERE c2 > 20 AND c2 < 800;
+----------+
| count(*) |
+----------+
| 779 |
+----------+
1 row in set
/* テーブルへのアクセス行数 */
obclient> SELECT/*+INDEX(t1 k1)*/ COUNT(*) FROM t1 WHERE c2 > 20 AND c2 < 800
AND c3 < 200;
+----------+
| count(*) |
+----------+
| 179 |
+----------+
1 row in set