А в чем, собственно, сам вопрос? Буду рад ответить.
К сожалению, если бы я останавливался на каждых деталях реализации и возможностях библиотеки, то одной статьей здесь бы не обошлось. Да и вряд ли бы я вообще смог закончить такую серию статей.
Я старался сжато показать и рассказать именно про настройку пула соединений, отметить основные моменты и сделать этот процесс более осознанным, чтобы лучше понимать как это может влиять на сервис.
Спасибо за хороший вопрос, ответ на который может даже претендовать на отдельную статью) Но постараюсь ответить коротко и понятно. Для начала, определим как происходит подготовка запроса для общего понимания:
Клиент отправляет команду серверу на подготовку запроса с плейсхолдерами;
Сервер обрабатывает запрос и возвращает идентификатор подготовленного выражения;
Клиент выполняет запрос отправляя серверу идентификатор подготовленного выражения и параметры, с которыми должен выполниться запрос.
Для подготовки выражения мы можем воспользоваться методом (*DB).Prepare(), который после выполнения подготовки вернет нам ссылку на структуру *Stmt.
Метод (*DB).Prepare() никак не учитывает настройку interpolateParams, он просто отправляет команду mysql серверу.
Чтобы выполнить запрос с подготовленным выражением нужно воспользоваться методом (*Stmt) Query(), замечу, что это другой метод, отличный от метода (*DB) Query()
Отвечая на первый вопрос, при выполнении (*Stmt) Query() настройка interpolateParams не учитывается, мы явно просим библиотеку выполнить подготовку на сервере и потом отправляем вторую команду на выполнение запроса для подготовленного выражения.
По второму вопросу, да, подготовленное выражение завязывается на соединение, и тут есть нюанс. Если при выполнении (*Stmt) Query() соединение, с которым выполнялась подготовка, недоступно (занято или вовсе закрылось), то будет создано (взято из пула) новое соединение и снова выполнится команда подготовки выражения, и только потом уже сам запрос. Это может привести к лишним подготовкам одних и тех же запросов. Метод (*Stmt) Close() при этом закрывает выражение и выполнение запросов после этого приведет к ошибке sql: statement is closed.
Да, (rs *Rows) Next() действительно освобождает соединение. Но тут слишком много "если". В defer нужно оставлять вызов Close() для надежности. Например, может возникнуть паника до того, как мы дошли до конца используя метод Next(). Поэтому я бы советовал все же в defer оставить освобождение соединения. И ничего страшного если мы вызовем метод Close() лишний раз.
Выбор происходит по условию price = 1950. Находим цену в индексе и, если нет covering index, то за данными (select *) будет одно обращение к диску (если в табличке одна запись с ценой 1950).
Да, MySQL использует статистику. Но цель рассматриваемого примера в статье — наглядно показать уменьшение количества чтений. И для этого «изобретался» способ решить возникшую проблему. А именно, вынести цены в отдельную табличку index_1, которая помещается на 250 кластерах диска, прочитать ее полностью, найти цену 1950 и по соответствующей ссылке получить данные из основной таблицы. Поэтому в расчетах получили чтение 251 кластера.
Спасибо за проделанную работу и подробные результаты 🔥
Буду работать над подачей материала в следующих статьях)
А в чем, собственно, сам вопрос? Буду рад ответить.
К сожалению, если бы я останавливался на каждых деталях реализации и возможностях библиотеки, то одной статьей здесь бы не обошлось. Да и вряд ли бы я вообще смог закончить такую серию статей.
Я старался сжато показать и рассказать именно про настройку пула соединений, отметить основные моменты и сделать этот процесс более осознанным, чтобы лучше понимать как это может влиять на сервис.
Спасибо за хороший вопрос, ответ на который может даже претендовать на отдельную статью)
Но постараюсь ответить коротко и понятно.
Для начала, определим как происходит подготовка запроса для общего понимания:
Клиент отправляет команду серверу на подготовку запроса с плейсхолдерами;
Сервер обрабатывает запрос и возвращает идентификатор подготовленного выражения;
Клиент выполняет запрос отправляя серверу идентификатор подготовленного выражения и параметры, с которыми должен выполниться запрос.
Для подготовки выражения мы можем воспользоваться методом
(*DB).Prepare()
, который после выполнения подготовки вернет нам ссылку на структуру*Stmt
.Метод
(*DB).Prepare()
никак не учитывает настройкуinterpolateParams
, он просто отправляет команду mysql серверу.Чтобы выполнить запрос с подготовленным выражением нужно воспользоваться методом
(*Stmt) Query()
, замечу, что это другой метод, отличный от метода(*DB) Query()
Отвечая на первый вопрос, при выполнении
(*Stmt) Query()
настройкаinterpolateParams
не учитывается, мы явно просим библиотеку выполнить подготовку на сервере и потом отправляем вторую команду на выполнение запроса для подготовленного выражения.По второму вопросу, да, подготовленное выражение завязывается на соединение, и тут есть нюанс. Если при выполнении
(*Stmt) Query()
соединение, с которым выполнялась подготовка, недоступно (занято или вовсе закрылось), то будет создано (взято из пула) новое соединение и снова выполнится команда подготовки выражения, и только потом уже сам запрос. Это может привести к лишним подготовкам одних и тех же запросов. Метод(*Stmt) Close()
при этом закрывает выражение и выполнение запросов после этого приведет к ошибкеsql: statement is closed
.Надеюсь я смог чем-то помочь.
Спасибо за дополнение.
Не против, если добавлю к статье как UPD ?
Да,
(rs *Rows) Next()
действительно освобождает соединение. Но тут слишком много "если". Вdefer
нужно оставлять вызовClose()
для надежности. Например, может возникнуть паника до того, как мы дошли до конца используя методNext()
. Поэтому я бы советовал все же в defer оставить освобождение соединения. И ничего страшного если мы вызовем методClose()
лишний раз.В таблице обозначена одна запись с ценой 1950 (смотрите рисунки).
Выбор происходит по условию price = 1950. Находим цену в индексе и, если нет covering index, то за данными (select *) будет одно обращение к диску (если в табличке одна запись с ценой 1950).
Да, MySQL использует статистику. Но цель рассматриваемого примера в статье — наглядно показать уменьшение количества чтений. И для этого «изобретался» способ решить возникшую проблему. А именно, вынести цены в отдельную табличку index_1, которая помещается на 250 кластерах диска, прочитать ее полностью, найти цену 1950 и по соответствующей ссылке получить данные из основной таблицы. Поэтому в расчетах получили чтение 251 кластера.