Skip to content

パフォーマンスチューニングガイド

NanaSQLiteは、標準構成でも高速に動作するように設計されていますが、適切な開発パターンと設定を選択することで、その性能を数倍〜数十倍に引き出すことが可能です。


🚀 核心となる最適化: バッチ操作の活用

SQLiteにおいて最も実行コストが高いのは「トランザクションの開始とコミット」です。

❌ アンチパターン: ループ内での個別書き込み

以下のコードは、1回のループごとにディスクI/Oが発生するため非常に低速です。

python
# 1000回のディスクコミットが発生(数秒〜数十秒かかる場合がある)
for i in range(1000):
    db[f"key_{i}"] = i

✅ 推奨パターン: batch_update / batch_get

NanaSQLiteのバッチ操作用メソッドを使用すると、1回のトランザクションでまとめて処理されるため、劇的に高速化します。

python
# 1回のディスクコミットで完了(ミリ秒単位で終了)
data = {f"key_{i}": i for i in range(1000)}
db.batch_update(data)

ベンチマーク指標: 大量書き込みにおいて、個別更新に比べ 10倍〜100倍以上 の高速化が期待できます。


⚡ データベース設定の最適化

WAL (Write-Ahead Logging) モード

NanaSQLiteはデフォルトで optimize=True 設定時に WALモード を有効にします。

  • メリット: 書き込み中も読み込みがブロックされず、並行性が向上します。
  • 注意

    : ネットワークドライブ(NFS/SMB)上ではWALモードが動作しない、または不安定になる場合があります。

メモリマップドI/O (mmap)

読み込みパフォーマンスを向上させるために、SQLiteの mmap_size を活用しています。デフォルトでは256MBが割り当てられています。


🧠 キャッシュ戦略 (v1.3.0+)

NanaSQLiteは、メモリ使用量と速度のバランスを最適化するために、複数のキャッシュ戦略を提供しています。

1. 無制限キャッシュ (CacheType.UNBOUNDED)

デフォルトの動作です。一度アクセスしたデータは、メモリが許す限りすべてキャッシュされます。

  • メリット: 同一キーへの再アクセスが最速。
  • 注意

    : データ量が非常に多い場合、メモリ不足(OOM)の原因になる可能性があります。

2. LRUキャッシュ (CacheType.LRU)

v1.3.0で導入されました。キャッシュサイズ(項目数)に上限を設け、古いデータから自動的に破棄します。

  • 使用方法: cache_strategy=CacheType.LRU, cache_size=1000 のように指定します。
  • メリット: メモリ使用量を一定に保つことができます。

⚡ 高速化オプション: orjson + lru-dict

JSON のシリアライズ・デシリアライズを高速化するために orjson を活用します。

  • orjson: 標準 json モジュールと比較して 3~5倍高速 です。
  • lru-dict: C拡張で実装された超高速な LRU データ構造。
bash
# クォート推奨(Zsh等のシェル対策)
pip install "nanasqlite[speed]"

インストールされている場合、NanaSQLite は自動的にこれらを検知して使用します。未インストールの場合は標準ライブラリ(json, OrderedDict)へフォールバックします。

3. TTLキャッシュ (CacheType.TTL)

v1.3.1で導入されました。データの有効期限を設定し、古いデータを自動的に無効化します。

  • 使用方法: cache_strategy=CacheType.TTL, cache_ttl=3600 (1時間)
  • Persistence TTL: cache_persistence_ttl=True を設定すると、キャッシュ失効時に SQLite からも自動的に削除されます。セッション管理などに最適です。

📌 テーブルごとの個別設定

特定のテーブル(巨大なログテーブルなど)だけメモリ使用を抑えたい場合に有効です。

python
# メインDBは無制限、logsテーブルだけ最新100件をキャッシュ
logs = db.table("logs", cache_strategy=CacheType.LRU, cache_size=100)

# セッションテーブルには 30分(1800s) の TTL を設定し、DBからも自動削除
sessions = db.table("sessions", 
    cache_strategy=CacheType.TTL, 
    cache_ttl=1800, 
    cache_persistence_ttl=True
)

⚡ キャッシュのロード方法

  1. bulk_load=True (初期化時):
    • 起動時に全データをメモリに読み込みます。
    • ユースケース: データ量が数万件程度で、起動直後から高速なランダムアクセスが必要な場合。
  2. デフォルト (遅延ロード):
    • アクセスされたデータのみをメモリに保持します。

TIP

キャッシュを強制的に最新状態にしたい場合は db.refresh(key) または最新値をDBから直接引く db.get_fresh(key) を使用してください。 メモリ内の全キャッシュをクリアしたい場合は db.clear_cache() を呼び出します。


🧠 CRUD 速度特化: memory_first=True (v1.5.7dev1+)

CRUD の読み書きを最優先したい場合は、メモリ優先モードを使用できます。

python
from nanasqlite import NanaSQLite

db = NanaSQLite("app.db", memory_first=True)

db["user:1"] = {"name": "Alice"}
user = db["user:1"]       # メモリから即座に取得
db.flush(wait=True)       # 重要な区切りでは明示的に永続化
db.close()                # 終了時にも残りの差分をフラッシュ

memory_first=True は起動時に KVS 全体をメモリへ読み込み、その後の CRUD 操作をメモリ上で完結させます。変更差分は v2 エンジンによりバックグラウンドでまとめて SQLite へフラッシュされます。デフォルトでは変更がある場合に約 5 秒ごとにフラッシュします。

python
db = NanaSQLite(
    "app.db",
    memory_first=True,
    memory_flush_interval=2.0,  # 2秒ごとに差分をフラッシュ
)

向いている用途

  • 単一プロセスで動くアプリケーション
  • CRUD が非常に多く、読み書きレイテンシを最小化したい場合
  • データセット全体をメモリに載せられる規模
  • 重要なタイミングで flush(wait=True) または close() を呼べる設計

注意点

  • LRU / TTL / cache_size / cache_persistence_ttl とは併用できません。メモリ優先モードでは無制限キャッシュが前提です。
  • プロセスが強制終了された場合、最後のフラッシュ以降の差分は失われる可能性があります。
  • 別プロセスや外部ツールが同じ SQLite ファイルを更新しても、メモリ上の値には自動反映されません。
  • マルチプロセス環境では使用しないでください。通常の v2 モードと同様にシングルプロセス専用です。

🔍 インデックスによる検索の高速化

query()query_with_pagination() を使用して、Key-Valueペア以外のデータ(JSON内の特定フィールドなど)を検索する場合、インデックスが不可欠です。

python
# 検索対象となるJSONフィールドにインデックスを貼る
db.create_index("idx_user_age", "data", ["age"])

インデックス作成の目安:

  • 数千件を超えるデータに対して WHERE 句での検索を頻繁に行う場合。
  • データの挿入速度よりも検索速度を優先したい場合。

💻 OS・環境固有の注意点

Windows環境

  • アンチウイルスソフト: SQLiteファイルの書き込み時にウイルススキャンが走ると、database is locked が発生しやすくなります。DBファイル(.db, .db-wal, .db-shm)をスキャン除外対象に設定することを推奨します。

SSD vs HDD

  • SQLite はトランザクション毎に fsync を多用するため、ディスクの永続化レイテンシに強く依存します。HDD 環境ではこの同期コストが支配的となり、synchronous=OFF など耐障害性を犠牲にした設定が必要になる場合があります。可能であれば fsync 性能の高い SSD 上での運用を推奨します。

チェックリスト

  • [ ] 大量処理に batch_update を使っているか?
  • [ ] 頻繁な検索に create_index を適用しているか?
  • [ ] optimize=True(デフォルト)を使用しているか?
  • [ ] CRUD 速度最優先かつシングルプロセスなら memory_first=True を検討したか?
  • [ ] SSD環境で動作させているか?