Skip to content

Commit 410a109

Browse files
authored
Add benchmarks (#17)
1 parent 0764d24 commit 410a109

File tree

4 files changed

+103
-4
lines changed

4 files changed

+103
-4
lines changed

GUIDE.md

+17
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,20 @@ Both `%$` and `%?` formats can be extended with `+` or `#`:
3131
* `%#?` will expand slice of slices argument as `(?, ?), (?, ?), ... (?, ?)`
3232

3333
Argument must be a slice (for `+`) or a slice of slices (for `#`), otherwise the `.Build()` method returns an error.
34+
35+
## Speed
36+
37+
Even with the `fmt` packge speed is very good. If case you want zero-allocation query builder consider to cache query and just use it's value (works only for static queries like in `BenchmarkBuildCached`)
38+
39+
```
40+
goos: darwin
41+
goarch: arm64
42+
pkg: github.com/cristalhq/builq
43+
BenchmarkBuildNaive
44+
BenchmarkBuildNaive-10 299349 4214 ns/op 488 B/op 8 allocs/op
45+
BenchmarkBuildManyArgs
46+
BenchmarkBuildManyArgs-10 85747 14027 ns/op 1056 B/op 24 allocs/op
47+
BenchmarkBuildCached
48+
BenchmarkBuildCached-10 1000000000 0.6213 ns/op 0 B/op 0 allocs/op
49+
PASS
50+
```

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ This tiny library helps to build queries and handles parameter indexing.
1717
## Features
1818

1919
* Simple and easy.
20-
* Safe.
20+
* Safe & fast.
2121
* Tested.
2222
* Dependency-free.
2323

builq.go

+12-3
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,23 @@ func (b *Builder) Addf(format string, args ...any) *Builder {
3535
if b.err != nil {
3636
return b
3737
}
38+
// prealloc on first Addf
39+
if b.args == nil {
40+
b.query.Grow(100)
41+
b.args = make([]any, 0, 10)
42+
}
3843

3944
wargs := make([]any, len(args))
40-
for i, arg := range args {
41-
wargs[i] = &argument{value: arg, builder: b}
45+
for i := range args {
46+
wargs[i] = &argument{value: args[i], builder: b}
4247
}
4348

44-
fmt.Fprintf(&b.query, format+"\n", wargs...)
49+
_, err := fmt.Fprintf(&b.query, format, wargs...)
50+
if b.err == nil && err != nil {
51+
b.err = err
52+
}
4553

54+
b.query.WriteByte('\n')
4655
return b
4756
}
4857

builq_bench_test.go

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package builq_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/cristalhq/builq"
7+
)
8+
9+
func BenchmarkBuildNaive(b *testing.B) {
10+
for i := 0; i < b.N; i++ {
11+
var bb builq.Builder
12+
bb.Addf("SELECT %s FROM %s", "foo,bar", "table")
13+
bb.Addf("WHERE id = %$", 123)
14+
query, args, err := bb.Build()
15+
16+
switch {
17+
case err != nil:
18+
b.Fatal(err)
19+
case len(query) == 0:
20+
b.Fatal("empty query")
21+
case len(args) == 0:
22+
b.Fatal("empty args")
23+
}
24+
}
25+
}
26+
27+
func BenchmarkBuildManyArgs(b *testing.B) {
28+
for i := 0; i < b.N; i++ {
29+
var bb builq.Builder
30+
bb.Addf("SELECT %s FROM %s", "foo,bar", "table")
31+
bb.Addf("WHERE id = %$", 123)
32+
bb.Addf("AND user_id = %$ OR referral_id = %$", 123, 456)
33+
bb.Addf("OR status = %$ OR name = %$", "admin", "nice")
34+
bb.Addf("AND password LIKE %$ OR password = %$", "str0ng", "qwerty")
35+
bb.Addf("GROUP BY %$", "foo")
36+
bb.Addf("ORDER BY %$", "bar")
37+
bb.Addf("LIMIT %$;", 123)
38+
query, args, err := bb.Build()
39+
40+
switch {
41+
case err != nil:
42+
b.Fatal(err)
43+
case len(query) == 0:
44+
b.Fatal("empty query")
45+
case len(args) == 0:
46+
b.Fatal("empty args")
47+
}
48+
}
49+
}
50+
51+
func BenchmarkBuildCached(b *testing.B) {
52+
var bb builq.Builder
53+
bb.Addf("SELECT %s FROM %s", "foo,bar", "table")
54+
bb.Addf("WHERE id = %$", 123)
55+
bb.Addf("AND user_id = %$ OR referral_id = %$", 123, 456)
56+
bb.Addf("OR status = %$ OR name = %$", "admin", "nice")
57+
bb.Addf("GROUP BY %$", "foo")
58+
bb.Addf("ORDER BY %$", "bar")
59+
bb.Addf("LIMIT %$;", 123)
60+
query, args, err := bb.Build()
61+
b.ResetTimer()
62+
63+
for i := 0; i < b.N; i++ {
64+
switch {
65+
case err != nil:
66+
b.Fatal(err)
67+
case len(query) == 0:
68+
b.Fatal("empty query")
69+
case len(args) == 0:
70+
b.Fatal("empty args")
71+
}
72+
}
73+
}

0 commit comments

Comments
 (0)