0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

複雑化したDictSQLiteをリファクタ!dict風SQLiteラッパー『NanaSQLite』で原点回帰した話

Posted at

📝 3行まとめ

  • DictSQLiteが高機能化で複雑になったので、シンプル版NanaSQLiteを作った
  • 機能を絞り込んだ結果、初期化7.7倍速・バッチ処理19.9倍速を実現
  • 「SQLiteをdictで使いたいだけ」なら3行のコードで即使える

はじめに - DictSQLiteが複雑化した理由

皆さんは「最初はシンプルだったのに、機能追加で複雑化してしまった」という経験はありませんか?

私が開発していたDictSQLiteは、まさにそのパターンでした。

DictSQLiteの当初の目的

# 「SQLiteをdictで扱いたい」それだけだった
db["key"] = "value"

シンプル、わかりやすい、これで十分。それが最初のコンセプトでした。

しかし、機能が増えていった...

機能追加の罠

  • 🔐 暗号化機能を追加
  • ⚡ 高速化・最適化を追加
  • 🥒 pickle対応で複雑なオブジェクトも保存可能に
  • 🛡️ セキュリティ機能を追加
  • 📊 インデックス、トランザクション管理...

気づいたら「重い・複雑・わかりにくい」ライブラリになっていた

問題点の整理

DictSQLiteが抱えていた問題を整理すると以下の通りです。

問題 具体的な症状
重い 暗号化・最適化処理で処理が遅い
複雑 オプションが多すぎて使い方がわからない
不具合 機能間の相互作用でバグが発生
学習コスト ドキュメントを読まないと使えない

開発者としての葛藤
高機能なDictSQLiteも良いライブラリだと思っています。
でも、「ただSQLiteをdictで使いたいだけ」のユーザーには過剰スペックでした。

解決策: NanaSQLiteの誕生

そこで、原点回帰しました。

コンセプト

開発の指針
シンプル > 高機能
速い > 多機能
わかる > できる

DictSQLiteから以下をあえて削除しました。

  • ❌ 暗号化機能
  • ❌ pickle対応(セキュリティリスク回避)
  • ❌ 複雑な最適化オプション
  • ❌ 高度なトランザクション管理

代わりに追加したのは、

  • ✅ dict風のシンプルなインターフェース
  • ✅ JSON自動シリアライズ(安全)
  • ✅ 即時永続化(書いたら即保存)
  • ✅ スマートキャッシング(必要に応じて高速化)
  • ✅ 設定不要(3行で使える)

使い方の比較

DictSQLite(複雑版)

from dictsqlite import DictSQLite

# 設定が必要...
db = DictSQLite(
    "data.db",
    encryption_key="secret",
    cache_size=1000,
    journal_mode="WAL"
)

# 使い方を覚える必要がある
with db.transaction():
    db.set("key", "value", encrypt=True)

こんなに設定が必要?
初心者には敷居が高すぎる...

NanaSQLite(シンプル版)

from nanasqlite import NanaSQLite

# たったこれだけ!
db = NanaSQLite("data.db")
db["key"] = "value"
print(db["key"])  # 'value'

Pythonのdictが使えれば使える
学習コストゼロ!

実際のコード例

基本的な使い方

from nanasqlite import NanaSQLite

# データベースを開く(なければ自動作成)
db = NanaSQLite("myapp.db")

# dictのように使う
db["user"] = {
    "name": "Nana",
    "age": 20,
    "tags": ["admin", "active"]
}

# ネストもOK
print(db["user"]["name"])  # 'Nana'
print(db["user"]["tags"][0])  # 'admin'

# 自動で保存される(closeを忘れても大丈夫)
db.close()

自動永続化
代入した瞬間にSQLiteに保存されます。
プログラムがクラッシュしてもデータは安全!

複雑なデータ構造も簡単

# 30階層以上のネストもOK
db["config"] = {
    "server": {
        "host": "localhost",
        "ports": {
            "http": 8080,
            "https": 8443,
            "admin": {
                "internal": 9000,
                "external": 9001
            }
        }
    }
}

# そのまま取得
print(db["config"]["server"]["ports"]["admin"]["internal"])  # 9000

バッチ操作で高速化

# 大量データを一気に書き込み
db.batch_update({
    "user1": {"name": "Alice", "score": 100},
    "user2": {"name": "Bob", "score": 200},
    "user3": {"name": "Carol", "score": 300},
    # ... 1000件でも高速
})

パフォーマンス
バッチ操作なら1000件の書き込みも数秒で完了!

一括ロードで読み取り高速化

# 起動時に全データをメモリに読み込み
db = NanaSQLite("data.db", bulk_load=True)

# 以降のアクセスは超高速(メモリアクセス)
for i in range(10000):
    print(db[f"user{i}"])  # ディスクアクセスなし!

コンテキストマネージャ対応

# with文で安全に使える
with NanaSQLite("temp.db") as db:
    db["temp_data"] = "一時データ"
    # 自動でclose()される

技術的なポイント

1. JSONシリアライズでシンプルに

pickleとJSONの違い
DictSQLiteはsafe pickle(独自の安全機構)でセキュリティ対策済みですが、
NanaSQLiteはさらにシンプルにJSONのみに絞りました。

# JSON使用(NanaSQLite)- 安全!
db["data"] = {"safe": "data"}  # 安全なデータ型のみ

NanaSQLiteはJSONシリアライズを使うため、以下が保証されます!

  • 安全性: 任意コード実行のリスクなし
  • 可読性: データベースを直接見れば中身がわかる
  • 互換性: 他の言語からも読み書き可能

2. WALモードとmmapで高速化

# 内部でこれらを自動設定
PRAGMA journal_mode=WAL;     # 並行書き込み可能
PRAGMA synchronous=NORMAL;   # 適度な安全性
PRAGMA mmap_size=268435456;  # メモリマップで高速化

設定不要で最適化済み
ユーザーは何も考えずに使えて、内部では高速動作

3. スマートキャッシング

# 遅延ロード(デフォルト)- メモリ節約
db = NanaSQLite("data.db")
value = db["key"]  # アクセス時にロード

# 一括ロード - 速度優先
db = NanaSQLite("data.db", bulk_load=True)
value = db["key"]  # メモリから即取得

DictSQLiteとの使い分け

どちらも現役開発中!
両方とも良いライブラリです。用途で使い分けてください。

DictSQLiteがおすすめ

  • 🔐 データを暗号化したい
  • 🥒 Pythonオブジェクトをそのまま保存したい
  • 🔧 細かいチューニングをしたい
  • 📊 高度なトランザクション管理が必要

DictSQLite

NanaSQLiteがおすすめ

  • 🚀 とにかくシンプルに使いたい
  • ⚡ 軽量・高速が最優先
  • 📖 学習コストをかけたくない
  • 🛡️ セキュリティリスクを避けたい(pickle不使用)

NanaSQLite

インストールと始め方

インストール

pip install nanasqlite

3行で動く最小コード

from nanasqlite import NanaSQLite
db = NanaSQLite("test.db")
db["hello"] = "world"

パフォーマンス比較

同一環境(Windows 11、Python 3.11、SSD)での測定結果です。

操作 DictSQLite NanaSQLite 速度差
初期化 84.88ms 11.00ms 7.7倍速
単純書き込み(1000件) 101.08ms 110.86ms ほぼ同等
バッチ書き込み(1000件) 88.88ms 4.47ms 19.9倍速
読み取り(1000件) 31.17ms 19.25ms 1.6倍速
一括ロード+読み取り - 3.78ms -
ネストデータ(100件) 10.02ms 8.84ms 1.1倍速
混合操作(1500操作) 101.80ms 123.62ms 0.8倍

NanaSQLiteが圧勝する場面

  • 🚀 初期化: 7.7倍速 - アプリ起動が高速
  • ⚡ バッチ書き込み: 19.9倍速 - 大量データ投入で真価を発揮
  • 📚 一括ロード: メモリ展開で457万件/秒の超高速読み取り

DictSQLiteが優れる場面

  • 🔐 暗号化が必要な場合
  • 🥒 Pythonオブジェクトをそのまま保存したい場合
  • 🔧 細かいチューニングをしたい場合

詳細スループット比較

操作 DictSQLite NanaSQLite
単純書き込み 9,893件/秒 9,020件/秒
バッチ書き込み 11,251件/秒 223,494件/秒
読み取り(遅延) 32,079件/秒 51,961件/秒
読み取り(一括) - 4,570,384件/秒 🚀
ネストデータ 9,985件/秒 11,317件/秒
混合操作 14,735操作/秒 12,134操作/秒

なぜバッチ書き込みで19.9倍も差が出るのか?

# DictSQLite - 高機能ゆえの処理
for key, value in data.items():
    # 暗号化チェック
    # pickle/JSON判定
    # 圧縮判定
    # トランザクション管理
    db[key] = value

# NanaSQLite - シンプルに直行
db.batch_update(data)
# → JSON一括変換 → SQL一括実行

余計な判定処理がない分、バッチ処理で圧倒的な速度を実現!

速度の秘密

NanaSQLiteは設定不要で以下が自動適用されています。

-- 自動最適化設定
PRAGMA journal_mode=WAL;      -- 並行アクセス対応
PRAGMA synchronous=NORMAL;    -- バランスの取れた安全性
PRAGMA mmap_size=268435456;   -- 256MBメモリマップ
PRAGMA cache_size=-64000;     -- 64MBキャッシュ
PRAGMA temp_store=MEMORY;     -- 一時領域をメモリに

一括ロードの威力

# 通常の読み取り: 52,000件/秒
db = NanaSQLite("data.db")
for i in range(1000):
    print(db[f"key_{i}"])  # 毎回ディスクアクセス

# 一括ロード: 4,570,000件/秒(87倍速!)
db = NanaSQLite("data.db", bulk_load=True)  # 起動時に全データをメモリに
for i in range(1000):
    print(db[f"key_{i}"])  # メモリアクセスのみ

使い分けのコツ

  • 頻繁に読み書き: 通常モード(遅延ロード)
  • 読み取り中心: 一括ロード - 起動は少し遅いが以降は超高速
  • 大量データ投入: バッチ書き込み - 22万件/秒の圧倒的速度

実測値で見る体感差

シナリオ DictSQLite NanaSQLite 体感
アプリ起動100回 8.5秒 1.1秒 待ち時間が7.4秒短縮
10万件インポート 9秒 0.4秒 ⚡ ほぼ瞬時
設定ファイル読み込み 31ms 19ms 体感差は小さい

結論: シンプルは速い

  • 機能を絞り込んだことで、オーバーヘッドが激減
  • 特にバッチ処理と起動速度で顕著な差
  • 日常的な使い方では体感できるレベルの高速化

どちらも優秀なライブラリですが、用途で使い分けが重要です!

開発の裏側

開発期間

2025年12月9日の1日で集中開発しました。コミットログを見ると以下の流れです。

  1. 基本機能実装
  2. pytest自動テスト整備
  3. CI/CD(自動パブリッシュ)構築
  4. Dependabot導入
  5. PyPIリリース

高速開発の秘訣
DictSQLiteで得た知見を活かし、必要な機能だけに絞ったから実現できました。

工夫した点

# バージョン管理を簡単に
__version__ = "0.1.0"  # この1行を変えるだけ

# 自動テスト完備
pytest tests/  # 全機能をテスト

# 自動パブリッシュ
git push  # PyPIに自動リリース!

実戦投入例

私が運営しているDiscordボット&VPSホスティングサービス「Disnana」でも実際に使用しています!

# ユーザー設定の保存
config_db = NanaSQLite("user_configs.db")
config_db[user_id] = {
    "language": "ja",
    "theme": "dark",
    "notifications": True
}

# サーバーステータスの記録
status_db = NanaSQLite("server_status.db")
status_db[server_id] = {
    "cpu": 45.2,
    "memory": 78.5,
    "uptime": 86400
}

本番環境で稼働中
個人プロジェクトからプロダクション環境まで対応

まとめ

Before(DictSQLite)

高機能 → 複雑 → 重い → 使いにくい

After(NanaSQLite)

シンプル → 軽量 → 速い → 使いやすい

学んだこと

  1. 機能追加は慎重に: 本当に必要な機能だけを実装
  2. シンプルイズベスト: 複雑さは最大の敵
  3. セキュリティ優先: pickleは便利だが危険
  4. ユーザー目線: 使う人の立場で考える

リンク集

コントリビューション募集中!
⭐ GitHubスター
🐛 バグ報告
💡 機能提案
📝 ドキュメント改善

お待ちしています!

おわりに

「シンプルなものを作りたかった」という原点に戻って開発したNanaSQLite。

DictSQLiteも引き続き開発しますが、「SQLiteをdictで使いたいだけ」という方にはNanaSQLiteをおすすめします。

ぜひ使ってみて、フィードバックをいただけると嬉しいです!


Happy Coding! 🚀

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?