From 69934dcd950f74c2757e2f30e5de2abcb2419215 Mon Sep 17 00:00:00 2001 From: Dominique Lefevre Date: Fri, 4 Jul 2025 14:11:46 +0300 Subject: [PATCH] Make fewer allocations in QueryContext(). For a simple query like `SELECT * FROM t WHERE id = $1`, QueryContext() used to make 6 allocations on average. Reduce that to 4 by avoiding two allocations that are immediately discarded: // the variadic arguments of c.conn.Query() escape, // so args is heap-allocated args := []any{databaseSQLResultFormats} // append() reallocates args to add enough space + // an array returned by namedValueToInterface() // is immediately discarded args = append(args, namedValueToInterface(argsV)...) --- stdlib/sql.go | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/stdlib/sql.go b/stdlib/sql.go index 4924fe41a..939b9636d 100644 --- a/stdlib/sql.go +++ b/stdlib/sql.go @@ -471,7 +471,8 @@ func (c *Conn) ExecContext(ctx context.Context, query string, argsV []driver.Nam return nil, driver.ErrBadConn } - args := namedValueToInterface(argsV) + args := make([]any, len(argsV)) + convertNamedArguments(args, argsV) commandTag, err := c.conn.Exec(ctx, query, args...) // if we got a network error before we had a chance to send the query, retry @@ -488,8 +489,9 @@ func (c *Conn) QueryContext(ctx context.Context, query string, argsV []driver.Na return nil, driver.ErrBadConn } - args := []any{databaseSQLResultFormats} - args = append(args, namedValueToInterface(argsV)...) + args := make([]any, 1+len(argsV)) + args[0] = databaseSQLResultFormats + convertNamedArguments(args[1:], argsV) rows, err := c.conn.Query(ctx, query, args...) if err != nil { @@ -848,28 +850,14 @@ func (r *Rows) Next(dest []driver.Value) error { return nil } -func valueToInterface(argsV []driver.Value) []any { - args := make([]any, 0, len(argsV)) - for _, v := range argsV { - if v != nil { - args = append(args, v.(any)) - } else { - args = append(args, nil) - } - } - return args -} - -func namedValueToInterface(argsV []driver.NamedValue) []any { - args := make([]any, 0, len(argsV)) - for _, v := range argsV { +func convertNamedArguments(args []any, argsV []driver.NamedValue) { + for i, v := range argsV { if v.Value != nil { - args = append(args, v.Value.(any)) + args[i] = v.Value.(any) } else { - args = append(args, nil) + args[i] = nil } } - return args } type wrapTx struct {