ルールベースのパス選択後、複数の選択可能なパスが存在する場合、OceanBaseデータベースは各パスのコストを計算し、その中からコストが最も小さいパスを最終的に選択します。
OceanBaseデータベースのコストモデルでは、CPUコスト(例えば、ある述語を処理するためのCPUオーバーヘッド)とI/Oコスト(例えば、マクロブロックやマイクロブロックの順次読み取りやランダム読み取りのコスト)が考慮されます。CPUコストとI/Oコストを合計して、総コストが求められます。
説明
複雑な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のスキャンメカニズムは順次I/Oです。
テーブルへの再アクセスコスト
テーブルへの再アクセスコストは再アクセス行数に正比例します。再アクセス行数が多いほど(再アクセス行数とは、インデックス上で実行可能なすべての述語を満たす行数のこと)、実行時間は長くなります。テーブルへの再アクセスのスキャンメカニズムはランダムI/Oであるため、テーブルへの再アクセスで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