📝 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オブジェクトをそのまま保存したい
- 🔧 細かいチューニングをしたい
- 📊 高度なトランザクション管理が必要
NanaSQLiteがおすすめ
- 🚀 とにかくシンプルに使いたい
- ⚡ 軽量・高速が最優先
- 📖 学習コストをかけたくない
- 🛡️ セキュリティリスクを避けたい(pickle不使用)
インストールと始め方
インストール
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日で集中開発しました。コミットログを見ると以下の流れです。
- 基本機能実装
- pytest自動テスト整備
- CI/CD(自動パブリッシュ)構築
- Dependabot導入
- 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)
シンプル → 軽量 → 速い → 使いやすい
学んだこと
- 機能追加は慎重に: 本当に必要な機能だけを実装
- シンプルイズベスト: 複雑さは最大の敵
- セキュリティ優先: pickleは便利だが危険
- ユーザー目線: 使う人の立場で考える
リンク集
- GitHub: disnana/NanaSQLite
-
PyPI:
pip install nanasqlite - 旧版: disnana/DictSQLite(こちらも現役)
コントリビューション募集中!
⭐ GitHubスター
🐛 バグ報告
💡 機能提案
📝 ドキュメント改善
お待ちしています!
おわりに
「シンプルなものを作りたかった」という原点に戻って開発したNanaSQLite。
DictSQLiteも引き続き開発しますが、「SQLiteをdictで使いたいだけ」という方にはNanaSQLiteをおすすめします。
ぜひ使ってみて、フィードバックをいただけると嬉しいです!
Happy Coding! 🚀