Postgres 9.6.17 и JDB C 42.2.1 как переключить режим соединения в «расширенный» - PullRequest
1 голос
/ 18 февраля 2020

У меня есть СУБД Postgres 9.6.17 и простая Java отдельная программа (без Spring), которая подключается к СУБД и выдает запрос. На основе документации Postgres запрос может быть выполнен в «простом режиме» или «расширенном режиме» (где разбор и перезапись запроса выполняются за один раз), но привязка происходит неоднократно.

У меня есть простая таблица customer(cust_id integer, first_name varchar(100), last_name varchar(100)). Код, который я выполняю, выглядит следующим образом:

Properties props = new Properties();
....//typical properties such as user, password, database etc
props.setProperty("preferQueryMode", "extendedForPrepared");
Connection con = DriverManager.getConnection(url, props);
PreparedStatement st = con.prepareStatement("select * from ecommerce.customer where cust_id = ?");
st.setInt(1, 22);
ResultSet rs = st.executeQuery();    

Я надеялся, что это приведет к использованию протокола «расширенного режима запроса» между клиентом JDB C и бэкэндом СУБД. Но он продолжает производить «простой режим запроса» взаимодействия. Я подтвердил это, включив ведение журнала JDB C для драйвера postgres. Я также посмотрел на реализации интерфейса Query в драйвере JDB C, и все, что я мог найти, это 3 реализации следующим образом:

  1. BatchedQuery
  2. CompositeQuery
  3. SimpleQuery

Несмотря на название CompositeQuery, все, что он делает, это разбивает запрос, включающий несколько операторов, в список SimpleQuery объектов.

Итак, мой вопрос: что я могу сделать, чтобы получить протокол, используемый моим подключением к расширенному режиму?

1 Ответ

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

По умолчанию драйвер Postgres JDB C начинает использовать операторы на стороне сервера только после того, как подготовленный оператор используется 5 раз. Из документации по свойствам драйвера JDB C :

prepareThreshold = int

Определите количество выполнений PreparedStatement, необходимых перед переключением на использование подготовленных операторов на стороне сервера , Значение по умолчанию - пять, что означает начало использования подготовленных операторов на стороне сервера при пятом выполнении того же объекта PreparedStatement. Дополнительная информация о подготовленных инструкциях на стороне сервера доступна в разделе «Готовые операторы сервера».

Но это свойство можно изменить.

Это программа, с которой я тестировал:

Properties props = new Properties();
props.setProperty("user", "test");
props.setProperty("password", "test");
props.setProperty("loggerLevel", "TRACE");
props.setProperty("prepareThreshold", "1");
try (Connection con = DriverManager.getConnection("jdbc:postgresql:test", props);
     PreparedStatement stat = con.prepareStatement("select * from app_user where username = ?"))
{
    for (String username : List.of("user1", "user2", "user3"))
    {
        stat.setString(1, username);
        try (ResultSet rs = stat.executeQuery())
        {
            if (rs.next())
                System.out.println("User " + username + " has ID: " + rs.getString(1));
        }
    }
}

Когда для prepareThreshold установлено значение 1, журналы показывают:

Feb 18, 2020 1:56:59 PM org.postgresql.core.v3.QueryExecutorImpl execute
FINEST:   simple execute, handler=org.postgresql.jdbc.PgStatement$StatementResultHandler@33065d67, maxRows=0, fetchSize=0, flags=16
Feb 18, 2020 1:56:59 PM org.postgresql.core.v3.QueryExecutorImpl sendParse
FINEST:  FE=> Parse(stmt=S_1,query="select * from app_user where username = $1",oids={1043})
Feb 18, 2020 1:56:59 PM org.postgresql.core.v3.QueryExecutorImpl sendBind
FINEST:  FE=> Bind(stmt=S_1,portal=null,$1=<'user1'>)
Feb 18, 2020 1:56:59 PM org.postgresql.core.v3.QueryExecutorImpl sendDescribePortal
FINEST:  FE=> Describe(portal=null)
Feb 18, 2020 1:56:59 PM org.postgresql.core.v3.QueryExecutorImpl sendExecute
FINEST:  FE=> Execute(portal=null,limit=0)
...
Feb 18, 2020 1:56:59 PM org.postgresql.core.v3.QueryExecutorImpl execute
FINEST:   simple execute, handler=org.postgresql.jdbc.PgStatement$StatementResultHandler@35dab4eb, maxRows=0, fetchSize=0, flags=16
Feb 18, 2020 1:56:59 PM org.postgresql.core.v3.QueryExecutorImpl sendBind
FINEST:  FE=> Bind(stmt=S_1,portal=null,$1=<'user2'>)
Feb 18, 2020 1:56:59 PM org.postgresql.core.v3.QueryExecutorImpl sendExecute
FINEST:  FE=> Execute(portal=null,limit=0)
...
Feb 18, 2020 1:56:59 PM org.postgresql.core.v3.QueryExecutorImpl execute
FINEST:   simple execute, handler=org.postgresql.jdbc.PgStatement$StatementResultHandler@2d901eb0, maxRows=0, fetchSize=0, flags=16
Feb 18, 2020 1:56:59 PM org.postgresql.core.v3.QueryExecutorImpl sendBind
FINEST:  FE=> Bind(stmt=S_1,portal=null,$1=<'user3'>)
Feb 18, 2020 1:56:59 PM org.postgresql.core.v3.QueryExecutorImpl sendExecute
FINEST:  FE=> Execute(portal=null,limit=0)

, которые показывают, что анализ запроса происходит один раз, затем повторяются привязки.


Сравните это с тем, когда prepareThreshold не установлено:

Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl execute
FINEST:   simple execute, handler=org.postgresql.jdbc.PgStatement$StatementResultHandler@33065d67, maxRows=0, fetchSize=0, flags=17
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendParse
FINEST:  FE=> Parse(stmt=null,query="select * from app_user where username = $1",oids={1043})
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendBind
FINEST:  FE=> Bind(stmt=null,portal=null,$1=<'user1'>)
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendDescribePortal
FINEST:  FE=> Describe(portal=null)
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendExecute
FINEST:  FE=> Execute(portal=null,limit=0)
...
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl execute
FINEST:   simple execute, handler=org.postgresql.jdbc.PgStatement$StatementResultHandler@8519cb4, maxRows=0, fetchSize=0, flags=17
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendParse
FINEST:  FE=> Parse(stmt=null,query="select * from app_user where username = $1",oids={1043})
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendBind
FINEST:  FE=> Bind(stmt=null,portal=null,$1=<'user2'>)
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendDescribePortal
FINEST:  FE=> Describe(portal=null)
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendExecute
FINEST:  FE=> Execute(portal=null,limit=0)
...
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl execute
FINEST:   simple execute, handler=org.postgresql.jdbc.PgStatement$StatementResultHandler@35dab4eb, maxRows=0, fetchSize=0, flags=17
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendParse
FINEST:  FE=> Parse(stmt=null,query="select * from app_user where username = $1",oids={1043})
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendBind
FINEST:  FE=> Bind(stmt=null,portal=null,$1=<'user3'>)
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendDescribePortal
FINEST:  FE=> Describe(portal=null)
Feb 18, 2020 2:01:25 PM org.postgresql.core.v3.QueryExecutorImpl sendExecute
FINEST:  FE=> Execute(portal=null,limit=0)

, где есть 3 отдельных анализа и связывания операторов. Однако после 5 запросов они должны начать использоваться повторно.


Что касается режима запросов «простой» или «расширенный», то, похоже, журналы всегда выводят «простой запуск» независимо от различий. В этом простом режиме параметры не будут связаны в подготовленном операторе, и вместо этого весь запрос будет отправлен в виде текста. В этом примере, если для свойства preferQueryMode установлено значение simple, журналы показывают:

Feb 18, 2020 2:06:19 PM org.postgresql.core.v3.QueryExecutorImpl execute
FINEST:   simple execute, handler=org.postgresql.jdbc.PgStatement$StatementResultHandler@33065d67, maxRows=0, fetchSize=0, flags=1,041
Feb 18, 2020 2:06:19 PM org.postgresql.core.v3.QueryExecutorImpl sendSimpleQuery
FINEST:  FE=> SimpleQuery(query="select * from app_user where username = 'user1'")
...
Feb 18, 2020 2:06:20 PM org.postgresql.core.v3.QueryExecutorImpl execute
FINEST:   simple execute, handler=org.postgresql.jdbc.PgStatement$StatementResultHandler@28261e8e, maxRows=0, fetchSize=0, flags=1,041
Feb 18, 2020 2:06:20 PM org.postgresql.core.v3.QueryExecutorImpl sendSimpleQuery
FINEST:  FE=> SimpleQuery(query="select * from app_user where username = 'user2'")
...
Feb 18, 2020 2:06:20 PM org.postgresql.core.v3.QueryExecutorImpl execute
FINEST:   simple execute, handler=org.postgresql.jdbc.PgStatement$StatementResultHandler@d737b89, maxRows=0, fetchSize=0, flags=1,041
Feb 18, 2020 2:06:20 PM org.postgresql.core.v3.QueryExecutorImpl sendSimpleQuery
FINEST:  FE=> SimpleQuery(query="select * from app_user where username = 'user3'")

заметить разницу между этим и значением по умолчанию - нет параметров и 'user1', ' Значения user2 'и' user3 'отправляются в строке с каждым запросом.


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

...