Ответ
Кэширование на уровне драйвера БД основано не на кэшировании самих данных, а на кэшировании плана выполнения запроса. Этот механизм реализуется через подготовленные выражения (Prepared Statements
).
Процесс выглядит так:
-
Подготовка (Prepare): Ваше приложение отправляет в СУБД шаблон SQL-запроса с плейсхолдерами (
?
или$1
) вместо конкретных значений.// Шаблон отправляется в БД один раз stmt, err := db.PrepareContext(ctx, "SELECT name, age FROM users WHERE id = ?")
-
Парсинг и Оптимизация: СУБД получает этот шаблон, проверяет синтаксис, права доступа и строит оптимальный план выполнения. Этот план кэшируется на стороне СУБД и ассоциируется с уникальным идентификатором, который возвращается драйверу.
-
Выполнение (Execute): Когда вы вызываете
stmt.Query(1)
илиstmt.Exec(2)
, ваше приложение отправляет в СУБД только:- Идентификатор подготовленного плана.
- Значения параметров (
1
,2
и т.д.).
// Отправляются только параметры. План выполнения переиспользуется. row := stmt.QueryRowContext(ctx, 1) // ... row = stmt.QueryRowContext(ctx, 2)
Ключевые преимущества:
- Производительность: СУБД не тратит ресурсы на повторный парсинг и оптимизацию одного и того же SQL-запроса. Это особенно эффективно для часто выполняемых запросов.
- Безопасность: Использование
Prepared Statements
является основным способом защиты от SQL-инъекций, так как параметры передаются отдельно от самого SQL-кода и не могут его изменить.
Таким образом, кэшируется не результат (user с id=1
), а план запроса, что позволяет быстро выполнять однотипные запросы с разными параметрами.