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 の両方で走らせて、結果が一致するかを見る。
| # | プローブ | sqlite3 | turso | 一致 |
|---|---|---|---|---|
| 1 | CREATE / INSERT / SELECT | ok | ok | yes |
| 2 | WHERE + LIKE | ok | ok | yes |
| 3 | JOIN | ok | ok | yes |
| 4 | WITH RECURSIVE (CTE) | ok | Recursive CTEs are not yet supported | NO |
| 5 | json_extract(JSON1) | ok | ok | yes |
| 6 | FTS5 仮想テーブル | ok | no such module: fts5 | NO |
| 7 | ALTER TABLE … ADD COLUMN | ok | ok | yes |
| 8 | ALTER TABLE … DROP COLUMN | ok | ok | yes |
基本的な CRUD と JOIN と JSON1 と ALTER 系は通った。
引っかかったのは WITH RECURSIVE と FTS5。両方とも sqlite3 側では動いたので、ここが現状の非互換ポイントということになる。
2. BEGIN CONCURRENT が動かなかった
BEGIN CONCURRENT は Turso が追加した機能で、「複数の書き込みを並列で進めていい」という命令。普通の SQLite の BEGIN は書き込みを直列化する(1つが書いている間、他のスレッドは待つ)ので、これが効けば書き込みスループットが上がる、というのが README の主張。MVCC(複数バージョンを内部に保持して並列処理を可能にする仕組み)を有効にしてから使う。
これは今回、pyturso からは動かせなかった。
ワークロード: 8 スレッド × 2000 INSERT を、それぞれ別テーブル(行コンフリクトなし)に。BEGIN を BEGIN と BEGIN CONCURRENT で切り替えて比較する。
| Engine | 経過時間 | 完了INSERT | 備考 |
|---|---|---|---|
| sqlite3 (WAL, BEGIN) | 0.162s | 16000/16000 | エラーなし |
| turso BEGIN, MVCC off | 0.181s | 8000/16000 | database is locked で半数の worker が脱落 |
| turso BEGIN CONCURRENT, MVCC off | 0.006s | 0/16000 | Concurrent transaction mode is only supported when MVCC is enabled |
| turso BEGIN CONCURRENT, MVCC on | 0.006s | 0/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 | 距離 |
|---|---|
| 1 | 4.47e-08(ほぼ 0) |
| 2 | 0.2929 |
| 3 | 1.0 |
| 4 | 1.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 RECURSIVEとFTS5はまだ。 BEGIN CONCURRENTは、pyturso 0.6.1から今回の手順では有効化できなかった。- CDC は Python バインディング側に窓口が見当たらなかった。
- Vector は書けて、距離関数も期待通りの並びを返した。