И така, въпросът ви най-накрая се свежда до „как java.sql.PreparedStatement
играе с PostgreSQL". Вижте накрая отговора на тема "как това работи с подготвени от сървъра планове".
Ето отговора:това зависи от JDBC драйвера, който използвате.
TL;DR :в съвременните драйвери изявлението, подготвено от сървъра, остава до прекратяване на връзката или докато изявлението не бъде изгонено от друг (обикновено изгонване на LRU).
Забележка:Сървърът на PostgreSQL не може да споделя подготвен израз между връзки към база данни, поради което най-добрият JDBC драйвер, който може да направи, е да поддържа плана в кеша във всяка връзка.
Забележка:Спецификацията на JDBC изисква използването на ?, ?
за контейнери за свързване, докато сървърът иска $1, $2
по този начин JDBC драйверите също кешират така наречените анализирани SQL текстове.
Има два добре познати JDBC драйвера:pgjdbc и pgjdbc-ng
pgjdbc
https://github.com/pgjdbc/pgjdbc
От pgjdbc 9.4-1202
той автоматично кешира планове от страна на сървъра, когато използва PreparedStatement
.Забележка:изразите се кешират дори ако close()
PreparedStatement
.За да стигнете до подготовка от страна на сървъра, трябва да изпълните заявката 5 пъти (което може да бъде конфигурирано чрез prepareThreshold
).
В момента кешът се прилага за всяка връзка. По подразбиране pgjdbc кешира 256 (preparedStatementCacheQueries
) заявки и до preparedStatementCacheSizeMiB
от заявки. Това е консервативна настройка, така че може да искате да я коригирате. Вижте документация
за описанието на свойствата. Кешът включва както анализирани, така и подготвени от сървъра изрази.
проблем с github:https://github.com/pgjdbc/pgjdbc/pull/319
pgjdbc-ng
https://github.com/impossibl/pgjdbc-ng
Не съм в pgjdbc-ng, но изглежда, че прави и двете синтактични анализи (размерът на кеша по подразбиране е 250 заявки) и подготовка на сървъра (размерът на кеша по подразбиране е 50 запитвания). Поддръжката на подготвени от страна на сървъра отчети се появи на 24 февруари 2014 г., така че ако използвате малко по-нова версия, можете да получите кеширане на отчети.
Забележка:ако случайно използвате много дълги заявки, можете да натиснете OutOfMemory
тъй като pgjdbc-ng не може да изгонва записи въз основа на броя на запазените байтове.
Кешът е за всяка връзка, така че се използва прозрачно дори ако затворите изрази.
Не мога да кажа много за производителността на pgjdbc-ng, въпреки че от последния път, когато се опитах да му хвърля jmh, се провали със случайни изключения.
проблем с github:https://github.com/impossibl/pgjdbc-ng/pull/ 69
Планове, подготвени от сървъра
PostgreSQL има PREPARE
и DEALLOCATE
команди за препратка към оператора при изпращане на EXEC
над жицата. Той оптимизира две неща:
- Когато използвате
PREPARE
d оператор (с други думи, подготвен от сървъра), клиентът не трябва да изпраща текст на заявка отново и отново. Той просто изпраща кратко име на заявка и стойностите за свързващите променливи. - От 9.2 базата данни все още се опитва да планира повторно първите няколко изпълнения на заявка. Това прави, за да опита дали заявката се нуждае от множество планове или дали общият план е достатъчно добър. В крайна сметка (незабавно, ако заявката няма параметри), базата данни може да премине към общ план .
- От 12 има настройка за принудително изпълнение на ВСИЧКИ подготвени от сървъра изрази с общи или персонализирани планове:plan_cache_mode
=
auto | force_custom_plan | force_generic_plan
С други думи, PreparedStatement
оптимизира както анализирането на заявки от страната на JDBC, така и планирането на заявки от страната на базата данни.
Повече информация тук:http://blog.endpoint .com/2014/04/custom-plans-prepared-statements-in.html
Подготвени изрази в PL/pgSQL
Според документацията PostgreSQL кешира планове за заявки, използвани в PL/pgSQL. Това се случва след няколко изпълнения (3 или 5, не помня точния праг), така че след като създадете съхранена процедура, може да е малко бавно, но след това ще премине към кеширани планове (при условие, че базата данни се съгласява да използва общ план за конкретна заявка).
С други думи, за да постигнете „кеширани планове за изпълнение“, или трябва да използвате актуален JDBC драйвер, или можете да обвиете всичките си заявки в съхранени процедури. Извикването на процедурата ще се планира отново при всяко изпълнение, но самото извикване е обикновено много по-кратък от заявките, които съставят процедурата.