我是 Golang 的新手,正在尝试使用 json 响应编写简单的 Web 服务器。端点之一是用于数据库访问。使用类静态响应(如任何静态字符串或简单数据转换)的平均响应时间约为 0s(<1ms)。如果我添加一些数据库请求,平均时间会增加到 250 毫秒,并且不取决于函数内容。所以我试图了解这个功能的时间。
我已经知道的:
- 查询数据库大约需要 40-50 毫秒
- 日期时间转换成本 >1ms
json.Marshal成本<1msstring(json.Marshal)<1ms
我所有的问题都在rows.Next():
- 所有内部
rows.Next()成本分别<1ms - 每个
row.Next()过程的成本取决于行长,大约为 10-50ms。
如果我理解db.Query()在一个请求中获取所有行并将其保存在内存中,提供虚拟游标作为迭代器(.Next())。为什么要花这么多钱?
- 所有
row.Next()数据处理大约需要 180ms。加上40 毫秒db.Query,它大约等于总响应时间(~240 毫秒) - 如果我评论所有
row.Next()周期并且只做出db.Query总响应仍然需要 200-240 毫秒
我使用的软件包:
import (
"database/sql"
"encoding/json"
"fmt"
"log"
"os"
"strconv"
"time"
"github.com/kshvakov/clickhouse"
routing "github.com/qiangxue/fasthttp-routing"
"github.com/valyala/fasthttp"
)
func getRecs(client string, dt string) string {
dtT := transformDate(&dt)
rows, err := db.Query(getRecsRequest(&client, &dtT))
if err != nil {
log.Fatal(err)
}
defer rows.Close()
start := time.Now()
got := []databaseRows{}
elapsed := time.Since(start)
for rows.Next() {
elapsed = time.Since(start)
log.Printf("Next took %s", elapsed)
var r databaseRows
err := rows.Scan(&r.ItemIds, &r.DtRecommendation, &r.Number)
if err != nil {
log.Fatal(err)
}
got = append(got, r)
start = time.Now()
}
jsonData, err := json.Marshal(&got)
return string(jsonData)
}
func getRecs(client string, dt string) string {
dtT := transformDate(&dt)
rows, err := db.Query(getRecsRequest(&client, &dtT))
if err != nil {
log.Fatal(err)
}
defer rows.Close()
// start := time.Now()
got := "[]databaseRows{}"
// elapsed := time.Since(start)
// for rows.Next() {
// elapsed = time.Since(start)
// log.Printf("Next took %s", elapsed)
// var r databaseRows
// err := rows.Scan(&r.ItemIds, &r.DtRecommendation, &r.Number)
// if err != nil {
// log.Fatal(err)
// }
// got = append(got, r)
// start = time.Now()
// }
jsonData, err := json.Marshal(&got)
return string(jsonData)
}
我可以期望 Web 服务器响应时间与数据库请求时间有关吗?
更新。
我用“github.com/kshvakov/clickhouse”尝试了“github.com/jmoiron/sqlx”,结果是一样的;只有语法改变了。
我还尝试了“github.com/mailru/go-clickhouse”和“database/sql”。它提供了对 clickhouse 的 HTTP 接口的访问。我按预期在一个请求中获得了所有行,但是 http 请求大约需要 240 毫秒,数据处理大约需要 0 毫秒。所以我正在寻找机会保持 tcp 连接打开,以便能够在一个请求中获取所有 nessasery 行并工作使用我的程序端内存缓冲区(与 tcp/socket 缓冲区组合有一些缓冲区限制)。
更新 2。
好的,我已经尝试过原生 clickhouse 客户端(和其他类似的 DBeaver),大约 250 毫秒是这个请求的限制。但这可能只是clickhouse原生tcp接口的限制。但是什么是 40-50ms db.Query() 操作,它不返回任何行。是服务器端查询的时间吗?或者只是查询字符串检查?