OceanBaseデータベースでは、パーティションテーブルの統計情報管理は パーティションレベル統計情報 と グローバル統計情報 に分かれており、この統計情報メカニズムはパーティションテーブルにのみ適用されます。非パーティションテーブル(つまり通常の単一テーブル)には、単一のグローバル統計情報のみが存在し、パーティション統計や導出ロジックは関与しません。
OceanBaseのパーティションテーブル統計情報メカニズムには、以下の特徴があります:
- グローバル統計とパーティション統計の区別:両者は独立して保存され、
partition_idによって区別されます。 - デフォルトで同時収集:
APPROX_GLOBAL AND PARTITIONの粒度では、グローバル統計とパーティション統計が同時に収集されます。 - 欠落の自動検出:欠落または期限切れの統計情報を自動的に検出し、収集をトリガーします。
- パーティション統計に基づくグローバル統計の導出:パーティション統計の基本統計情報に基づいてグローバル基本統計情報を導出し、グローバル統計情報の時宜性と正確性を向上させます。
本記事では、OceanBaseがパーティションテーブルに対して採用する統計情報収集戦略と自動更新ルールについて詳しく説明します。
デフォルトの収集ポリシー
OceanBaseは、すべてのパーティションテーブルに対して、デフォルトでAPPROX_GLOBAL AND PARTITION粒度で統計情報を収集します(DBMS_STATSパッケージのGATHER_INDEX_STATSプロシージャによって実装されています)。このポリシーでは、システムはパーティションレベル統計情報とグローバル統計情報の2種類の統計を同時に生成します。
パーティションレベル統計情報
各パーティションの独立した統計情報を収集します:
- 基本統計:列の最小値(min)、最大値(max)、異なる値の数(NDV)など。
- ヒストグラム:データの分布特性を表すために使用されます。
グローバル統計情報
- 基本統計情報(min、max、異なる値の数など):各パーティションの基本統計から導出・合成されます(例:グローバルmin = すべてのパーティションのminの最小値)。
- グローバルヒストグラム:パーティションの結果から導出することができないため、テーブル全体をサンプリングして収集する必要があります。
グローバル基本統計はテーブル全体のスキャンを必要とせず、大規模なパーティションテーブルの統計収集効率を大幅に向上させます。特にTB/PBレベルのAPシナリオに適しています。
自動更新メカニズム
統計情報の時宜を得た性質を保証するため、OceanBaseは自動検出および更新メカニズムを内蔵しており、データ変更率に基づいてリフレッシュをトリガーします。
グローバル統計情報更新のトリガー条件
以下のいずれかの状況が発生すると、グローバル統計の更新がトリガーされます:
- グローバル統計欠落:テーブルにグローバル統計情報が存在しません。
- グローバルデータ期限切れ:テーブル全体の変更行数比率が10%以上に達した場合 (
STALE_PERCENTで制御)。 - いずれかのパーティション統計の期限切れ:グローバルデータが変更されていなくても、特定のパーティション統計が無効になると、一貫性を保証するためにグローバル統計の更新がトリガーされます。
更新プロセス:
- グローバル基本統計:パーティションレベルの統計情報から導出されます (min、max、異なる値の数など)。
- グローバルヒストグラム:ヒストグラムは現在、パーティションの結果から導出して生成することができないため、個別に収集する必要があります。
パーティションレベル統計情報更新のトリガー条件
単一のパーティションの統計は、以下の場合に更新されます:
- そのパーティション統計欠落:特定のパーティションに統計情報が存在しません。
- そのパーティションデータ期限切れ:そのパーティションの変更行数比率が10%以上に達した場合 (
STALE_PERCENTで制御)。
更新プロセス:
- 期限切れのパーティションの統計情報を再収集します。
- グローバル統計情報を再収集します。
STALE_PERCENTの設定方法
ユーザーは DBMS_STATS パッケージを使用して、期限切れのしきい値を柔軟に調整できます:
-- グローバルデフォルト値を設定 (すべての新規テーブルに適用)
CALL dbms_stats.set_global_prefs('STALE_PERCENT', '50');
-- スキーマレベルを設定
CALL dbms_stats.set_schema_prefs('MY_SCHEMA', 'STALE_PERCENT', '30');
-- テーブルレベルを設定
CALL dbms_stats.set_table_prefs('MY_SCHEMA', 'MY_TABLE', 'STALE_PERCENT', '20');
自動検出機能
OceanBaseシステムのバックグラウンドでは、以下の検出タスクを継続的に実行します。
- 統計情報状態チェック:既存のすべてのグローバルおよびパーティション統計情報をスキャンします。
- 期限切れパーティション検出:各パーティションが期限切れまたは欠落していないか確認します。
- 欠落統計検出:欠落項目を自動的にマークし、収集キューに追加します。
- 独立した更新トリガー:グローバル統計とパーティション統計の更新を独立してトリガーでき、互いに影響しません。
主なパラメータ
パラメータ |
デフォルト値 |
説明 |
|---|---|---|
STALE_PERCENT |
10(10%) | ステアティック変更の閾値を判定するためのストアドプロシージャ(set_schema_prefs、set_table_prefs)のパラメータ |
| デフォルト収集粒度 | APPROX_GLOBAL AND PARTITION |
パーティションテーブルにのみ有効です。非パーティションテーブルでは GLOBAL を使用します(DBMS_STATS パッケージの GATHER_INDEX_STATS プロシージャにより実装されます)。 |
非パーティションテーブルとの比較
機能 |
パーティションテーブル |
非パーティションテーブル(単一テーブル) |
|---|---|---|
| 統計タイプ | グローバル + パーティション | グローバルのみ |
| グローバル基本統計の出典 | パーティション統計から導出 | フルテーブルスキャンにより生成 |
| パーティションプルーニング最適化をサポートするかどうか | はい | いいえ |
| デフォルトの収集粒度 | APPROX_GLOBAL AND PARTITION |
GLOBAL |
例:OceanBaseパーティションテーブルの統計情報管理
この例は、OceanBaseデータベース(MySQLモード)を基に、パーティションテーブルの作成方法、その統計情報の収集および自動更新の動作を確認する方法を示し、グローバル統計情報がパーティション統計からどのように導出されるかを実演します。
ステップ1:テスト用パーティションテーブルを作成する
-- データベースとユーザーを作成する(まだ存在しない場合)
CREATE DATABASE IF NOT EXISTS sales_db;
USE sales_db;
-- RANGEパーティションによる販売記録テーブルを作成する
CREATE TABLE sales (
id BIGINT NOT NULL,
region VARCHAR(50),
amount DECIMAL(10,2),
sale_date DATE,
PRIMARY KEY (id, sale_date)
) PARTITION BY RANGE COLUMNS(sale_date) (
PARTITION p2023_q1 VALUES LESS THAN ('2023-04-01'),
PARTITION p2023_q2 VALUES LESS THAN ('2023-07-01'),
PARTITION p2023_q3 VALUES LESS THAN ('2023-10-01'),
PARTITION p2023_q4 VALUES LESS THAN ('2024-01-01')
);
ステップ2:初期データを挿入する
-- 各パーティションにテストデータを挿入する
INSERT INTO sales VALUES
(1, 'North', 1500.00, '2023-01-15'),
(2, 'South', 2300.50, '2023-02-20'),
(3, 'East', 980.75, '2023-04-10'),
(4, 'West', 3200.00, '2023-06-25'),
(5, 'North', 1800.25, '2023-07-05'),
(6, 'South', 2100.00, '2023-09-18');
ステップ3:統計情報を収集する(デフォルトの粒度:APPROX_GLOBAL AND PARTITION)
CALL DBMS_STATS.GATHER_TABLE_STATS(
ownname => 'sales_db',
tabname => 'sales',
method_opt => 'FOR ALL COLUMNS SIZE AUTO',
granularity => 'APPROX_GLOBAL AND PARTITION'
);
ステップ4:統計情報を確認する
グローバルテーブルレベルの統計情報を表示する
SELECT
TABLE_NAME,
OBJECT_TYPE,
NUM_ROWS,
AVG_ROW_LEN,
LAST_ANALYZED
FROM oceanbase.DBA_TAB_STATISTICS
WHERE OWNER = 'SALES_DB' AND TABLE_NAME = 'SALES'
ORDER BY OBJECT_TYPE;
期待される結果:
+------------+-------------+----------+-------------+----------------------------+
| TABLE_NAME | OBJECT_TYPE | NUM_ROWS | AVG_ROW_LEN | LAST_ANALYZED |
+------------+-------------+----------+-------------+----------------------------+
| sales | PARTITION | 2 | 73 | 2026-01-14 10:45:58.067339 |
| sales | PARTITION | 2 | 72 | 2026-01-14 10:45:58.067339 |
| sales | PARTITION | 2 | 73 | 2026-01-14 10:45:58.067339 |
| sales | PARTITION | 0 | 0 | 2026-01-14 10:45:58.067339 |
| sales | TABLE | 6 | 72 | 2026-01-14 10:45:58.079250 |
+------------+-------------+----------+-------------+----------------------------+
5 rows in set
グローバル列レベルの統計情報を表示する(例:amount列)
SELECT
COLUMN_NAME,
NUM_DISTINCT,
LOW_VALUE,
HIGH_VALUE,
NUM_NULLS,
HISTOGRAM
FROM oceanbase.DBA_TAB_COL_STATISTICS
WHERE OWNER = 'SALES_DB'
AND TABLE_NAME = 'SALES'
AND COLUMN_NAME = 'AMOUNT';
期待される結果:
+-------------+--------------+-----------+------------+-----------+-----------+
| COLUMN_NAME | NUM_DISTINCT | LOW_VALUE | HIGH_VALUE | NUM_NULLS | HISTOGRAM |
+-------------+--------------+-----------+------------+-----------+-----------+
| amount | 6 | 980.75 | 3200.00 | 0 | NULL |
+-------------+--------------+-----------+------------+-----------+-----------+
1 row in set
パーティションレベルの列統計情報を確認する(例:p2023_q1パーティションのamount列)
SELECT
PARTITION_NAME,
COLUMN_NAME,
NUM_DISTINCT,
LOW_VALUE,
HIGH_VALUE,
NUM_NULLS
FROM oceanbase.DBA_PART_COL_STATISTICS
WHERE OWNER = 'SALES_DB'
AND TABLE_NAME = 'SALES'
AND PARTITION_NAME = 'P2023_Q1'
AND COLUMN_NAME = 'AMOUNT';
期待される結果:
+----------------+-------------+--------------+-----------+------------+-----------+
| PARTITION_NAME | COLUMN_NAME | NUM_DISTINCT | LOW_VALUE | HIGH_VALUE | NUM_NULLS |
+----------------+-------------+--------------+-----------+------------+-----------+
| p2023_q1 | amount | 2 | 1500.00 | 2300.50 | 0 |
+----------------+-------------+--------------+-----------+------------+-----------+
1 row in set
ステップ5:自動更新メカニズムの検証(オプション)
-- p2023_q4に新しいデータを挿入(>10%の変更をシミュレート)
INSERT INTO sales
SELECT 1000 + n, 'Central', ROUND(RAND()*5000, 2), '2023-11-01'
FROM (SELECT @n := @n + 1 AS n FROM information_schema.columns a, information_schema.columns b, (SELECT @n := 0) r LIMIT 50) t;
-- バックグラウンドでの自動検出を待つ(または手動でトリガー)
CALL DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO();
-- この時点で変更率がSTALE_PERCENT(デフォルト10%)以上の場合、システムは自動的にデータをstaleとマークし、収集をトリガーする可能性があります。
-- LAST_ANALYZEDの時間が更新されているか再度確認
SELECT PARTITION_NAME, LAST_ANALYZED
FROM oceanbase.DBA_TAB_STATISTICS
WHERE OWNER = 'SALES_DB' AND TABLE_NAME = 'SALES'
ORDER BY PARTITION_NAME;
期待される結果:
+----------------+----------------------------+
| PARTITION_NAME | LAST_ANALYZED |
+----------------+----------------------------+
| NULL | 2026-01-14 10:45:58.079250 |
| p2023_q1 | 2026-01-14 10:45:58.067339 |
| p2023_q2 | 2026-01-14 10:45:58.067339 |
| p2023_q3 | 2026-01-14 10:45:58.067339 |
| p2023_q4 | 2026-01-14 10:45:58.067339 |
+----------------+----------------------------+
5 rows in set
関連ドキュメント
関連するPLプロシージャの参照ドキュメントは以下のとおりです: