Skip to content

Commit 5608f0d

Browse files
committed
Optimize In by specializing for concrete slice types
1 parent f980a91 commit 5608f0d

File tree

2 files changed

+54
-4
lines changed

2 files changed

+54
-4
lines changed

bind.go

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,9 @@ func In(query string, args ...interface{}) (string, []interface{}, error) {
135135
}
136136

137137
newArgs := make([]interface{}, 0, flatArgsCount)
138+
buf := bytes.NewBuffer(make([]byte, 0, len(query)+len(", ?")*flatArgsCount))
138139

139140
var arg, offset int
140-
var buf bytes.Buffer
141141

142142
for i := strings.IndexByte(query[offset:], '?'); i != -1; i = strings.IndexByte(query[offset:], '?') {
143143
if arg >= len(meta) {
@@ -163,13 +163,12 @@ func In(query string, args ...interface{}) (string, []interface{}, error) {
163163
// write everything up to and including our ? character
164164
buf.WriteString(query[:offset+i+1])
165165

166-
newArgs = append(newArgs, argMeta.v.Index(0).Interface())
167-
168166
for si := 1; si < argMeta.length; si++ {
169167
buf.WriteString(", ?")
170-
newArgs = append(newArgs, argMeta.v.Index(si).Interface())
171168
}
172169

170+
newArgs = appendReflectSlice(newArgs, argMeta.v, argMeta.length)
171+
173172
// slice the query and reset the offset. this avoids some bookkeeping for
174173
// the write after the loop
175174
query = query[offset+i+1:]
@@ -184,3 +183,24 @@ func In(query string, args ...interface{}) (string, []interface{}, error) {
184183

185184
return buf.String(), newArgs, nil
186185
}
186+
187+
func appendReflectSlice(args []interface{}, v reflect.Value, vlen int) []interface{} {
188+
switch val := v.Interface().(type) {
189+
case []interface{}:
190+
args = append(args, val...)
191+
case []int:
192+
for i := range val {
193+
args = append(args, val[i])
194+
}
195+
case []string:
196+
for i := range val {
197+
args = append(args, val[i])
198+
}
199+
default:
200+
for si := 0; si < vlen; si++ {
201+
args = append(args, v.Index(si).Interface())
202+
}
203+
}
204+
205+
return args
206+
}

sqlx_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1726,6 +1726,36 @@ func BenchmarkIn(b *testing.B) {
17261726
}
17271727
}
17281728

1729+
func BenchmarkIn1k(b *testing.B) {
1730+
q := `SELECT * FROM foo WHERE x = ? AND v in (?) AND y = ?`
1731+
1732+
var vals [1000]interface{}
1733+
1734+
for i := 0; i < b.N; i++ {
1735+
_, _, _ = In(q, []interface{}{"foo", vals[:], "bar"}...)
1736+
}
1737+
}
1738+
1739+
func BenchmarkIn1kInt(b *testing.B) {
1740+
q := `SELECT * FROM foo WHERE x = ? AND v in (?) AND y = ?`
1741+
1742+
var vals [1000]int
1743+
1744+
for i := 0; i < b.N; i++ {
1745+
_, _, _ = In(q, []interface{}{"foo", vals[:], "bar"}...)
1746+
}
1747+
}
1748+
1749+
func BenchmarkIn1kString(b *testing.B) {
1750+
q := `SELECT * FROM foo WHERE x = ? AND v in (?) AND y = ?`
1751+
1752+
var vals [1000]string
1753+
1754+
for i := 0; i < b.N; i++ {
1755+
_, _, _ = In(q, []interface{}{"foo", vals[:], "bar"}...)
1756+
}
1757+
}
1758+
17291759
func BenchmarkRebind(b *testing.B) {
17301760
b.StopTimer()
17311761
q1 := `INSERT INTO foo (a, b, c, d, e, f, g, h, i) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`

0 commit comments

Comments
 (0)