12k
All articles

知っておく価値のある MariaDB の 5 つの機能

MariaDBの注目機能: ベクトル検索、システム版管理とアプリケーション時間テーブル、テーブル別ストレージエンジン、11.8 LTSのutf8mb4標準。

OpenReplay Team
OpenReplay Team
知っておく価値のある MariaDB の 5 つの機能

MySQL 8.0 を運用しているチームにとって、MariaDB で最も影響の大きい 5 つの機能は、組み込みのベクトル検索、システムバージョン管理テーブル (system-versioned tables)、アプリケーション時間期間 (application-time periods)、テーブル単位でのストレージエンジン選択、そして UCA 14.0.0 照合順序を伴う utf8mb4 のサーバーデフォルト化です。これらは MariaDB 11.6 以降で導入され、11.8 LTS 系列にも引き継がれています。

MySQL 8.0 環境でバージョンの判断を検討しているなら、MariaDB は選択肢のリストに加える価値があります。

以下では各機能を順に取り上げ、その機能が何をするのか、そして実際に入力する SQL を示します。バージョンの参照先は MariaDB 11.8 LTS と MariaDB 12.3 LTS で、これから導入するチームの多くがインストールするリリースです。

要点

  • MariaDB はコミュニティサーバー本体にベクトル類似検索を同梱しています。VECTOR(N) カラムと、改良版 HNSW アルゴリズムに基づく VECTOR INDEX が、拡張機能のインストールなしで利用できます。
  • MariaDB がベクトルインデックスを使うのは、ORDER BY がインデックス構築時のメトリックに一致する素の距離関数呼び出しであり、その後に LIMIT が続く場合のみです。距離関数が一致しない場合はフルテーブルスキャンにフォールバックします。
  • WITH SYSTEM VERSIONING と SELECT ... FOR SYSTEM_TIME AS OF を使えば、監査トリガーや影の履歴テーブルなしにポイントインタイムクエリが可能になります。
  • PERIOD FOR はテーブルに業務上の有効期間を宣言するもので、システムバージョン管理とアプリケーション時間期間の両方を宣言すると、そのテーブルはバイテンポラルになります。
  • デフォルト文字セットは MariaDB 11.6 以降 utf8mb4 となり、照合順序は UCA 14.0.0 に基づいています。11.8 はこれを搭載した最初の長期サポートリリースです。

MariaDB はどうやって拡張機能なしでベクトル検索を実現しているのか

MariaDB はコミュニティサーバー自体に埋め込みの保存と検索の機能を備えています。VECTOR(N) カラム、改良版 HNSW アルゴリズムを用いた VECTOR INDEX、そしてコサイン類似度とユークリッド距離の距離関数です。MariaDB Vector プロジェクトページ では 11.8 LTS で一般提供 (GA) となったとされており、VECTOR 型のリファレンス ではカラムの上限が 16,383 次元とされています。追加でインストールするものは何もなく、行データの隣に並んで徐々に同期がずれていく第二のデータストアも存在しません。

CREATE TABLE support_articles (
  id         BIGINT UNSIGNED PRIMARY KEY,
  tenant_id  INT NOT NULL,
  body       TEXT,
  embedding  VECTOR(768) NOT NULL,
  VECTOR INDEX (embedding) M=8 DISTANCE=cosine
) ENGINE=InnoDB;

768 は、広く使われているいくつかのオープンウェイトの文埋め込みモデルの出力幅に対応しています。使用するモデルが出力する次元数に合わせて設定してください。この DDL からは 2 つの制約を読み取っておく価値があります。インデックス対象のカラムは NOT NULL でなければならず、M は 3 から 200 までの値を取ります。値を大きくすると精度は上がりますが、インデックスサイズと書き込み速度を犠牲にします (create-table-with-vectors リファレンス を参照)。プロジェクトページには、テーブルあたりのベクトルインデックスは 1 つまでという制限も記載されています。

サーバーはベクトルを保持・検索しますが、生成はしません。したがって配列は埋め込みモデルから取得し、テキストとして投入します。

INSERT INTO support_articles (id, tenant_id, body, embedding)
VALUES (1, 17, 'Resetting a device token',
        VEC_FromText('[0.021, -0.113, 0.447, ...]'));

埋め込みが通常の InnoDB テーブル内に存在するため、WHERE 句と類似度によるランキングが単一のトランザクショナルなステートメントとして実行されます。データベースの脇に付け足したベクトルサービスでは、これに太刀打ちできません。最近傍探索を単一テナントの行に限定するのに、2 つのシステムをまたぐ join も、すでに取得コストを払った結果に対する後フィルタリングも不要です。

SELECT id, body
FROM support_articles
WHERE tenant_id = 17
ORDER BY VEC_DISTANCE_COSINE(embedding, VEC_FromText('[...]'))
LIMIT 10;

なぜベクトルインデックスがスキップされるのか

インデックスが使われるのは、クエリが素の距離関数呼び出しでソートし、かつインデックス構築時のメトリックを使用し、LIMIT で行数を制限している場合だけです。コサインで構築したインデックスに対してユークリッド距離関数でクエリを実行すると、リファレンスドキュメントが明記しているとおりインデックスは使えず、クエリはフルテーブルスキャンに退化します。

-- index above was built with DISTANCE=cosine
SELECT id, body
FROM support_articles
WHERE tenant_id = 17
ORDER BY VEC_DISTANCE_EUCLIDEAN(embedding, VEC_FromText('[...]'))
LIMIT 10;

汎用の VEC_DISTANCE は、ベクトル概要 に記載のとおり、基盤となるインデックスに応じてユークリッドかコサインに解決されるため、この落とし穴を回避できます。サポートされるメトリックはこの 2 つのみです。小さい LIMIT 値での再現率 (recall) が重要な場合、mhnsw_ef_search がインデックス検索で保持する候補数を設定します。デフォルトは 20 で、1 から 10000 まで設定可能です。LIMIT がそれより少ない件数を要求しても、検索はこの値を下回る件数を探索することはないため、値を上げると検索時間と引き換えに品質が向上します。

比較として、MySQL 8.0 には VECTOR 型がありません。ベクトル型は 9.x 系列で登場し、インデックスを用いたベクトル検索は HeatWave の機能として文書化されています。そこでは、頻繁にクエリされるベクトルカラムに対して HeatWave GenAI が自らインデックスを構築します。PostgreSQL では同じ役割を pgvector が担いますが、これはインストールして有効化する拡張機能です。

システムバージョン管理テーブル: 先週の火曜日の状態をどうクエリするか

システムバージョン管理テーブルは、各行の置き換えられた全バージョンをテーブル自身の中に保持します。そのため、ポイントインタイムの読み取りは、自前で維持管理する履歴テーブルに書き込む監査トリガーではなく、通常の SELECT に付ける句になります。古いバージョンが現行のものと同居しているので、任意の過去時点でのテーブルの状態を読み取り、何が変わったかを追跡し、2 つの日付を並べて比較できます。

CREATE TABLE subscription (
  account_id  BIGINT PRIMARY KEY,
  plan        VARCHAR(32),
  seats       INT
) WITH SYSTEM VERSIONING;

SELECT account_id, plan, seats
FROM subscription
FOR SYSTEM_TIME AS OF TIMESTAMP '2025-11-04 09:00:00'
WHERE account_id = 4021;

これがこの機能のすべてです。履歴は FOR SYSTEM_TIME を指定したときに返され、システムバージョン管理テーブルのリファレンス には、クエリ形式として AS OF、BETWEEN、FROM ... TO、ALL が記載されています。明示的な DDL 形式では GENERATED ALWAYS AS ROW START と ROW END カラムを PERIOD FOR SYSTEM_TIME とともに宣言します。上記の短縮形は、同じ情報を ROW_START と ROW_END という擬似カラムの背後に格納します。InnoDB では、BIGINT UNSIGNED の row-start / row-end カラムを使ってトランザクション単位でバージョン管理し、FOR SYSTEM_TIME AS OF TRANSACTION で読み取ることもできます。MariaDB 自身の 差異に関するドキュメント では、テンポラルデータテーブルは MySQL に対応機能がない capability の 1 つとして挙げられています。

業務上の有効期間を表すアプリケーション時間期間

システムバージョン管理はデータベースがいつその情報を伝えられたかを記録し、アプリケーション時間期間はその事実が実際にいつ真であったかを記録します。アプリケーション時間期間 は、同じ型と幅を持つ 2 つの時間カラムによって区切られる区間であり、サーバーレベルではなくアプリケーションレベルでデータをバージョン管理します。有効期間ウィンドウを持つ価格が典型例です。

CREATE TABLE price_list (
  sku        VARCHAR(32),
  price      DECIMAL(10,2),
  valid_from DATE,
  valid_to   DATE,
  PERIOD FOR validity(valid_from, valid_to),
  UNIQUE (sku, validity WITHOUT OVERLAPS)
);

UPDATE price_list FOR PORTION OF validity
  FROM '2026-01-01' TO '2026-04-01'
  SET price = 18.00
WHERE sku = 'KB-114';

期間を宣言すると、両方のカラムが強制的に NOT NULL になり、最初の値が 2 番目の値より前であるというチェックが暗黙のうちに追加されます。主キーまたはユニークキーに付けた WITHOUT OVERLAPS は、期間が衝突する行を拒否します。この句は MariaDB 10.5.3 から文書化されています。期間そのものは FOR PORTION を含めてそれより前の MariaDB 10.4.3 で導入されました。1 つのテーブルに期間とシステムバージョン管理の両方を宣言すると バイテンポラルテーブル になり、同じ行に対して両種のバージョン管理が同時に働きます。これこそが、「火曜日時点で誤っていた価格」と「単に入力が遅れただけの価格」を区別するものです。

テーブルごとにストレージエンジンを選べるのか

MariaDB はストレージエンジンをテーブル単位で設定するため、トランザクショナルなテーブルは InnoDB のままにしつつ、同じスキーマ内の他のテーブルには別のエンジンを使えます。標準的なエンジン群に加えて、差異に関するドキュメントでは、分散分析処理向けの ColumnStore、MyRocks、クラウドアーカイブ向けの S3 エンジン、MyISAM の代替としての Aria、さらに CONNECT、SEQUENCE、Spider、SphinxSE、FederatedX、OQGRAPH が挙げられています。

CREATE TABLE event_archive (
  id   BIGINT PRIMARY KEY,
  body TEXT
) ENGINE=Aria;

これらのいくつかはサーバーに組み込まれてコンパイルされているのではなく、別個のプラグインパッケージとして提供されます。そのため、単に ENGINE= 句を書くだけで十分と決めてかかる前に、インストールするリリースについて該当エンジンのドキュメントを確認してください。

utf8mb4 のデフォルト化と新しい照合順序

MariaDB は 11.6 でサーバーのデフォルト文字セットを latin1 から utf8mb4 に変更し、同時に照合順序を UCA 14.0.0 に更新しました。長期サポートリリース間でアップグレードする場合、この両方が揃うのは 11.8 であり、2025 年 6 月 8 日の 11.8 LTS リリース告知 はこれらを当該リリースの一部として紹介しています。これは、MariaDB が絵文字より前の時代に遡る自前のデフォルトを引退させたということであって、デフォルト設定において MySQL を追い抜いた瞬間というわけではありません。アップグレード後も影響が残るのは照合順序の側です。ソート順と比較は MySQL よりも新しい Unicode 照合アルゴリズムに従うため、両者の出力を比較する場合はソート結果の突き合わせをしておく価値があります。

MariaDB の機能と導入リリース

機能できることMariaDB での提供状況
ベクトル検索VECTOR(N) に埋め込みを保存し、VECTOR INDEX でインデックス化、1 つのステートメントでフィルタリングとランキングVECTOR 型は 11.7.1 で追加、11.8 LTS で GA、12.3 LTS にも搭載
システムバージョン管理テーブル過去のタイムスタンプまたはトランザクション時点の状態でテーブルを読み取る11.8 および 12.3 LTS リリースで利用可能
アプリケーション時間期間業務上の有効期間ウィンドウをモデル化し、その一部区間を更新する期間と FOR PORTION は 10.4.3 から、WITHOUT OVERLAPS は 10.5.3 から、現行 LTS に搭載
バイテンポラルテーブル1 つのテーブルでシステム時間と業務時間の両方によるバージョン管理現行 LTS に搭載
utf8mb4 デフォルト、UCA 14.0.0サーバー設定の変更なしで Unicode を利用11.6 からデフォルト、これを搭載した最初の LTS は 11.8

覚えておく価値のあるアップグレード上の注意点が 1 つあります。11.8 のリリース投稿によれば、TIMESTAMP の範囲拡張はシステムバージョン管理テーブルを使用していない限りデータ変換を必要としないとされており、内部のタイムスタンプ表現が変わったため、これらのテーブルが唯一の既知の複雑要因として挙げられています。

この 5 つのうち、すでに抱えている課題に対応するものを 1 つ選んでください。それが監査履歴であれば、使い捨てのテーブルを WITH SYSTEM VERSIONING で作成し、行を 2 回変更して FOR SYSTEM_TIME AS OF で読み戻してみてください。それが、これまで維持してきたトリガーを置き換えられるかどうかは、数分で分かるはずです。

FAQ

すでに存在するテーブルに対してシステムバージョン管理を有効にできますか?

はい。ALTER TABLE t ADD SYSTEM VERSIONING で既存テーブルに対して有効化でき、ALTER TABLE t DROP SYSTEM VERSIONING で削除できますが、その場合は全履歴が削除されます。どちらもテーブルを再構築するため、大きなテーブルでは時間がかかることがあります。その後のスキーマ変更は system_versioning_alter_history の設定に依存します。ERROR の場合、バージョン管理されたテーブルの変更は失敗します。KEEP の場合、変更は成功しますが、履歴クエリでは新しいテーブル構造が表示されます。

システムバージョン管理テーブルが際限なく肥大化するのを防ぐにはどうすればよいですか?

文書化された選択肢が 3 つあります。DELETE HISTORY ステートメントで刈り込む方法 (DELETE HISTORY 権限が必要)、SYSTEM_TIME でパーティション分割して履歴パーティションを削除する方法 (現行パーティションや唯一の履歴パーティションは削除できない点に注意)、あるいはシステムバージョン管理を削除して再追加する方法 (テーブル再構築のコストと引き換えに履歴がクリアされます)。TRUNCATE TABLE では目的を果たせません。履歴を保護するため、サーバーはエラー 4137 でこれを拒否します。

MariaDB で 1 つのベクトルカラムにコサインとユークリッドの両方のインデックスを張れますか?

いいえ。ベクトルインデックスは単一の距離関数用に構築され、有効な値はコサインとユークリッド (デフォルト) です。異なる距離関数を使った検索ではそのインデックスを利用できません。また MariaDB はテーブルあたり 1 つのベクトルインデックスしか許可しないため、2 つ目のメトリックに対応するには、インデックスを並べて追加するのではなく、既存のインデックスを削除して別の DISTANCE 値で再構築する必要があります。

MariaDB 11.8 の utf8mb4 デフォルト化は、古いサーバーへのレプリケーションに影響しますか?

はい。MariaDB 11.6 でデフォルト文字セットが latin1 から utf8mb4 に、デフォルト照合順序が utf8mb4_uca1400_ai_ci に変更され、11.8 はこの変更を搭載した最初の長期サポートリリースです。古いリリースにはその照合順序が存在しないため、サーバーを従来のデフォルトに戻して設定しない限り、MariaDB 11.8 のプライマリから MariaDB 10.6 のレプリカへのレプリケーションはできません。

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — self-hosted, with full data ownership.

Star on GitHub

We use cookies to improve your experience. By using our site, you accept cookies.