筆者は ShannonBase の開発者です。実際に手を動かして試せる内容にしていますが、そのつもりでお読みください。
この記事の対象
- MySQL で
GROUP BYを含む集計クエリが遅くて困っている - 分析用に ClickHouse や BigQuery へ流す構成を検討しているが、二重運用は避けたい
- とりあえず 15 分で挙動を確かめたい
ShannonBase とは
MySQL 8.4 互換の HTAP データベースです。MySQL 本体の Secondary Engine の仕組みを使って、列指向エンジン(Rapid/IMCS)を同一インスタンス内に持ちます。
大事なのはアプリ側の変更が要らないことです。接続先も、SQL も、コネクタもそのまま。テーブル単位で列指向のミラーを作るかどうかを ALTER で指定するだけです。
1. 起動する
docker run -d \
--name shannonbase \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=yourpassword \
shannondata/shannonbase:latest
接続は普通の MySQL クライアントで行けます。
mysql -h 127.0.0.1 -P 3306 -u root -p
SELECT VERSION();
-- 8.4.x
バージョン文字列が 8.4 系で返ります。ここが独自バージョンになっていないのは意図的で、既存のツールチェーン(マイグレーションツール、監視エージェント、ORM のバージョン判定)をそのまま通すためです。
2. データを入れる
TPC-H の lineitem を使うのが手軽です。ここでは簡略版のテーブルで説明します。
CREATE DATABASE bench;
USE bench;
CREATE TABLE orders (
o_orderkey BIGINT PRIMARY KEY,
o_custkey BIGINT NOT NULL,
o_orderstatus CHAR(1) NOT NULL,
o_totalprice DECIMAL(15,2) NOT NULL,
o_orderdate DATE NOT NULL,
o_orderpriority VARCHAR(15) NOT NULL,
KEY idx_date (o_orderdate)
) ENGINE=InnoDB;
データ投入は【要記入:データ生成手順 or サンプルダンプの URL】を参照してください。以下は 1,000 万行を入れた前提で進めます。
3. まず InnoDB のまま測る
SET SESSION use_secondary_engine = OFF;
SELECT o_orderpriority, COUNT(*), SUM(o_totalprice)
FROM orders
WHERE o_orderdate BETWEEN '1995-01-01' AND '1995-12-31'
GROUP BY o_orderpriority;
実行計画を見ておきます。
EXPLAIN FORMAT=TREE
SELECT o_orderpriority, COUNT(*), SUM(o_totalprice)
FROM orders
WHERE o_orderdate BETWEEN '1995-01-01' AND '1995-12-31'
GROUP BY o_orderpriority;
インデックスレンジスキャン+グルーピングになっているはずです。
4. 列指向ミラーを作る
ALTER TABLE orders SECONDARY_ENGINE = rapid;
ALTER TABLE orders SECONDARY_LOAD;
SECONDARY_LOAD はテーブル全体を列形式に変換してメモリに載せる処理なので、行数に応じて時間がかかります。完了後、ロード状況はこう確認します。
SELECT * FROM performance_schema.rpd_tables;
ロード後は、InnoDB 側への INSERT/UPDATE/DELETE が列側に自動で同期されます。バッチ再ロードは不要です。内部的には Redo Log と DML 通知の二重チャネルで追従しています。
5. もう一度測る
SET SESSION use_secondary_engine = ON;
EXPLAIN FORMAT=TREE
SELECT o_orderpriority, COUNT(*), SUM(o_totalprice)
FROM orders
WHERE o_orderdate BETWEEN '1995-01-01' AND '1995-12-31'
GROUP BY o_orderpriority;
実行計画に副エンジンへのオフロードが現れれば成功です。同じ SQL、同じ接続、同じアプリケーションコードのまま実行経路だけが変わります。
計測結果の例(【要記入:実測値。マシンスペックと my.cnf を必ず併記】)
| クエリ | InnoDB | Rapid |
|---|---|---|
| 上記の集計 | 【要記入】 | 【要記入】 |
オフロードされない場合、クエリは自動的に InnoDB にフォールバックします。結果は常に正しいですが、速度は出ません。EXPLAIN でオフロードの有無を確認するのが確実です。
6. ハマりどころ
メモリ不足で SECONDARY_LOAD が失敗する
列側は全量メモリ常駐です。テーブルサイズに対して十分な割り当てが必要です。まず一番重い 1 テーブルだけをロードして様子を見るのが安全です。
オフロードされない
すべての演算子が対応しているわけではありません。ウィンドウ関数や一部のサブクエリ形は InnoDB 側に落ちます。EXPLAIN FORMAT=TREE で確認してください。
行と列で結果が違う
あってはならない状態です。もし遭遇したら再現 SQL とスキーマを添えて Issue を立ててもらえると非常に助かります。行実行と列実行の意味論一致は最優先で扱っています。
現時点の制約
正直に書いておきます。
- 列指向側はメモリ常駐前提のため、データサイズはメモリ量に律速されます
- ネイティブな ANN ベクトルインデックスはありません。MySQL コミュニティ本体のベクトルインデックス実装を待つ方針です
- オフロード非対応の演算子があります
まとめ
MySQL 8.4 互換のまま、ALTER TABLE 2 行で列指向の分析経路が足せます。CDC パイプラインとスキーマの二重管理が要らない点が、既存の分析基盤構成に対する主な差分です。
リポジトリ: https://github.com/Shannon-Data/ShannonBase