Anu*_*g M 3 postgresql go psql
我使用 golang 应用程序对本地 postgresql 实例运行相同的查询,并使用psql. 时间差异很大,我想知道为什么。使用解释/分析查询花费了 1 毫秒,database/sql在 golang 中使用,花费了 24 毫秒。我在下面添加了我的代码片段。我意识到解释/分析可能并不等同于直接查询数据库,并且可能还涉及一些网络延迟,但是差异仍然很大。为什么会出现这样的差异呢?
编辑:我已经尝试过使用 10 个以上查询的样本大小进行上述操作,并且差异仍然存在。
postgres=# \timing
Timing is on.
postgres=# select 1;
?column?
----------
1
(1 row)
Time: 2.456 ms
postgres=# explain analyze select 1;
QUERY PLAN
------------------------------------------------------------------------------------
Result (cost=0.00..0.01 rows=1 width=4) (actual time=0.002..0.002 rows=1 loops=1)
Planning Time: 0.017 ms
Execution Time: 0.012 ms
(3 rows)
Time: 3.748 ms
Run Code Online (Sandbox Code Playgroud)
package main
import (
"database/sql"
"fmt"
_ "github.com/lib/pq"
"time"
)
func main() {
// setup database connection
db, err := sql.Open("postgres", "host='localhost' port=5432 user='postgres' password='' dbname='postgres' sslmode=disable")
if err != nil {
panic(err)
}
// query database
firstQueryStart := time.Now()
_, err = db.Query("select 1;")
firstQueryEnd := time.Now()
if err != nil {
panic(err)
}
fmt.Println(fmt.Sprintf("first query took %s", firstQueryEnd.Sub(firstQueryStart).String()))
//run the same query a second time and measure the timing
secondQueryStart := time.Now()
_, err = db.Query("select 1;")
secondQueryEnd := time.Now()
if err != nil {
panic(err)
}
fmt.Println(fmt.Sprintf("second query took %s", secondQueryEnd.Sub(secondQueryStart).String()))
}
Run Code Online (Sandbox Code Playgroud)
first query took 13.981435ms
second query took 13.343845ms
Run Code Online (Sandbox Code Playgroud)
注意#1:sql.DB不代表连接,而是代表连接池。
注意#2:sql.Open初始化池,但不必实际打开连接,它只允许验证 dsn 输入,然后连接的打开将由池延迟处理。
第一个 缓慢的原因db.Query是因为您从一个新的连接池开始,该连接池有 0 个空闲(但打开)连接,因此第一个 db.Query需要首先建立到服务器的新连接,并且只有在此之后是否能够执行sql语句。
你的第二个 也很慢的原因是因为第一个db.Query创建的连接尚未释放回池中,因此你的第二个也需要先建立一个到服务器的新连接,然后才能执行sql语句。 db.Query db.Query
要将连接释放回池,您需要首先保留其主要返回值db.Query,然后调用Close其方法。
要从至少有一个可用连接的池开始,请Ping在初始化池后立即调用。
例子:
\nfunc main() {\n // setup database connection\n db, err := sql.Open("postgres", "postgres:///?sslmode=disable")\n if err != nil {\n panic(err)\n } else if err := db.Ping(); err != nil {\n panic(err)\n }\n\n for i := 0; i < 5; i++ {\n // query database\n firstQueryStart := time.Now()\n rows, err := db.Query("select 1;")\n firstQueryEnd := time.Now()\n if err != nil {\n panic(err)\n }\n\n // put the connection back to the pool so\n // that it can be reused by next iteration\n rows.Close()\n\n fmt.Println(fmt.Sprintf("query #%d took %s", i, firstQueryEnd.Sub(firstQueryStart).String()))\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n我的机器上的时间(没有db.Ping#0 很慢)
query #0 took 6.312676ms\nquery #1 took 102.88\xc2\xb5s\nquery #2 took 66.702\xc2\xb5s\nquery #3 took 64.694\xc2\xb5s\nquery #4 took 208.016\xc2\xb5s\nRun Code Online (Sandbox Code Playgroud)\n在我的机器上的时间(使用db.Ping#0 比不使用 #0 快很多)
query #0 took 284.846\xc2\xb5s\nquery #1 took 78.349\xc2\xb5s\nquery #2 took 76.518\xc2\xb5s\nquery #3 took 81.733\xc2\xb5s\nquery #4 took 103.862\xc2\xb5s\nRun Code Online (Sandbox Code Playgroud)\n如果您正在执行一个不带参数的简单查询,db.Query("select 1 where true")那么您实际上只是在执行一个简单的查询。
但是,如果您正在执行带参数的查询,那么db.Query("select 1 where $1", true)实际上您正在创建并执行准备好的语句。
见4.2。值表达式,它说:
\n\n\n值表达式是以下之一:...
\n\n
\n- 函数定义或预备语句主体中的位置参数引用
\n
\n...
位置参数还说:
\n\n\n位置参数引用用于指示从外部提供给 SQL 语句的值。参数用于 SQL\n函数定义和准备好的查询中。某些客户端库还支持与 SQL 命令字符串分开指定数据值,在这种情况下,参数用于引用外联数据值。
\n
postgres 的消息流协议如何指定simple queries和extended queries
\n\n扩展查询协议将上述简单查询协议分解为多个步骤。准备步骤的结果\n可以多次重复使用以提高效率。此外,还可以使用其他功能,例如可以将数据值作为单独的参数提供,而不必将它们直接插入查询字符串中。
\n
最后,在lib/pq司机的掩护下:
query #0 took 6.312676ms\nquery #1 took 102.88\xc2\xb5s\nquery #2 took 66.702\xc2\xb5s\nquery #3 took 64.694\xc2\xb5s\nquery #4 took 208.016\xc2\xb5s\nRun Code Online (Sandbox Code Playgroud)\n