OrioleDB は小規模DBでも OLTP に強い

この記事は [PostgreSQL Advent Calendar 2024](https://qiita.com/advent-calendar/2024/postgresql) と [SRA Advent Calendar 2024](https://qiita.com/advent-calendar/2024/sra) の 12月 12日の記事です。
その後、[OrioleDB について続きの記事](https://qiita.com/harukat1232000/items/1a241d6c924331bb7b23)も書きました。

### OrioleDBとは

[OrioleDB](https://github.com/orioledb/orioledb) は PostgreSQL開発者でもある Alexander Korotkov 氏が開発する新たな OSSデータベースソフトウェアです。PostgreSQL へのパッチと拡張モジュールという形で開発されていて、バッファ管理、データ格納、WAL の実装を置き換えています。 OrioleDB についての基本的な説明とインストール手順は別の記事「[OrioleDB を触ってみる](https://qiita.com/harukat1232000/items/90ed5febc48c061cd8b0)」に書きましたので参照ください。

### 本記事のテーマ：新DBの恩恵は大スペックマシンだけ？

近年新たにデータベースソフトウェアを開発される動機として、既存データベースソフトウェアのハードウェアスケーラビリティに対する不満ということがあります。従来製品では、多コア、大メモリ、磁気ディスク以外の永続ストレージでのスケールアップにうまく対応できていない、という主張です。

[OrioleDBのサイト](https://www.orioledb.com/)でも優れたハードウェアスケーラビリティが謳われています。読み書きトランザクションのベンチマークでネイティブ PostgreSQL が10万TPSであるところ、OrioleDBで40万TPS出しています。

ここで気になるのは、OrioleDB を使う価値があるのは、大スペックのマシンを使って、巨大なワークロードを相手にするときだけなのかという点です。今回は、小規模マシンで、OrioleDB は性能向上するのか？ という検証をしてみました。性能比較に使うのは OLTP（オンライントランザクション処理）のワークロードです。OLAP（オンライン分析処理）を速くする手段はサーバ分割が適用しやすいために沢山あるのですが、OLTP を速くしようと思うとすぐに行き詰ります。切実に解決策が必要とされているのは OLTP の高速化です。

### 今回の検証環境

手元PC上につくった virtual Box 仮想マシン（vCPU 4個、メモリ 8GB、Rocky Linux 8.x）を使いました。OrioleDB は PostgreSQL 17.x ベースで構築しました。使用したソフトウェアは以下の通りです。

 * PostgreSQLパッチバージョン [patches17_4](https://github.com/orioledb/postgres/releases/tag/patches17_4)
 * OrioleDBバージョン [beta6](https://github.com/orioledb/orioledb/releases/tag/beta6)

ビルド手順は「[OrioleDB を触ってみる](https://qiita.com/harukat1232000/items/90ed5febc48c061cd8b0)」記事と同じです。違いとしては、本バージョンの OrioleDB ではデータを S3 に格納する機能が追加されたのでリグレッションテストむけに S3 のセットアップをしておかないと関連するテストが失敗することです。以下で行う検証では S3 機能は使わないのでこの失敗は無視することにします。

ビルドした PostgreSQL は テーブルアクセスメソッドに orioledb を使わなければ、ネイティブ PostgreSQL と変わりませんので、これを OrioleDB、PostgreSQL の両方のベンチマークに使います。

postgresql.conf には以下の設定を与えます。アーキテクチャが違うため同一と言えるかは難しいところですが、PostgreSQLとOrioleDB でバッファサイズを同じにしています。

````
shared_buffers = 2048MB
wal_buffers = 32MB
checkpoint_completion_target = 0.9
logging_collector = on
orioledb.main_buffers = 2048MB
orioledb.free_tree_buffers = 256MB
orioledb.catalog_buffers = 32MB
orioledb.undo_buffers = 32MB
orioledb.checkpoint_completion_ratio = 0.9
````

PostgreSQL用データベースと OrioleDB用データベースを作り、後者のデータベースには以下のようなコマンドを実行しました。

````
db1=# CREATE EXTENSION orioledb ;
db1=# ALTER DATABASE db1 SET default_table_access_method TO orioledb;
````

これによりベンチマークツールで自動的に作成されるテーブルが、orioledbアクセスメソッドを使ったテーブルになります。

なお、OrioleDB にはデータ圧縮機能がありますが、今回は使用していません。

### ベンチマーク

ベンチマークの設計としては、データはバッファ上に全て載る前提での同時実行性とWAL書き込み性能を見ることを意図しています。
以下にベンチマーク結果を示します。今回は手抜きで、同水準で複数回実行をしていませんので、結果のバラつき度合いは確認できていません。

#### pgbench

以下は pgbench の結果です。標準のシナリオをユーザ定義SQL関数で記述して、それを呼び出すトランザクションを実行しています。OrioleDB に「トランザクションは関数定義してワンショットで呼び出さなければならない」という制限はありません。SQLコマンド文字列の解析など PostgreSQL と共通する部分の処理負荷を小さくして、差異があらわれやすくする狙いで、このようにしました。スケールは 10倍で、これは対象データが全てバッファに載るサイズです。

![orioledb_pgbench.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152412/6b7334c0-1710-6520-7d94-5c787b053e2c.png)

同時接続数 64 では同等性能で、若干 PostgreSQL（グラフでは vanilla PG17 と記載） の方が速いくらいですが、同時接続数が増えていくにしたがい、OrioleDB が優越する結果となりました。TPS (時間あたりトランザクション数）で見たとき、1024接続で 2倍程度の性能差が出ました。

#### TPC-C

[HammerDB](https://github.com/TPC-Council/HammerDB) による TPC-C ベンチマークもやってみました。PostgreSQL/OrioleDB のパラメータは pgbench のときと同じで、TPC-C の各種パラメータは基本的に HammerDB のデフォルトのままとしています。単位の NOPM は「分あたりのオーダー処理件数」です。TPC-C ではオーダー以外のトランザクションも若干実行されますが、それらはこの結果には含めてないということです。Virtual Users は想定ユーザ数を意味し、多いほど並列実行が増える指標です。warehouse数によるスケール指定は 1倍で、全データがバッファに載るサイズです。

![orioledb_hammerdb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152412/9126c02f-7d58-329c-2f8b-dcb576892632.png)

TPC-C の結果も似た傾向といえます。同時実行数が少ないときには OrioleDB と PostgreSQL の差異はなく PostgreSQL の方がやや速いくらいですが、同時実行数が増えていくと、OrioleDB 性能が２倍以上となっています。

#### PostgreSQL 16 → 17 でも速くなっている

ここまでネイティブの PostgreSQL 17 と OrioleDB を比較してきましたが、PostgreSQL 16 から 17 のバージョンアップでも、同時接続数が多いときの OLTP 性能は以下のように向上しています。したがいまして、PostgreSQL 16.x 以前を OrioleDB に置き換える場合、性能向上はさらに劇的なものとなるはずです。

![pgbench_PG16_17.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152412/4f4eb477-983b-d976-bdc9-d7e225e4e80d.png)
（出典：[SRA OSS Tech-Blog - PostgreSQL 17検証報告](https://www.sraoss.co.jp/tech-blog/pgsql/pg17report/)）

なお、この「WAL挿入の排他制約改善」による PostgreSQL 16 → 17 の性能向上は、OrioleDB over PG16 → OrioleDB over PG17 の性能向上には寄与しません。改良された部分は OrioleDB で差し替えられている部分であるからです。

#### サーバ負荷にはどうあらわれる？

OrioleDB と PostgreSQL はサーバリソースをそれぞれどのように使用しているのでしょうか。以下表は、 今回の pgbench 実行で 同時接続数 1024 で負荷をかけたときの vmstat 出力の（序終盤を適当に切り捨てた）平均値です。一番右に大小比較した列を追記しています。

| |OrioleDB |PostgreSQL|(大小)|
|--|--|--|--|
|r |5.3 |27.2|<<|
|b |0.6 |0.4|>|
|swpd |0.0 |0.0|=|
|free |2814626.7 |1905585.8|>|
|buff |2708.0 |2708.0|=|
|cache |4658609.8 |3074567.0|>|
|si |0.0 |0.0|=|
|so |0.0 |0.0|=|
|bi |0.1 |0.8|<|
|bo |13385.6 |5726.8|>|
|in |23264.5 |21885.3|≒|
|cs |40302.7 |41360.3|≒|
|CPU:us |40.3 |57.0|<|
|CPU:sy |33.5 |37.4|<|
|CPU:id |21.5 |5.0|>>|
|CPU:wa |4.8 |0.4|>>|
|CPU:st |0.0 |0.0|=|

r と CPU:* から CPU使用について比較すると、PostgreSQLの方が CPU を多く使っていて、CPU飽和に近い状態であることが分かります。OrioleDB は CPU に余力が沢山あります。それでいて b や CPU:wa (CPU I/O wait) が殊更に多いわけではありませんので、ストレージI/O 待ちで CPU が使えていないというわけではなく、少ないサーバリソース消費でトランザクションをより多く処理できている、と解釈できます。

メモリも cache を多く取っている一方で free が大きいですので、OrioleDB での実行時の方が、メモリリソースに余裕を残しているように見えます。

bo は OrioleDB が大きくなっています。WAL書き出しの競合が少ないので、より速くWALを書き出すことができて、それで時間あたりのストレージ書き出し量が増えた結果と解釈できそうです。

### まとめ

ということで本記事では OrioleDB をその辺にありそうな小規模マシンで OLTP のベンチマークをしてみました。OrioleDB は小規模ワークロードでも、ネイティブの PostgreSQL よりも優れた OLTP性能を出す、という結果になりました。

[機能上の制限事項](https://github.com/orioledb/orioledb/blob/beta6/doc/usage.md#current-limitations)（他に[これ](https://github.com/orioledb/orioledb/blob/beta6/doc/usage.md#collations)も）が問題ないケースであれば、PostgreSQL に代えて OrioleDB を導入することは、損の少ない選択肢といえます。もちろん「周りの皆が使っていない」「情報が少ない」「サポートしてくれる人、構築してくれる人が少ない」といったことはあるのですが。