1 回答
TA贡献1805条经验 获得超10个赞
注意#1:sql.DB不代表连接,而是代表连接池。
注意#2:sql.Open初始化池,但它不必实际打开连接,只允许验证 dsn 输入,然后连接的打开将由池延迟处理。
你的第 db.Query一个慢的原因是因为你从一个新的连接池开始,一个有 0 个空闲(但打开)连接的连接池,因此第一个 db.Query需要首先建立与服务器的新连接,然后才会它能够执行sql语句。
你的第二个 db.Query也很慢的原因是因为第一个创建的连接还 db.Query没有释放回池中,因此你的第二个 db.Query也需要先与服务器建立新的连接才能执行sql语句。
要释放与池的连接,您需要首先保留 的主要返回值,db.Query然后调用其Close上的方法。
要从至少有一个可用连接的池开始,请Ping在初始化池后立即调用。
例子:
func main() {
// setup database connection
db, err := sql.Open("postgres", "postgres:///?sslmode=disable")
if err != nil {
panic(err)
} else if err := db.Ping(); err != nil {
panic(err)
}
for i := 0; i < 5; i++ {
// query database
firstQueryStart := time.Now()
rows, err := db.Query("select 1;")
firstQueryEnd := time.Now()
if err != nil {
panic(err)
}
// put the connection back to the pool so
// that it can be reused by next iteration
rows.Close()
fmt.Println(fmt.Sprintf("query #%d took %s", i, firstQueryEnd.Sub(firstQueryStart).String()))
}
}
我的机器上的时间(db.Ping只有 #0 很慢)
query #0 took 6.312676ms
query #1 took 102.88µs
query #2 took 66.702µs
query #3 took 64.694µs
query #4 took 208.016µs
我的机器上的时间(db.Ping#0 比没有快很多)
query #0 took 284.846µs
query #1 took 78.349µs
query #2 took 76.518µs
query #3 took 81.733µs
query #4 took 103.862µs
关于准备好的陈述的说明:
例如,如果您正在执行一个不带参数的简单查询,db.Query("select 1 where true")那么您实际上只是在执行一个简单查询。
但是,如果您正在执行带有参数的查询,例如db.Query("select 1 where $1", true),那么实际上,您正在创建和执行准备好的语句。
见4.2。值表达式,它说:
值表达式是以下之一: ...
位置参数引用,在函数定义或准备好的语句的主体中
......
位置参数也说:
位置参数引用用于指示从外部提供给 SQL 语句的值。参数用于 SQL 函数定义和准备好的查询中。一些客户端库还支持独立于 SQL 命令字符串指定数据值,在这种情况下,参数用于引用线外数据值。
postgres 的消息流协议如何指定simple queries和extended queries
扩展查询协议将上述简单查询协议分解为多个步骤。准备步骤的结果可以多次重复使用以提高效率。此外, 还提供了其他功能,例如可以将数据值作为单独的参数提供,而不必将它们直接插入到查询字符串中。
最后,在lib/pq司机的掩护下:
...
// Check to see if we can use the "simpleQuery" interface, which is
// *much* faster than going through prepare/exec
if len(args) == 0 {
return cn.simpleQuery(query)
}
if cn.binaryParameters {
cn.sendBinaryModeQuery(query, args)
cn.readParseResponse()
cn.readBindResponse()
rows := &rows{cn: cn}
rows.rowsHeader = cn.readPortalDescribeResponse()
cn.postExecuteWorkaround()
return rows, nil
}
st := cn.prepareTo(query, "")
st.exec(args)
return &rows{
cn: cn,
rowsHeader: st.rowsHeader,
}, nil
...
- 1 回答
- 0 关注
- 173 浏览
添加回答
举报