# SQLiteがバイトコードを使用する理由 - 技術要約
## 概要
すべてのSQLデータベースエンジンは、入力されたSQLテキストを「プリペアドステートメント」に変換してから実行するという共通のアプローチを取る。プリペアドステートメントの実装方法として、主に2つの手法が存在する:
1. **バイトコード方式**:SQLiteが採用。SQLを仮想マシン言語に変換し、仮想マシンインタープリターで実行
2. **オブジェクトツリー方式**:MySQLやPostgreSQLが採用。SQLを処理を表すオブジェクトツリーに変換し、ツリーを辿って実行
## 技術的定義
### SQLiteのバイトコード
SQLiteのバイトコードは、従来のJavaVMやWebAssemblyとは異なり、データベース特有の高レベル操作を含む:
- **OP_Column**:特定のカーソルが指すデータベース行のN番目の列から値を抽出
- **OP_CreateBtree**:データベースファイル内に新しいB-Treeの領域を割り当て
- **OP_ParseSchema**:sqlite_schemaテーブルの再読み込みと再解析
- **OP_SeekGE**:B-Tree上のカーソルを指定キー以上の最初のエントリに移動
- **OP_Next**:B-Tree上のカーソルを次のエントリに進める
### 抽象構文木(AST)とデータフロープログラミング
AST(Abstract Syntax Tree)は通常LALR(1)パーサーによってSQL文から生成される。実行可能形式へと変換される過程で、元のAST構造から大きく変化するため、最終的な実行可能オブジェクトツリーを「AST」と呼ぶのは厳密には不正確。
「データフロープログラム」という表現がより適切で、各ノードが特定の計算を担当し、ノード間でデータを受け渡しする有向グラフを形成する。
## バイトコード方式の技術的優位性
### 1. 理解しやすさ
- 平坦なopcode列として簡単に出力可能
- SQLiteの「EXPLAIN」キーワードにより、6列テーブル形式で可視化
- オブジェクトツリーは多様な構造により統一的な表示が困難
### 2. デバッグ性
- フロントエンド(解析)とバックエンド(実行)の明確な分離
- `PRAGMA vdbe_trace=ON`によるバイトコード実行トレース機能
- 問題発生時の原因特定が容易
### 3. 増分実行
- SQL文を部分的に実行し、最初の行を生成後に一時停止可能
- オブジェクトツリーでは実行状態の保存・復元が複雑
- クライアント/サーバー型でないSQLiteには重要な機能
### 4. メモリ効率
- バイトコードは対応するASTより小さい
- `sqlite3_prepare()`実行中は両方が存在するが、ASTは即座に破棄
- プリペアドステートメントの長期キャッシュに有利
### 5. 実行速度
- 計算の各ステップで必要な判断が少ない
- 実験的検証は困難だが、理論的に高速
## オブジェクトツリー方式の優位性
### 1. 実行時クエリプラン変更
- バイトコードは生成後の変更が困難
- オブジェクトツリーは実行中の動的調整が可能
- クエリの自己調整機能
### 2. 並列化容易性
- 各処理ノードを異なるスレッドに割り当て可能
- ノード間の中間結果転送用のスレッドセーフキューが必要
- ノード内での同期プリミティブは不要
- データ利用可能性と出力キューの空きによる単純なスケジューリング
## 適用領域による使い分け
- **OLTP(オンライントランザクション処理)**:SQLiteの主要用途、バイトコードが適している
- **OLAP(オンライン分析処理)**:大規模マルチコアサーバーでの分析クエリ、データフロープログラムが有利
## 結論
SQLiteはOLTP用途とIoT環境での使用を主眼とし、増分実行とメモリ効率を重視するため、バイトコード方式を採用している。一方、大規模分析処理や並列処理を重視するシステムでは、オブジェクトツリー方式が適している場合もある。