Использование QueryRow через оператор или базу данных в пределах Go - PullRequest
0 голосов
/ 22 февраля 2020

Способы выполнения запросов ниже выдают точно такие же ( количество 3 ) запросов в БД, что хорошо и понятно - см. Ниже . Тем не менее, я хочу знать, что с точки зрения Go существует ли реальная разница между двумя типами: память, процессор, кэш, использование соединений и т. Д.?

Запросы

2020-02-22T12:29:23.858393Z 41 Prepare SELECT id, uuid, name FROM users WHERE id = ?
2020-02-22T12:29:23.859601Z 41 Execute SELECT id, uuid, name FROM users WHERE id = 1
2020-02-22T12:29:23.861607Z 41 Close   stmt

Методы

func Select1(query string, args ...interface{}) (*sql.Row, error) {
    stmt, err := DB.Prepare(query)
    if err != nil {
        return nil, err
    }
    defer stmt.Close()

    return stmt.QueryRow(args...), nil
}
func Select2(query string, args ...interface{}) *sql.Row {
    return DB.QueryRow(query, args...)
}

Ответы [ 2 ]

1 голос
/ 23 февраля 2020

В дополнение к тому, что @mkopriva сказал в комментариях о клиентской стороне, есть серверная возможность использования подготовленных операторов.

Важно отметить, что использование *sql.DB использует пул соединений :

БД - это дескриптор базы данных, представляющий пул из нуля или более базовых соединений

Почему это важно? Хорошо параллельный доступ может инициировать несколько физических соединений. А при использовании подготовленных операторов, которые предназначены для повторного использования, они эффективны только при использовании в том же сеансе базы данных (т.е. соединение).

Пул соединений (используя *sql.DB) его природа не гарантирует этого. Таким образом, при 100 одновременных запросах - теоретически может быть 100 одновременных соединений с базой данных, генерирующих - не один - но до 100 подготовленных операторов на на стороне сервера .

Вы можете получить одно соединение с БД через sql .DB.Conn () , где:

Запросы, запущенные на том же Conn, будут выполняться в той же базе данных сеанс.

означает, что любой ранее сгенерированный подготовленный оператор получит преимущества от повторного использования (так как они используют один и тот же "сеанс").

В заключение, взвесьте преимущества подготовленного оператора. заявление о влиянии клиента и на сервер, а также о том, действительно ли вы получаете эти преимущества от одновременного использования.

0 голосов
/ 27 февраля 2020

Я потратил больше времени на тестирование и профилирование, так что это мой вывод - также подтверждает комментарии @ mkopriva.

Если используется оператор SELECT, с заполнителями запросов или без них, вы должны предпочесть используя DB.Query и / или DB.QueryRow вместо комбинации DB.Prepare & STMT.Exec. Когда я проверял журналы запросов MySQL, это выглядело как DB.Query и DB.QueryRow , которые действовали , как если бы они были DB.Exec для запросов, в которых не было аргументов-заполнителей. Это означает только одну (Query) сеть в обоих направлениях вместо три (Prepare, Execute и Close)!

Так почему не просто использовать DB.Exec тогда? Потому что он используется для запросов, которые не возвращают набор результатов. Кстати, DB.Exec освобождает свое соединение прямо обратно в пул, но DB.Query не позволяет подключиться к нему до тех пор, пока не будет вызван rows.Close(). Если вы забудете позвонить, это может привести к «утечке» и недоступности соединений. Технически, DB.Query сопряжен со своими рисками, если вы делаете что-то не так.

Последнее замечание, если ваши INSERT, UPDATE и DELETE аргументы запроса SQL не содержат инъекций, тогда используйте DB.Exec, в противном случае используйте DB.Prepare. Для ручной подготовки аргументов запроса вы можете использовать функцию fmt.Sprintf () .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...