Я новичок в Голанге и пытаюсь написать простой веб-сервер с ответом json. Одна из конечных точек - для доступа к базе данных. При статическом ответе (таком как любая статическая строка или простое преобразование данных) среднее время ответа составляет около 0 с (<1 мс). Если я добавлю какой-нибудь запрос к базе данных, среднее время увеличится до 250 мс, и это не зависит от содержимого функции. Поэтому я пытаюсь понять время этой функции. </p>
Что я уже знаю:
- Запрос к БД стоит около 40-50 мс
- Расходы на преобразование даты и времени> 1 мс
json.Marshal
стоит <1 мс </li>
string(json.Marshal)
<1 мс </li>
Вся моя проблема в rows.Next()
:
- все внутри
rows.Next()
стоит <1 мс отдельно </li>
- Стоимость каждой
row.Next()
процедуры зависит от длины строки и составляет около 10-50 мс.
Если я понимаю, db.Query()
получает все строки в одном запросе и сохраняет его в памяти, предоставляя виртуальный курсор в качестве итератора (.Next()
). Почему это так дорого стоит?
- Все
row.Next()
обработка данных стоит около 180 мс. При 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)
}
Можно ли ожидать, что время отклика веб-сервера будет примерно равно времени запроса базы данных?
UPDATE.
Я пробовал "github.com/jmoiron/sqlx" с "github.com/kshvakov/clickhouse", и результат был таким же; изменен только синтаксис.
Я также попробовал "github.com/mailru/go-clickhouse" с "database / sql". Он предоставляет доступ к HTTP-интерфейсу для clickhouse. Я получил все строки в одном запросе, как и ожидалось, но он требует около 240 мс для HTTP-запроса и около 0 мс для обработки данных. Поэтому я ищу возможность держать соединение TCP открытым, чтобы можно было получить все строки nessasery в одном запросе и работать с моей буфера памяти на стороне программы (с некоторым ограничением буфера в сочетании с буфером TCP / сокета).
ОБНОВЛЕНИЕ 2.
Хорошо, я пробовал собственный клиент clickhouse (и другой такой DBeaver), и ограничение приблизительно 250 мс для этого запроса. Но это может быть только ограничение родного TCPP интерфейса clickhouse.
Но что такое операция 40-50ms db.Query (), которая не возвращает строк. Время для запроса на стороне сервера? Или просто проверка строки запроса?