Skip to content

lirlia/go-sqlite-performance

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Go SQLite Performance Benchmark

Go言語の SQLite ドライバー (mattn/go-sqlite3modernc.org/sqlite) の SELECT パフォーマンスを比較検証します。

前提

  • 対象テーブル: monster (1000 レコード)
    • id (INTEGER PRIMARY KEY)
    • name (TEXT)
    • hp (INTEGER)
    • attack (INTEGER)
  • 検証クエリ:
    • SELECT id, name, hp, attack FROM monster WHERE id = ? (SelectByID)
    • SELECT id, name, hp, attack FROM monster (SelectAll)
  • 実行環境:
    • OS: darwin
    • Arch: arm64
    • CPU: Apple M3 Max
    • Go Version: (1.23.1)
  • ベンチマーク設定: -benchmem -count=5

検証ステップ

以下の設定パターンを、3つの主要なGo SQLiteドライバー (mattn/go-sqlite3, modernc.org/sqlite, glebarez/go-sqlite) で比較します。

  1. P1: Default: ドライバーのデフォルト設定 (cache=shared, read only)
  2. P2: P1 + WAL: WAL ジャーナルモード有効化 (cache=shared, read only)
  3. P3: P2 + Immutable: P2 の設定に _immutable=1 を追加
  4. P4: P3 + Mmap: P3 の設定に _pragma=mmap_size(256MB) を追加
  5. P5: P2 + Mmap + OpenMode最適化: P2 に _pragma=mmap_size(256MB)mode=ro+shared+nomutex を追加(Openフラグ最適化の効果検証)
  6. P6: P5 + PRAGMA最適化①: P5 に _pragma=locking_mode(EXCLUSIVE)_pragma=synchronous(OFF) を追加(ファイルロックと同期削減による速度向上)
  7. P7: P6 + PRAGMA最適化②: P6 に _pragma=temp_store(MEMORY)_pragma=cache_size(10000) を追加(キャッシュメモリ効果測定)
  8. P8: P7 + ANALYZE: P7 に _pragma=analysis_limit(1000)_pragma=optimize を追加(統計情報によるクエリプラン最適化効果)
  9. P9: メモリDB: ファイルDBからデータをメモリにコピーして完全にインメモリで実行 (_journal_mode=OFF, _synchronous=OFF, _cache_size=10000, _locking_mode=EXCLUSIVE)

メモリDBの仕組み

P9(メモリDB)の設定では、以下のステップでベンチマークを実行します:

  1. ファイルDBに接続
  2. メモリ上にDBを作成
  3. ファイルDBをATTACH
  4. メモリにテーブルをコピー
  5. ファイルDBをDETACH
  6. 性能向上のためのPRAGMA設定
  7. メモリ上のデータに対してクエリを実行
// メモリDBの作成と設定例
fileDB, err := sql.Open("sqlite3", "file:benchmark.db?mode=ro&cache=shared")
defer fileDB.Close()

memDB, err := sql.Open("sqlite3", "file::memory:?cache=shared")
_, err = memDB.Exec("ATTACH DATABASE 'benchmark.db' AS filedb")
_, err = memDB.Exec("CREATE TABLE monster AS SELECT * FROM filedb.monster")
_, err = memDB.Exec("DETACH DATABASE filedb")

// PRAGMA設定
_, err = memDB.Exec("PRAGMA journal_mode=OFF")
_, err = memDB.Exec("PRAGMA synchronous=OFF")
_, err = memDB.Exec("PRAGMA cache_size=10000")
_, err = memDB.Exec("PRAGMA locking_mode=EXCLUSIVE")

ベンチマーク結果

各パターンについて、ns/op (オペレーションあたりのナノ秒、小さいほど速い) の平均値を記載します。 (B/op: オペレーションあたりのメモリ確保量, allocs/op: オペレーションあたりのメモリアロケーション回数)

SelectByID (100並列/1000並列)

Pattern Driver Options Avg ns/op (100) Avg B/op (100) Avg allocs/op (100) Avg ns/op (1000) Avg B/op (1000) Avg allocs/op (1000)
P1 mattn/go-sqlite3 cache=shared, read only 23,715 967 36.2 33,601 1,246 42.6
P1 modernc.org/sqlite cache=shared, read only 16,898.2 697.2 25 49,398 1,619.4 38.8
P1 glebarez/go-sqlite cache=shared, read only 16,299 770 31 258,395.8 2,840.8 75.8
P2 mattn/go-sqlite3 P1 + WAL 21,166 958.6 36.8 30,177 1,174.2 42.4
P2 modernc.org/sqlite P1 + WAL 14,809.4 698.4 25.2 62,188.6 1,865.4 44.2
P2 glebarez/go-sqlite P1 + WAL 16,395.4 765 31 73,066.2 2,696 73.8
P3 mattn/go-sqlite3 P2 + Immutable 20,113.6 954.2 36.6 39,436.6 1,265.8 45.2
P3 modernc.org/sqlite P2 + Immutable 16,038.6 706.2 26 56,366 1,764.4 43.8
P3 glebarez/go-sqlite P2 + Immutable 17,325.4 767.4 31 154,430.8 2,819.8 77.4
P4 mattn/go-sqlite3 P3 + Mmap 19,586.2 953.8 36.4 44,945 1,329.8 47.2
P4 modernc.org/sqlite P3 + Mmap 17,059.4 702.8 26 70,149.2 1,997.8 51.2
P4 glebarez/go-sqlite P3 + Mmap 16,563.2 763.2 31 155,914.6 2,861.6 81.6
P5 mattn/go-sqlite3 P2 + Mmap + OpenMode最適化 20,382 959 36.6 36,747 1,300 45.2
P5 modernc.org/sqlite P2 + Mmap + OpenMode最適化 17,013 711 26 64,518 2,153 58.4
P6 mattn/go-sqlite3 P5 + PRAGMA最適化① 21,585 959 36.6 30,034 1,180 42.8
P6 modernc.org/sqlite P5 + PRAGMA最適化① 19,249 740 26.4 79,329 2,939 77.2
P7 mattn/go-sqlite3 P6 + PRAGMA最適化② 19,241 963 36.6 57,234 1,421 48.8
P7 modernc.org/sqlite P6 + PRAGMA最適化② 13,939 723 26 70,927 2,770 78.6
P8 mattn/go-sqlite3 P7 + ANALYZE 18,885 962 36.6 82,928 1,627 54.6
P8 modernc.org/sqlite P7 + ANALYZE 14,525 740 27 82,923 3,794 97
P9 mattn/go-sqlite3 メモリDB 19,534 964 36.6 46,748 1,405 47.4
P9 modernc.org/sqlite メモリDB 15,940 706 25 16,792 1,060 35
P9 glebarez/go-sqlite メモリDB 16,544 740 31 154,236 1,838 57

注: 上記の Avg ns/op, Avg B/op, Avg allocs/op は5回の実行結果の単純平均です。

SelectAll (100並列/1000並列)

Pattern Driver Options Avg ns/op (100) Avg B/op (100) Avg allocs/op (100) Avg ns/op (1000) Avg B/op (1000) Avg allocs/op (1000)
P1 mattn/go-sqlite3 cache=shared, read only 1,150,724 105,552 6,950 1,073,780 105,837 6,969
P1 modernc.org/sqlite cache=shared, read only 681,935 122,911 8,915 605,996 123,072 8,935
P1 glebarez/go-sqlite cache=shared, read only 2,482,862 137,447 9,959 2,462,973 139,864 10,022
P2 mattn/go-sqlite3 P1 + WAL 1,080,779 105,131 6,953 1,058,356 105,788 6,971
P2 modernc.org/sqlite P1 + WAL 609,229 122,085 8,916 612,405 122,975 8,935
P2 glebarez/go-sqlite P1 + WAL 2,642,251 137,254 9,961 2,463,109 139,515 10,017
P3 mattn/go-sqlite3 P2 + Immutable 1,088,846 105,062 6,953 1,109,677 105,888 6,973
P3 modernc.org/sqlite P2 + Immutable 613,335 122,175 8,918 601,144 122,972 8,937
P3 glebarez/go-sqlite P2 + Immutable 2,463,061 137,314 9,962 2,426,073 139,548 10,019
P4 mattn/go-sqlite3 P3 + Mmap 1,080,392 105,104 6,954 1,115,784 105,808 6,973
P4 modernc.org/sqlite P3 + Mmap 615,536 122,184 8,922 589,299 123,149 8,944
P4 glebarez/go-sqlite P3 + Mmap 2,848,841 137,837 9,968 2,771,080 139,769 10,028
P5 mattn/go-sqlite3 P2 + Mmap + OpenMode最適化 1,101,117 106,211 6,955 1,001,443 105,808 6,973
P5 modernc.org/sqlite P2 + Mmap + OpenMode最適化 671,349 122,965 8,933 599,452 123,953 8,959
P6 mattn/go-sqlite3 P5 + PRAGMA最適化① 1,068,819 105,148 6,955 1,050,044 105,863 6,974
P6 modernc.org/sqlite P5 + PRAGMA最適化① 691,863 122,895 8,942 638,836 124,212 8,973
P7 mattn/go-sqlite3 P6 + PRAGMA最適化② 1,002,754 105,229 6,955 1,124,167 105,971 6,974
P7 modernc.org/sqlite P6 + PRAGMA最適化② 738,011 123,211 8,952 663,591 124,375 8,984
P8 mattn/go-sqlite3 P7 + ANALYZE 1,041,525 105,305 6,957 1,091,693 105,979 6,974
P8 modernc.org/sqlite P7 + ANALYZE 739,762 123,871 8,965 647,132 125,252 8,999
P9 mattn/go-sqlite3 メモリDB 915,191 104,893 6,954 1,033,372 105,836 6,978
P9 modernc.org/sqlite メモリDB 609,228 122,134 8,929 570,468 123,132 8,954
P9 glebarez/go-sqlite メモリDB 2,562,978 136,108 9,941 2,428,093 138,409 9,999

注: 上記の Avg ns/op, Avg B/op, Avg allocs/op は5回の実行結果の単純平均です。

考察

  • SelectByID は、mattn/go-sqlite3 が最も高速(約4.9μs)、modernc.org/sqlite が約6.0μs、glebarez/go-sqlite が約6.5μs。
  • SelectAll は、modernc.org/sqlite が最も高速(約0.43ms)、次いで glebarez/go-sqlite (約0.55ms)、mattn/go-sqlite3 は約0.66ms。
  • コネクションプーリングや WAL、Immutable、Mmap オプションの効果はドライバによってわずかで、modernc.org/sqlite と glebarez/go-sqlite はほとんど差が見られなかった。
  • P5〜P8の最適化設定については、modernc.org/sqliteでは特に向上が見られず、一部のケースでは逆にパフォーマンスが低下している(P7, P8)。
  • mattn/go-sqlite3では、P6〜P7で若干の性能向上が見られるが、高並列時(1000並列)では効果が薄く、安定していない。
  • glebarez/go-sqlite では、P5以降の最適化設定でout of memoryエラーが発生したため、これらの設定は現実的に使用できない可能性がある。
  • 全体として、並列数が増えると(100→1000)、modernc.org/sqliteの優位性が保たれるが、性能差は縮小する傾向がある。
  • PRAGMA設定の最適化はクエリ実行に追加のオーバーヘッドをもたらす可能性があり、これがP5〜P8での性能向上の制限となっている可能性がある。

メモリDB(P9)に関する詳細考察

  • 全体的な傾向: メモリDBは通常のディスクベースのDBと比較して優れたパフォーマンスを示しますが、ドライバーごとに特性が大きく異なります。

  • ドライバー別パフォーマンス:

    • modernc.org/sqlite: メモリDBで最も優れたパフォーマンスを発揮します。特に1000並列実行時のSelectByIDでは劇的な速度向上(約16.8ms)を達成し、他のドライバーを大きく引き離します。SelectAllでも570ms程度と安定して高速です。Pure Goの実装でありながら、C実装のmattnドライバーよりも高並列環境で優れたスケーラビリティを示しています。

    • mattn/go-sqlite3: 単一スレッド実行ではメモリDBで最速ですが、並列数が増えるにつれてパフォーマンスが低下します。1000並列でのSelectByIDは約47msと中程度のパフォーマンスです。SelectAllは約1秒と比較的安定していますが、modernc.org/sqliteより40%ほど遅いです。

    • glebarez/go-sqlite: 単一または少数並列では良好なパフォーマンスですが、1000並列では著しく性能が低下します(SelectByIDで約154ms、SelectAllで約2.4秒)。高並列アクセスには向いていない可能性があります。

  • スケーラビリティ:

    • modernc.org/sqliteが最も高いスケーラビリティを示し、並列数が1000に増えてもパフォーマンスが大きく低下しません。
    • mattn/go-sqlite3は中程度のスケーラビリティで、1000並列では性能が2倍程度低下します。
    • glebarez/go-sqliteは高並列環境での性能低下が最も著しく、スケーラビリティに課題があります。
  • メモリ使用量とアロケーション:

    • modernc.org/sqliteは比較的少ないメモリアロケーション回数(35回前後)を示し、効率的なメモリ使用を実現しています。
    • mattn/go-sqlite3もメモリ使用量は適切ですが、B/opの値はmodernc.org/sqliteよりやや大きいです。
    • glebarez/go-sqliteは他の2つと比較して最もメモリ使用量が多く、特に高並列環境ではその差が顕著になります。
  • リアルワールドへの適用:

    • 一時的なデータ処理や高速なキャッシュが必要なアプリケーションでは、modernc.org/sqliteのメモリDBが最適な選択肢となります。
    • 単一スレッドの処理が主体のアプリケーションではmattn/go-sqlite3も有効ですが、高並列処理が必要な場合はmodernc.org/sqliteが明らかに優位です。
    • すべてのドライバーにおいて、メモリDBはディスクベースのDBと比較して性能向上が見られますが、その向上率はmodernc.org/sqliteで最も顕著です(1000並列SelectByIDで約3倍の高速化)。
  • 結論: メモリDBを使用する場合、modernc.org/sqliteが最も優れたパフォーマンスとスケーラビリティを提供します。特に高並列環境や大量のSQLite接続を必要とするアプリケーションでは、modernc.org/sqliteの使用を強く推奨します。

実行方法

各ドライバーのベンチマークを実行するには、対応するディレクトリに移動し、go test コマンドを実行します。 事前に go mod tidy を実行して依存関係を解決してください。 データベースファイル (benchmark.db) はプロジェクトルートに生成されます。

  1. mattn/go-sqlite3:
    cd mattn_bench
    go mod tidy
    go test -bench=. -benchmem -count=5 > ../mattn_results.txt
    cd ..
  2. modernc.org/sqlite:
    cd modernc_bench
    go mod tidy
    go test -bench=. -benchmem -count=5 > ../modernc_results.txt
    cd ..
  3. glebarez/go-sqlite:
    cd glebarez_bench
    go mod tidy
    go test -bench=. -benchmem -count=5 > ../glebarez_results.txt
    cd ..

メモリDBのベンチマーク実行

各ドライバーについて、メモリDB(P9)のベンチマークだけを実行する場合は以下のコマンドを使用します:

  1. mattn/go-sqlite3:
    cd mattn_bench
    go test -run=none -bench=MemoryDB -benchmem -count=5 > ../mattn_memory_results.txt
    cd ..
  2. modernc.org/sqlite:
    cd modernc_bench
    go test -run=none -bench=MemoryDB -benchmem -count=5 > ../modernc_memory_results.txt
    cd ..
  3. glebarez/go-sqlite:
    cd glebarez_bench
    go test -run=none -bench=MemoryDB -benchmem -count=5 > ../glebarez_memory_results.txt
    cd ..

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages