|
|
|
ConnectionPool + PreparedStatements, вопрос-дискуссия
|
|||
|---|---|---|---|
|
#18+
Всем привет! Пришла в голову идея скрестить ConnectionPool + PreparedStatements, но перед использованием хочу прояснить некоторые моменты. Оговорюсь, что все ниже написанное предполагает использование MySql. Плюс использования пула- соединение создается не не при каждом запросе от клиента, а используется из пула. Подробности про создание нового, если нет свободных или ожидание свободного соединения я опущу, сейчас суть не в этом. Плюс использования PreparedStatements - помимо защиты от инъекций, использование этой штуки предотвращает синтаксический разбор и попытки движка оптимизировать запрос - то есть, если один и тот же запрос занимает 90% всех запросов в системе( как раз мой случай), можно его "запрепарировать" и избавиться от выполнения одних и тех же Действий движком СУБД. Вопрос: когда мы делаем someConnection.prepareStatement("query"), созданный PreparedStatement хранится где-то в кэше СУБД или же в этом объекте - то есть, уничтожив этот объект, либо создавая каждый раз его заново, мы теряем его и в итоге все плюсы использования PS или же даже при уничтожении этого объекта движок СУБД понимает, что такой запрос уже был "запрепарирован" и не выполняет разбор+оптимизацию? Если ответ да, СУБД хранит инфу о таких вещах и даже многократный вызов someConnection.prepareStatement("query") одного и того же запроса не вызывает повторной подготоки Statement-а, а вытаскивается из кеша тогда расходимся, мои дальнейшие рассуждения отпадают) Если ответ нет, не хранит и для получения пользы от PreparedStatement, его нужно хранить и пользоваться впоследствии этим же объектом, тогда есть такие тезисы, которые я хотел бы обсудить, подвергнуть критике: 1) Храним в пуле не только соединения, но и PreparedStatement на самый частый, Bottle Neck запрос. 2) При запросе соединения из пула для выполнения какого-либо запроса передаем буллевый флаг - это Bottle Neck запрос или простой запрос. В первом случае пул пользуется подготовленным ранее PreparedStatement-ом, во втором случае просто делаем что-то вроде Код: java 1. 2. 3) Понятно, что если у Вас в системе нет очень частых однообразных запросов, тогда глупо использовать идею, приведенную выше - вы не почувствуете разницу от того, парсит ли движок СУБД ваш запрос каждый раз или нет, если он выполняется раз в день или раз в неделю, если это запрос,например, на генерацию отчета. 4) А что если у Вас десятки разных запросов и есть несколько Bottle Neck-ов? Если бы было 1-5 таких, можно было бы вместо буллевого флага передавать цифру - 1,2,3,4,5 - номер Bottle Neck, запроса или -1 - когда просто пользуемся соединением - кусочек кода из пункта 2. Но если Bottle Neck-ов 10-20 или более, не будете же Вы хардкодить все эти варианты и потом еще пистаь аццкий switch case вида Код: java 1. 2. 3. 4. 5. 6. 7. Выход есть - В пуле теперь хранится вместо пары (Connection conn, PreparedStatement bottleNeck) пара (Connection conn, HashSet<String,PreparedStatement> bottleNecks) - то есть при выполнение запроса смотрим, есть ли он в сете, если нет - это простой запрос, если есть - вытаскиваем из сета и пользуемся. Но как создавать/инициализировать этот сет? Создаем файл с тестом наших Bottle Neck запросов, естественно оформляя подставляемые параметры как "?", и в конструкторе объекта пула считываем с файла и "препарим" их. Собственно все, хотелось бы услышать конструктивную критику, идеи для дальнейшего улучшения либо опыт использования такой конструкции, если таковой был. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.03.2013, 10:07:52 |
|
||
|
ConnectionPool + PreparedStatements, вопрос-дискуссия
|
|||
|---|---|---|---|
|
#18+
BaurzhanS Если ответ да, СУБД хранит инфу о таких вещах и даже многократный вызов someConnection.prepareStatement("query") одного и того же запроса не вызывает повторной подготоки Statement-а, а вытаскивается из кеша тогда расходимся, мои дальнейшие рассуждения отпадают) СУБД кеширует по тексту запроса его план и повторно не парсит SQL, если запрос 1-в-1 совпадает. Смысла кешировать экземпляры при наличии young generation в GC особого нет. Чем рассуждать, можно было написать тестовый пример и посмотреть, будет ли какая-то выгода, или нет. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.03.2013, 12:44:13 |
|
||
|
ConnectionPool + PreparedStatements, вопрос-дискуссия
|
|||
|---|---|---|---|
|
#18+
Пришла в голову идея скрестить ConnectionPool + PreparedStatements Уже реализовали такую идею, почитайте документацию по имеющимся пулам. Вообще, в случае mysql вы ускорения не добьетесь, потому что парсер там быстр а оптимизатор туп (это не оракл). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.03.2013, 20:18:13 |
|
||
|
ConnectionPool + PreparedStatements, вопрос-дискуссия
|
|||
|---|---|---|---|
|
#18+
СУБД кеширует по тексту запроса его план и повторно не парсит SQL, если запрос 1-в-1 совпадает. В постгресе и mysql после подготовки запроса сервер выдает id подготовленного запроса. Клиент должен запомнить этот id. В оракле конечно удобнее сделано. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.03.2013, 20:20:38 |
|
||
|
ConnectionPool + PreparedStatements, вопрос-дискуссия
|
|||
|---|---|---|---|
|
#18+
Blazkowicz, насчет Blazkowiczповторно не парсит SQL, если запрос 1-в-1 совпадает. - имеется в виду что даже подставляемые параметры должны совпадать, например select * from ttt where x=111 и select * from ttt where x=222, это одинаковые запросы? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.03.2013, 20:56:22 |
|
||
|
ConnectionPool + PreparedStatements, вопрос-дискуссия
|
|||
|---|---|---|---|
|
#18+
BaurzhanSBlazkowicz, насчет Blazkowiczповторно не парсит SQL, если запрос 1-в-1 совпадает. - имеется в виду что даже подставляемые параметры должны совпадать, например select * from ttt where x=111 и select * from ttt where x=222, это одинаковые запросы? Имеется ввиду, что если вместо binding variables Код: sql 1. инлайнить параметры Код: sql 1. то СУБД не сможет кешировать такие запросы, а будет каждый раз их парсить и составлять план запроса. Возможно это где-то уже решается. Но это больше вопрос к реализации СУБД. В общем случае так делать не стоит. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.03.2013, 21:26:34 |
|
||
|
ConnectionPool + PreparedStatements, вопрос-дискуссия
|
|||
|---|---|---|---|
|
#18+
СУБД не сможет кешировать такие запросы, а будет каждый раз их парсить и составлять план запроса В оракле для этого есть cursor_sharing=force ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.03.2013, 21:38:54 |
|
||
|
ConnectionPool + PreparedStatements, вопрос-дискуссия
|
|||
|---|---|---|---|
|
#18+
Йуный джавистЪВ оракле для этого есть cursor_sharing=force Да, понятно, что это технически решаемо. Но запрос всё равно парсится чтобы идентифицировать литералы, которые можно заменить на параметры. Опять же, то Oracle. А все ли так умеют? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.03.2013, 22:03:33 |
|
||
|
|

start [/forum/topic.php?fid=59&gotonew=1&tid=2129861]: |
0ms |
get settings: |
15ms |
get forum list: |
27ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
27ms |
get topic data: |
11ms |
get first new msg: |
7ms |
get forum data: |
2ms |
get page messages: |
49ms |
get tp. blocked users: |
2ms |
| others: | 304ms |
| total: | 452ms |

| 0 / 0 |
