Ошибка Java PostgreSQL при большом запросе: ошибка ввода-вывода произошла при отправке на серверную часть

В Java, используя java.sql.PreparedStatement, я пытаюсь отправить довольно большой запрос, содержащий постоянное выражение (VALUES (?), (?), (?)...) для эффективного соединения.

Есть около 250K значений, поэтому я также устанавливаю параметры 250K.

В Java я получаю

org.postgresql.util.PSQLException: An I/O error occurred while sending to the backend.

В моем журнале PostgreSQL на сервере есть одна строка об этой ошибке:

incomplete message from client

Есть идеи о некоторых настройках, которые я мог бы изменить где угодно, чтобы мой большой запрос работал?


person Tregoreg    schedule 18.12.2016    source источник
comment
Вы пытаетесь выполнить PreparedStatement с 250000 параметрами? Вот твоя проблема. Попробуйте создать темп. table, используйте пакетные вставки в эту таблицу, а затем присоединитесь к temp. стол.   -  person Andreas    schedule 18.12.2016
comment
@Andreas Я понимаю вашу точку зрения и спасибо, мне, вероятно, придется сделать что-то в этом роде. Я знаю, что 250 КБ - это много, но все же, пока у компьютеров нет эмоций, это должен быть какой-то предел, которого я достиг. У меня вопрос об этом пределе и о том, могу ли я его увеличить. Я читал, что ограничение размера запроса psql составляет 1 ГБ, но мои параметры - короткие идентификаторы, он должен быть где-то еще ...   -  person Tregoreg    schedule 18.12.2016
comment
Предел может зависеть от драйвера JDBC; для некоторых драйверов установлено ограничение 2 КБ. Я согласен с Андреасом; используйте простую вставку с addBatch() или какой-либо другой вариант пакетной вставки, поддерживаемый драйвером.   -  person Mick Mnemonic    schedule 18.12.2016
comment
@MickMnemonic Это не столько драйвер, сколько ограничения сервера. Водитель может просто предварительно установить ограничения, иногда немного ниже. Например. MS SQL 2016 имеет макс. 2100 параметров на хранимую процедуру (см. msdn.microsoft.com/en-us/library /ms143432.aspx), и я считаю, что драйвер JDBC использует временные хранимые процедуры для PreparedStatements.   -  person Andreas    schedule 18.12.2016


Ответы (1)


Максимальное количество параметров, которые драйвер JDBC может передать в бэкэнд, составляет 32767. Это ограничено проводным протоколом v3, который передает счетчик параметров в 16-битном int (см. Документ для определение сообщения Bind).

Вы можете обойти это, передав значения в массив и отключив их на сервере:

// Normally this would be one too many parameters
Integer[] ids = new Integer[Short.MAX_VALUE  + 1];
Arrays.setAll(ids, i -> i);
// Pass them in an array as a single parameter and unnest it 
PreparedStatement stmt = con.prepareStatement(
    "WITH ids (id) AS (SELECT unnest (?)) " +
    "SELECT f.* FROM foo f JOIN ids i ON i.id = f.id"
);
stmt.setArray(1, con.createArrayOf("INT", ids));
person teppic    schedule 18.12.2016