INFRA

Turso(Rust製SQLite互換DB)を試した

ベータ版の Turso データベースを Windows + Python で触り、READMEに並ぶ「SQLite互換」「BEGIN CONCURRENT」「CDC」「Vector」を1つずつ実走した記録。

Turso という、SQLite を Rust で書き直した新しい組み込みDBが GitHub Trending に乗っていたので触ってみた。Tursoという会社が「Turso」という名前の DB を出した、という形。まだ ベータ版 で、READMEにも「production data 注意」と書いてある。

環境: Windows 11 / Python 3.12 / pyturso==0.6.1

1. SQLite 互換

同じ SQL を sqlite3(標準ライブラリ)と turso の両方で走らせて、結果が一致するかを見る。

#プローブsqlite3turso一致
1CREATE / INSERT / SELECTokokyes
2WHERE + LIKEokokyes
3JOINokokyes
4WITH RECURSIVE (CTE)okRecursive CTEs are not yet supportedNO
5json_extract(JSON1)okokyes
6FTS5 仮想テーブルokno such module: fts5NO
7ALTER TABLE … ADD COLUMNokokyes
8ALTER TABLE … DROP COLUMNokokyes

基本的な CRUD と JOIN と JSON1 と ALTER 系は通った。

引っかかったのは WITH RECURSIVEFTS5。両方とも sqlite3 側では動いたので、ここが現状の非互換ポイントということになる。

2. BEGIN CONCURRENT が動かなかった

BEGIN CONCURRENT は Turso が追加した機能で、「複数の書き込みを並列で進めていい」という命令。普通の SQLite の BEGIN は書き込みを直列化する(1つが書いている間、他のスレッドは待つ)ので、これが効けば書き込みスループットが上がる、というのが README の主張。MVCC(複数バージョンを内部に保持して並列処理を可能にする仕組み)を有効にしてから使う。

これは今回、pyturso からは動かせなかった。

ワークロード: 8 スレッド × 2000 INSERT を、それぞれ別テーブル(行コンフリクトなし)に。BEGIN を BEGINBEGIN CONCURRENT で切り替えて比較する。

Engine経過時間完了INSERT備考
sqlite3 (WAL, BEGIN)0.162s16000/16000エラーなし
turso BEGIN, MVCC off0.181s8000/16000database is locked で半数の worker が脱落
turso BEGIN CONCURRENT, MVCC off0.006s0/16000Concurrent transaction mode is only supported when MVCC is enabled
turso BEGIN CONCURRENT, MVCC on0.006s0/16000同じエラー

MVCC の有効化方法は README には載っていなくて、Turso のリポジトリの別ファイル(scripts/turso-mvcc-sqlite3)に「PRAGMA journal_mode = 'mvcc' で有効化する」と書いてあった。その通りに実行してから BEGIN CONCURRENT を呼んでも、同じ「MVCC is not enabled」というエラーが返ってくる。

PRAGMA 命令自体はエラーを出さずに通っているので、本当に有効になっているのか、それとも別の手順が必要なのか、README とサンプルコードを眺めた範囲では分からなかった。動かせなかった、というのが今回の結論。

ちなみに普通の BEGIN(concurrent ではない方)で走らせた場合も、半分のスレッドが「database is locked」のエラーで落ちる。普通の SQLite はこういう時に少し待ってから再試行する仕組みが入っているが、pyturso でそれをどう設定するのかも今回は調べきれなかった。

3. CDC は使い方が分からなかった

CDC(Change Data Capture)は、データベースの変更(行の追加・更新・削除)をリアルタイムで取り出せる機能。普通の SQLite には無く、Turso 側で追加された機能になる。

触ってみようとしたが、pyturso の中身を一通り眺めても、READMEの該当箇所を読み返しても、それらしい入り口が見当たらなかった。Rust や JS のバインディング側にはあるのか、まだ Python から触れる段階に来ていないのかは分からない。

4. Vector はちゃんと動いた

ベクトル検索が動くか、2次元の矢印4本で試す。コサイン距離は「2つの矢印の向きのズレ」を測るものなので、矢印を見れば並び順は事前に予想できる。

クエリのベクトル:[1, 0](→ 真横を向いた矢印)

テーブルに入れた4本:

idベクトル矢印クエリとの角度
1[1, 0]0°(クエリと同じ向き)
2[1, 1]45°
3[0, 1]90°
4[-1, 0]180°(真逆)

矢印を見れば、近い順は id 1 → 2 → 3 → 4 のはず。

SQL はこんな感じ:

cur.execute("CREATE TABLE v (id INTEGER PRIMARY KEY, e F32_BLOB(2))")
cur.execute("INSERT INTO v (id, e) VALUES (?, vector(?))", (1, "[1.0, 0.0]"))
# ... id 2, 3, 4 も同様に挿入 ...
cur.execute(
"SELECT id, vector_distance_cos(e, vector(?)) AS d FROM v ORDER BY d",
("[1.0, 0.0]",),
).fetchall()

結果:

id距離
14.47e-08(ほぼ 0)
20.2929
31.0
41.9999…

並びは予想通り。距離の値もコサイン距離の理屈と一致する(1 - cos(角度) で、0° → 0、45° → 約 0.293、90° → 1、180° → 2)。

F32_BLOB(N) という型と、vector(...) / vector_distance_cos(...) という関数で書ける。近似(ANN)インデックスはまだ使えなくて、これがないと大量のベクトル検索が遅くなるので実用的ではないらしい。README では roadmap に入っている。

触ってみて分かったこと

  • SQLite の文法と JSON1 と ALTER 系は概ね動く。WITH RECURSIVEFTS5 はまだ。
  • BEGIN CONCURRENT は、pyturso 0.6.1 から今回の手順では有効化できなかった。
  • CDC は Python バインディング側に窓口が見当たらなかった。
  • Vector は書けて、距離関数も期待通りの並びを返した。