OceanBaseデータベースにおいて、テーブルは最も基礎的なデータストレージユニットです。テーブルには、すべてのユーザーがアクセス可能なデータが含まれており、各テーブルは複数の行で、そして各行は複数の列で構成されています。各テーブルの設計と運用は、業務要件に基づいて適切に計画する必要があり、システムの効率性と拡張性を確保するために不可欠です。
テーブルタイプ
OceanBaseデータベースでサポートされているテーブルタイプには、パーティションテーブル、レプリケーションテーブル、主キーテーブル、主キーのないテーブル、外部テーブルなどがあります。
- パーティションテーブル:OceanBaseデータベースでは、通常のテーブルのデータを一定のルールに従って複数のブロックに分割し、同一ブロックのデータを物理的にまとめて保存することができます。このようにパーティションブロックに分割されたテーブルは、パーティションテーブルと呼ばれます。OceanBaseデータベースの基本的なパーティション戦略には、範囲(Range)パーティション、リスト(List)パーティション、ハッシュ(Hash)パーティションが含まれます。
- レプリケーションテーブル:レプリケーションテーブルは、OceanBaseデータベースにおける特殊なテーブルです。このテーブルは、任意の「正常」なレプリカでデータの最新の変更を読み取ることができます。
- 主キーテーブルと主キーのないテーブル:主キーテーブルとは主キーを含むテーブルのことです。主キーが指定されていないテーブルは主キーのないテーブルと呼ばれます。
- 外部テーブル:データベース内のテーブルデータはデータベースのストレージ領域に格納されますが、外部テーブルのデータは外部ストレージサービスに格納されます。
- ヒープテーブル:ヒープ構成のテーブルモードで、主キーは一意性制約のために使用され、クエリは主テーブルに依存します。ユーザーのデータが時間順に並べ替えられた場合、Skip Indexを使用することでクエリ効率をより効果的に向上させることができます。
APシナリオ において、OceanBaseは多様なテーブルタイプをサポートしています。TPシナリオ で一般的な レプリケーションテーブル、パーティションテーブル、主キーテーブル、主キーのないテーブル に加えて、データのストレージ方式、すなわち行指向か列指向かによって、新たなテーブルタイプとして カラムストアテーブル、行列混在テーブル が導入されています。
カラムストアテーブル:カラムストアテーブルは、データを行ではなく列単位で格納するため、分析クエリのパフォーマンスを大幅に向上させることができます。特に、大量のデータや集約分析を頻繁に行うシナリオに適しています。詳細については、カラムストアテーブルのアーキテクチャを参照してください。
行列混合ストレージテーブル:行指向と列指向の両方のデータを別々に格納し、システムがクエリステートメントに基づいて行指向または列指向のどちらがパフォーマンス的に優れているかを自動的に判断します。トランザクション系の業務と分析系の業務が混在するシナリオに適しています。
テーブルの更新モード
OceanBaseデータベースでは、テーブル作成時にデータの書き込みモードとクエリモードを指定できます。テーブル作成時、CREATE TABLE文のmerge_engineパラメータによってdelete_insert更新モードとpartial_update更新モードを選択します。これら2つのモードは、異なるビジネスシナリオに合わせて設計されたデータ更新戦略です。
delete_insert(全列更新モード)
クエリ性能を優先するモードです。「Merge-On-Write」という仕組みにより、
UPDATE操作を全列データのDELETEとINSERTに変換し、各行が常に全列のデータを持つようにします。このモードは、複雑なクエリやバッチ処理(分析系のタスクなど)の効率を大幅に向上させます。ただし、増分データの保存に余分なストレージ容量が必要となるため、増分データの更新が頻繁で、かつ高速な分析が求められるシナリオに適しています。partial_update(部分更新モード)
変更された列の値のみを記録することで、冗長なデータ保存を回避します。クエリ時には複数のバージョンのデータをマージして最新の値を取得する必要があるため、クエリ性能は相対的に低くなります。しかし、更新頻度は高いがクエリの要求は低いシナリオ(OLTP系の業務など)や、ストレージコストを抑えたい環境に適しています。
| 特性 | delete_insert更新モード | partial_update更新モード |
|---|---|---|
| ストレージ方式 | 更新のたびに、SSTableに全列データを含む2行(DELETEとINSERT)を書き込む。 |
更新のたびに、変更された列の値のみを記録するため、ストレージ容量を節約できる。 |
| クエリ効率 |
|
クエリ実行時に、複数のMemtableやSSTableのレコードをマージして主キーの最新値を取得する必要があるため、性能に影響が出る可能性がある。 ストレージコストを重視し、更新処理が頻繁なシナリオに適している。 |
| 適用シナリオ | 増分データの割合が高く、複雑なクエリやバッチ処理による分析を頻繁に実行するシナリオ。 | 更新頻度は高いが、クエリの要求は低いシナリオ。 |
詳細については、MySQLモードでのテーブル作成およびOracleモードでのテーブル作成をご参照ください。
データの分散
OceanBaseデータベースは、パーティションテーブルを作成することでデータを複数のパーティションに分散し、各パーティションのデータを異なるマシンに分散します。クエリ時にはパーティションプルーニングを利用することで、スキャンするデータ量を減らし、複数マシンリソースを活用してクエリのパフォーマンスを向上させることができます。デフォルトでは、異なるテーブル間のデータはランダムに分散されており、直接的な関係はありません。ロードバランシングによって、一つのテーブルのデータをクラスタ全体に均等に分散させることが可能です。
分散型APシステムでは、テーブルのデータ量は多くなる傾向があります。異なるテーブルのデータがランダムに分散されている場合、テーブル結合時のデータ転送のオーバーヘッドは無視できないことが多いです。テーブルグループ(Table Group)を利用すると、同じパーティション方式を持つパーティションテーブル同士のデータを特定の規則で揃えることができ、関連するデータを同一ノードに集約できます。これにより、関連するデータが同一のマシンに集約され、これらのテーブルを結合する際にPartition Wise Join方式で実行できるようになり、結合シナリオにおけるデータ転送のオーバーヘッドを効果的に削減し、パフォーマンスを向上させることができます。
OceanBaseは、パーティションテーブルとコンポジット・パーティションテーブルをサポートし、範囲(Range)パーティション、リスト(LIST)パーティション、ハッシュ(HASH)パーティションの3つのパーティショニングタイプをサポートしています。
OceanBaseは、3種類のプロパティを持つテーブルグループを提供します:
NONE:テーブルグループ内のすべてのテーブルのすべてのパーティションは、同じマシンに集約されます。
PARTITION:テーブルグループ内の各テーブルのデータは、パーティションごとに分散されます。コンポジット・パーティションテーブルの場合、パーティションの下にあるすべてのサブパーティションは一緒に集約されます。
ADAPTIVE:テーブルグループ内の各テーブルのデータは、適応型方式で分散されます。テーブルグループ内のテーブルがパーティションテーブルの場合、パーティションごとに分散されます。テーブルグループ内のテーブルがコンポジット・パーティションテーブルの場合、各パーティションのサブパーティションごとに分散されます。
詳細は、データの分散、MySQLモードのテーブルグループ、および Oracleモードのテーブルグループを参照してください。
インデックスタイプ
インデックスは、クエリのパフォーマンスを向上させるための重要なコンポーネントです。OceanBaseは、APシーンにおいて、複数のインデックスタイプをサポートすることで、ユーザーに柔軟かつ効率的なデータ検索方法を提供します。以下は、一般的なインデックスタイプとその適用シナリオです:
- ローカルインデックス:ローカルインデックスは、単一のパーティションに対して作成されるインデックスです。検索対象が特定パーティションに限定するシナリオに適しています。データが厳密に複数のパーティションに分割されている場合、ローカルインデックスを使用することで、クエリ時のデータスキャン範囲を大幅に削減できるため、クエリの効率を向上させることができます。
- 一意インデックス:一意インデックスは、データ列内の各値が一意であることを保証します。特定の列に一意インデックスを作成することで、データベースはデータの重複を効果的に防止し、クエリ処理の高速化を実現できます。
- 非一意インデックス:非一意インデックスは一意インデックスとは異なり、列内のすべての値が一意である必要はありません。主にデータクエリを高速化するために使用され、特に特定の条件に合致する複数のレコードを検索する場合、検索効率を大幅に向上させることができます。
- 全文インデックス:OceanBaseは、MySQLと互換性のある全文検索機能をサポートしており、テキストコンテンツを事前に処理してキーワードインデックスを作成することで、全文検索の効率を効果的に向上させます。全文インデックスの詳細については、全文インデックスを参照してください。
- JSON複数値インデックス:OceanBaseデータベースのMySQLモードは、複数値インデックス機能をサポートしており、これはJSONドキュメントやその他の集合型データに特に役立ちます。この機能を利用することで、配列または集合にインデックスを作成でき、JSON配列の要素に基づく検索クエリの効率を向上させることができます。複数値インデックスの詳細については、 複数値インデックスを参照してください。
- 空間インデックス:空間インデックスは、地理空間データのクエリ効率を最適化するために使用され、地理情報システム(GIS)や位置情報サービスで広く利用されています。これらのアプリケーションにおいて、空間インデックスは地理座標範囲内のデータ情報を迅速に検索し、位置情報サービスを強力にサポートします。
- カラムストア・インデックス:HTAP (Hybrid Transactional and Analytical Processing)シナリオにおいて、OceanBaseデータベースはバージョンV4.3.0以降、テーブル作成時にストレージ形式をカラムストアとして指定することをサポートしています。インデックスもテーブルと同様に管理されるため、インデックスを列指向で格納することが可能です。カラムストア・インデックスは、行ではなく列に基づいてデータを格納するため、特に大規模データ処理において、分析クエリのパフォーマンスを大幅に向上させることができます。これにより、データ検索と分析にかかる時間を大幅に短縮し、リアルタイム分析を実現できます。カラムストアの詳細については、カラムストアを参照してください。
インデックスの詳細については、MySQLモードのインデックスの概要および Oracleモードのインデックスの概要を参照してください。
データ型
テーブルの作成と使用の前に、データベース管理者はビジネスニーズに基づいてテーブル構造とデータ型を適切に計画する必要があります。データストレージの効率とクエリの最適化を確保するため、管理者は以下の原則に従う必要があります:
- テーブル構造の正規化:テーブル構造を適切に設計することで、データの冗長性を最小限に抑え、クエリのパフォーマンスを向上させます。
- 適切なSQLデータ型の選択:各列に対して最適なSQLデータ型を選択することで、ストレージ容量を削減し、クエリの速度を向上させます。
一般的なSQLデータ型には、以下のようなものがあります:
- 基本データ型:例えば、
INT、VARCHAR、DATEなどがあります。 - 複合データ型:例えば、
JSON、ARRAY、BITMAPなど、より複雑なデータ構造を格納するのに適しています。
詳細なSQLデータ型については、以下を参照してください:
ビュー
OceanBaseデータベースは、標準ビューとマテリアライズドビューをサポートしています。
- 標準ビュー(Standard Views):標準ビューは、非マテリアライズビューとも呼ばれ、最も一般的なビューのタイプです。これらは、ビューを定義するSQLクエリのみを格納し、クエリ結果は格納しません。
- マテリアライズドビュー(Materialized Views):マテリアライズドビューは標準ビューとは異なり、物理的なストレージ上にクエリ結果を格納します。OceanBaseデータベースは非同期マテリアライズドビューをサポートしています。つまり、ベーステーブルのデータが変更されても、マテリアライズドビューはすぐに更新されず、ベーステーブルのDML操作の実行パフォーマンスが維持されます。MySQLモードでのマテリアライズドビューおよび Oracleモードでのマテリアライズドビューを参照してください。
データテーブルの作成例
パーティション、カラムストア、および行ストアインデックスを含むテーブルを作成する
CREATE TABLE salesdata (
sale_id INT,
product_id INT NOT NULL,
saledate DATE NOT NULL,
saledate_int INT, -- 通常の列として定義
quantity INT,
price DECIMAL(10, 2),
customer_id INT,
PRIMARY KEY (sale_id, saledate_int) -- 主キーは通常の列を含めることができます
)
PARTITION BY RANGE COLUMNS (saledate_int) (
PARTITION p2023_q1 VALUES LESS THAN (202304),
PARTITION p2023_q2 VALUES LESS THAN (202307),
PARTITION p2023_q3 VALUES LESS THAN (202310),
PARTITION p2023_q4 VALUES LESS THAN (202401)
)
WITH COLUMN GROUP(each column);
CREATE INDEX idx_product_id ON salesdata(product_id);
CREATE INDEX idx_customer_id ON salesdata(customer_id);
パーティション:
salesdataテーブルはRANGEパーティションを使用しています。PARTITION BY RANGE COLUMNS (saledate_int):saledate_int列を基準にパーティショニングを行います。4つのパーティションを定義しました:
p2023_q1パーティションには、202304より前のすべてのデータ(つまり、2023年第1四半期)が含まれています。p2023_q2、p2023_q3およびp2023_q4パーティションは、2023年の第2四半期、第3四半期および第4四半期のデータをそれぞれ含みます。
カラムストア:
WITH COLUMN GROUP(each column);により カラムストア が指定されました。これらの列のデータはラムストア方式で格納され、大規模なデータ分析のシナリオに適しています。行ストアインデックス:それぞれ
product_id列とcustomer_id列に、idx_product_idとidx_customer_idの2つのインデックスを作成しました。行ストアインデックスは、特定の列に基づくクエリ、特に高頻度で発生する小規模なクエリを高速化できます。
カラムストアテーブルを作成して使用する際に大量のデータをインポートした場合は、読み込みパフォーマンスを向上させるために一度マージ操作を実行し、統計情報収集を行い、実行戦略を調整する必要があります。
マージ操作:データを一括インポートした後は、一度マージ操作を実行することを推奨します。これはマージ操作により断片化されたデータが整理され、物理ストレージ上でより連続的にすることで、読み取り時のディスクI/Oが削減され、読み取りパフォーマンスの向上に役立ちます。データインポート後、テナント内でマージ操作を実行し、すべてのデータがベースライン層にマージされるようにしてください。操作の詳細については、MAJORおよびMINOR (MySQLモード)および MAJORおよびMINOR (Oracleモード)を参照してください。
統計情報収集:マージ操作が完了した後は、統計情報の収集を行うことを推奨します。これは、オプティマイザーが効果的なクエリプランと実行戦略を生成するために非常に重要です。GATHER_SCHEMA_STATS (MySQLモード) /GATHER_SCHEMA_STATS (Oracleモード)を実行することで、すべてのテーブルに対して統計情報の収集を行うことができます。また、GV$OB_OPT_STAT_GATHER_MONITOR (MySQLモード)および GV$OB_OPT_STAT_GATHER_MONITOR (Oracleモード)ビューを通して収集進捗をモニタリングすることができます。
注意点として、カラムストアテーブルのデータ量が増加するにつれて、マージ操作の速度が低下する可能性があります。