セレクション率とは、述語条件を経た後に返される行数と、述語条件を経ずに返される行数の比率です。明らかに、セレクション率の値域は0から1であり、値が小さいほど選択性が良いことを意味し、セレクション率が1の場合が最も選択性が悪いことを示します。OceanBaseデータベースのオプティマイザーは、統計情報とセレクション率計算ルールに基づいて述語のセレクション率を計算し、その後行数を推定します。
例えば、次の例を見てください:
テーブル
t1を作成します。obclient> CREATE TABLE t1(c1 INT, c2 INT, c3 INT);テーブル
t1にテストデータを挿入します。obclient> INSERT INTO t1 SELECT mod(level, 10), mod(level, 100), mod(level, 1000) FROM DUAL CONNECT BY LEVEL <= 1000;実行結果は次のとおりです:
Query OK, 1000 rows affected Records: 1000 Duplicates: 0 Warnings: 0ユーザー
TESTのT1テーブルの統計情報を収集します。obclient> CALL DBMS_STATS.GATHER_TABLE_STATS('TEST','T1');ユーザー
TESTのT1テーブルの列統計情報を確認します。obclient> SELECT NUM_DISTINCT, LOW_VALUE, HIGH_VALUE FROM SYS.DBA_TAB_COL_STATISTICS WHERE owner = 'TEST' AND table_name = 'T1';実行結果は次のとおりです:
+--------------+-----------+------------+ | NUM_DISTINCT | LOW_VALUE | HIGH_VALUE | +--------------+-----------+------------+ | 10 | 0 | 9 | | 101 | 0 | 99 | | 1031 | 0 | 999 | +--------------+-----------+------------+ 3 rows in set
テーブル
t1を作成します。obclient> CREATE TABLE t1(c1 INT, c2 INT, c3 INT);テーブル
t1にテストデータを挿入します。変数を設定します。
obclient> SET @i = 0;データを挿入します。
obclient> INSERT INTO t1 (c1, c2, c3) SELECT MOD(@i := @i + 1, 10), MOD(@i, 100), MOD(@i, 1000) FROM information_schema.tables a, information_schema.tables b, information_schema.tables c LIMIT 1000;実行結果は次のとおりです:
Query OK, 1000 rows affected Records: 1000 Duplicates: 0 Warnings: 0t1のデータ件数を確認します。obclient> SELECT COUNT(*) FROM t1;実行結果は次のとおりです:
+----------+ | COUNT(*) | +----------+ | 1000 | +----------+ 1 row in set
データベース
db_testのt1テーブルの統計情報を収集します。obclient> CALL DBMS_STATS.GATHER_TABLE_STATS('db_test','t1');データベース
db_testのt1テーブルの列統計情報を確認します。obclient> SELECT NUM_DISTINCT, LOW_VALUE, HIGH_VALUE FROM oceanbase.DBA_TAB_COL_STATISTICS WHERE owner = 'db_test' AND table_name = 't1';実行結果は次のとおりです:
+--------------+-----------+------------+ | NUM_DISTINCT | LOW_VALUE | HIGH_VALUE | +--------------+-----------+------------+ | 10 | 0 | 9 | | 103 | 0 | 99 | | 1012 | 0 | 999 | +--------------+-----------+------------+ 3 rows in set
統計情報を収集した後、関連するビューを照会することで、c1 列の NDV が10であることがわかります。したがって、クエリQ1:SELECT * FROM t1 WHERE c1 = 10 における c1 = 10 のセレクション率は:1/10 = 0.1 となります。したがって、推定される行数は:1000 * 1/10 = 100 となります。以下の実行計画を確認して検証します:
Q1:
obclient> EXPLAIN SELECT * FROM t1 WHERE c1 = 10;
結果は次のとおりです:
+------------------------------------------------------------------------------------+
| Query Plan |
+------------------------------------------------------------------------------------+
| =============================================== |
| |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)| |
| ----------------------------------------------- |
| |0 |TABLE FULL SCAN|t1 |100 |60 | |
| =============================================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([t1.c1], [t1.c2], [t1.c3]), filter([t1.c1 = 10]), rowset=256 |
| access([t1.c1], [t1.c2], [t1.c3]), partitions(p0) |
| is_index_back=false, is_global_index=false, filter_before_indexback[false], |
| range_key([t1.__pk_increment]), range(MIN ; MAX)always true |
+------------------------------------------------------------------------------------+
11 rows in set
同様に、クエリQ2:SELECT * FROM t1 WHERE c1 = 10 AND c2 = 10 について、cardinality_estimation_model が partial の場合、Q2の2つの述語のセレクション率は 1/101 * sqrt( 1/10) で、約0.0031となります。行数の推定結果は切り上げて4となります。以下の実行計画を確認して検証します:
Q2:
obclient> EXPLAIN SELECT * FROM t1 WHERE c1 = 10 AND c2 = 10;
結果は次のとおりです:
+------------------------------------------------------------------------------------------+
| Query Plan |
+------------------------------------------------------------------------------------------+
| =============================================== |
| |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)| |
| ----------------------------------------------- |
| |0 |TABLE FULL SCAN|T1 |4 |63 | |
| =============================================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([T1.C1], [T1.C2], [T1.C3]), filter([T1.C2 = 10], [T1.C1 = 10]), rowset=16 |
| access([T1.C1], [T1.C2], [T1.C3]), partitions(p0) |
| is_index_back=false, is_global_index=false, filter_before_indexback[false,false], |
| range_key([T1.__pk_increment]), range(MIN ; MAX)always true |
+------------------------------------------------------------------------------------------+
11 rows in set
現在、セレクション率による行数推定は、OceanBaseデータベースのオプティマイザーにおける行数推定の主要な手法です。計画生成時には、関連する演算子の述語条件に対して統計情報とそのセレクション率計算ルールに基づいて対応するセレクション率が計算され、最終的に全体のセレクション率に基づいて行数が推定されます。