diff options
| author | Stefan Majewsky <majewsky@gmx.net> | 2026-04-10 15:56:22 +0200 |
|---|---|---|
| committer | Stefan Majewsky <majewsky@gmx.net> | 2026-04-10 15:56:22 +0200 |
| commit | e0fb5aa0acc1983648ab1480f22114aead234eeb (patch) | |
| tree | bc70cbac9a3f33b596d7435576d6a789c6c34144 /benchmark/benchmark_test.go | |
| parent | bce3df549ff4ccc8895697a3222269bd14fc22a4 (diff) | |
| download | go-oblast-e0fb5aa0acc1983648ab1480f22114aead234eeb.tar.gz | |
initial MVP for oblast.Select()
Diffstat (limited to 'benchmark/benchmark_test.go')
| -rw-r--r-- | benchmark/benchmark_test.go | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/benchmark/benchmark_test.go b/benchmark/benchmark_test.go new file mode 100644 index 0000000..c08361e --- /dev/null +++ b/benchmark/benchmark_test.go @@ -0,0 +1,131 @@ +// SPDX-FileCopyrightText: 2026 Stefan Majewsky <majewsky@gmx.net> +// SPDX-License-Identifier: Apache-2.0 + +package main_test + +import ( + "crypto/sha256" + "database/sql" + "fmt" + "strconv" + "testing" + + "github.com/go-gorp/gorp/v3" + _ "github.com/mattn/go-sqlite3" + "go.xyrillian.de/oblast" +) + +func BenchmarkSelect(b *testing.B) { + const ( + totalRecordCount = 10000 + selectedRecordCount = 1 + ) + + db, err := sql.Open("sqlite3", "file:foobar?mode=memory&cache=shared") + if err != nil { + b.Fatal(err) + } + + // fill in some random-looking, but deterministic data + _, err = db.Exec(`CREATE TABLE entries (id INTEGER, message TEXT)`) + if err != nil { + b.Fatal(err) + } + stmt, err := db.Prepare(`INSERT INTO entries (id, message) VALUES (?, ?)`) + if err != nil { + b.Fatal(err) + } + for idx := range totalRecordCount { + buf := sha256.Sum256([]byte(strconv.Itoa(idx))) + _, err = stmt.Exec(idx, fmt.Sprintf("sha256:%x", buf[:])) + if err != nil { + b.Fatal(err) + } + } + err = stmt.Close() + if err != nil { + b.Fatal(err) + } + + // prepare the functions that will be benched + odb := oblast.NewDB(db, oblast.SqliteDialect()) + gdb := gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}} + type record struct { + ID int `db:"id"` + Message string `db:"message"` + } + query := `SELECT * FROM entries WHERE id < ` + strconv.Itoa(selectedRecordCount) + + selectWithOblast := func(b *testing.B) { + records, err := oblast.Select[record](b.Context(), odb, query) + if err != nil { + b.Error(err) + } + if len(records) != selectedRecordCount { + b.Errorf("expected %d, but got %d records", selectedRecordCount, len(records)) + } + } + + selectWithGorp := func(b *testing.B) { + var records []record + _, err := gdb.Select(&records, query) + if err != nil { + b.Error(err) + } + if len(records) != selectedRecordCount { + b.Errorf("expected %d, but got %d records", selectedRecordCount, len(records)) + } + } + + selectWithSqlite := func(b *testing.B) { + var count int64 + rows, err := db.Query(query) + if err != nil { + b.Error(err) + } + var ( + id int64 + message string + ) + for rows.Next() { + err := rows.Scan(&id, &message) + if err != nil { + b.Error(err) + } + if id != 20000 && message != "" { // always true; ensures that values are not optimized away + count++ + } + } + err = rows.Close() + if err != nil { + b.Error(err) + } + if count != selectedRecordCount { + b.Errorf("expected %d, but got %d records", selectedRecordCount, count) + } + } + + // run once to prewarm caches + selectWithOblast(b) + selectWithGorp(b) + if b.Failed() { + b.FailNow() + } + + // run actual benchmark + b.Run("via Gorp", func(b *testing.B) { + for range b.N { + selectWithGorp(b) + } + }) + b.Run("via Oblast", func(b *testing.B) { + for range b.N { + selectWithOblast(b) + } + }) + b.Run("just SQLite", func(b *testing.B) { + for range b.N { + selectWithSqlite(b) + } + }) +} |
