Created
December 12, 2023 06:07
-
-
Save benweint/a73c073a0d101627450a8cbccaa9f4b0 to your computer and use it in GitHub Desktop.
Go maps vs. SQLite for very simple ops
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module github.com/benweint/sqlite-demo | |
go 1.20 | |
require github.com/mattn/go-sqlite3 v1.14.18 // indirect |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
github.com/mattn/go-sqlite3 v1.14.18 h1:JL0eqdCOq6DJVNPSvArO/bIV9/P7fbGrV00LZHc+5aI= | |
github.com/mattn/go-sqlite3 v1.14.18/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"log" | |
"testing" | |
"math/rand" | |
"database/sql" | |
_ "github.com/mattn/go-sqlite3" | |
) | |
// This benchmark demonstrates the performance difference between an in-process | |
// Go map with no synchronization and an in-memory SQLite database for the very | |
// simple use case of storing short strings under short string keys. | |
const tableSize = 10000 | |
var result string | |
func generateKeyValuePair(i int) (string, string) { | |
key := fmt.Sprintf("key%d", i) | |
value := fmt.Sprintf("value%d", i) | |
return key, value | |
} | |
func getRandomKey() string { | |
return fmt.Sprintf("key%d", rand.Intn(tableSize)) | |
} | |
// BenchmarkMap inserts tableSize key/value pairs into a Go map[string]string, | |
// then looks up random entries from the map b.N times. | |
func BenchmarkMap(b *testing.B) { | |
m := map[string]string{} | |
for i := 0; i < tableSize; i++ { | |
key, val := generateKeyValuePair(i) | |
m[key] = val | |
} | |
b.ResetTimer() | |
var val string | |
for i := 0; i < b.N; i++ { | |
key := getRandomKey() | |
var ok bool | |
val, ok = m[key] | |
if !ok { | |
log.Fatal(fmt.Sprintf("not found: %s", key)) | |
} | |
} | |
result = val | |
} | |
// BenchmarkSqlite inserts tableSize key/value pairs into an in-memory SQLite DB table | |
// with a TEXT PRIMARY KEY column plus a TEXT value column, then looks up random | |
// entries from the table b.N times using a prepared statement. | |
func BenchmarkSqlite(b *testing.B) { | |
db, err := sql.Open("sqlite3", ":memory:") | |
if err != nil { | |
log.Fatal(err) | |
} | |
defer db.Close() | |
_, err = db.Exec(`CREATE TABLE IF NOT EXISTS t (id TEXT PRIMARY KEY, value TEXT)`) | |
if err != nil { | |
log.Fatal(err) | |
} | |
for i := 0; i < tableSize; i++ { | |
id := fmt.Sprintf("key%d", i) | |
value := fmt.Sprintf("value%d", i) | |
_, err := db.Exec("INSERT INTO t (id, value) VALUES (?, ?)", id, value) | |
if err != nil { | |
log.Fatal(err) | |
} | |
} | |
stmt, err := db.Prepare("SELECT value FROM t WHERE id=?") | |
if err != nil { | |
log.Fatal(err) | |
} | |
defer stmt.Close() | |
b.ResetTimer() | |
var val string | |
for i := 0; i < b.N; i++ { | |
err = stmt.QueryRow(getRandomKey()).Scan(&val) | |
if err != nil { | |
log.Fatal(err) | |
} | |
} | |
result = val | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment