Size: a a a

2020 May 07

KS

Kirill Shelopugin in pro.jvm
Vladimir Sitnikov
Пример про вообще другую тему. Пример про то, чтобы обрабатывать 100500 строк и не упасть в OutOfMemoryError.

Теоретически, хочется, чтобы данные обрабатывались небольшими пачками. Например, чтобы каждый rs.next забирал очередную пачку из 1000 строк из базы и её обрабатывал.
И Oracle DB даже так по умолчанию работает, правда там размер пачки 10 штук )

Но в PostgreSQL так не работает, и чтобы «курсор» жил какое-то время нужно, чтобы была жива транзакция.

Поэтому setAutoCommit(false) в том примере нужно именно для того, чтобы заработал функционал «выбирать по 50 строк».

Кхм. ровно про это же недавно писал: https://habr.com/ru/post/499794/#comment_21566550


Там, конечно, есть второй вопрос: а почему мы транзакцию не закрываем. Технически, да, надо бы. Но в том конкретном примере, транзакция readonly, и закрывать нечего. Вообще нечего. База создаёт транзакцию только тогда, когда речь доходит до модификации данных (ну или хотя бы блокировки через select for update). Поэтому, после select’а, который как бы readonly, никакой транзакции остаться не может.

Но, да, наверное, логично было бы добавить commit, чтобы не смущать.
> Поэтому, после select’а, который как бы readonly, никакой транзакции остаться не может.
Т.е. если у меня, допустим, нет DML-запросов, только select, то я могу вообще не делать commit никогда, просто брать connection из пула, проставлять ему autoCommit = false, делать свои дела и возвращать в пул, не беспокоясь о коммитах (при условии, что пул ничего за мной не чистит и никак не работает с транзакциями)?
источник

VS

Vladimir Sitnikov in pro.jvm
Vladimir Petrakovich
> Но в PostgreSQL так не работает, и чтобы «курсор» жил какое-то время нужно, чтобы была жива транзакция.
Так ведь она должна жить как раз до закрытия ResultSet, зачем отключать автокоммит?
Проблема в том, что

>All portals are implicitly closed at transaction end.

И этим драйвер не может управлять.

Ты кидаешь базе запрос, и она его выполняет и тут же «закрывает транзакцию». У тебя вообще нет шансов использовать «named portal» при остутствующей транзакции.
источник

AE

Alexandr Emelyanov in pro.jvm
Vladimir Sitnikov
Проблема в том, что

>All portals are implicitly closed at transaction end.

И этим драйвер не может управлять.

Ты кидаешь базе запрос, и она его выполняет и тут же «закрывает транзакцию». У тебя вообще нет шансов использовать «named portal» при остутствующей транзакции.
да ну, а как тогда у всех работает?
источник

VS

Vladimir Sitnikov in pro.jvm
Kirill Shelopugin
> Поэтому, после select’а, который как бы readonly, никакой транзакции остаться не может.
Т.е. если у меня, допустим, нет DML-запросов, только select, то я могу вообще не делать commit никогда, просто брать connection из пула, проставлять ему autoCommit = false, делать свои дела и возвращать в пул, не беспокоясь о коммитах (при условии, что пул ничего за мной не чистит и никак не работает с транзакциями)?
>я могу вообще не делать commit никогда,

commit делать не вредно. В pgjdbc это быстрая операция и по сети она не ходит, если транзакции по факту нет.
источник

VS

Vladimir Sitnikov in pro.jvm
Alexandr Emelyanov
да ну, а как тогда у всех работает?
У всех это у кого?
источник

D

Dima in pro.jvm
Vladimir Sitnikov
>я могу вообще не делать commit никогда,

commit делать не вредно. В pgjdbc это быстрая операция и по сети она не ходит, если транзакции по факту нет.
то есть разницы нет?
источник

VP

Vladimir Petrakovich in pro.jvm
Vladimir Sitnikov
Проблема в том, что

>All portals are implicitly closed at transaction end.

И этим драйвер не может управлять.

Ты кидаешь базе запрос, и она его выполняет и тут же «закрывает транзакцию». У тебя вообще нет шансов использовать «named portal» при остутствующей транзакции.
То есть если я хочу, чтобы setFetchSize() работал, мне не стоит рассчитывать на поведение, описанное в JDBC?
источник

AE

Alexandr Emelyanov in pro.jvm
Vladimir Sitnikov
У всех это у кого?
как работает тот же батчинг в spring data? каким образом там привязывается Stream к курсору? оно бы не работало, если бааза сама закрывает
источник

VS

Vladimir Sitnikov in pro.jvm
Vladimir Petrakovich
То есть если я хочу, чтобы setFetchSize() работал, мне не стоит рассчитывать на поведение, описанное в JDBC?
По факту, в PostgreSQL сделать fetch size можно только в рамках транзакции. Это ограничение базы. Обойти его драйвер не может. Ну и периодически мы (как пользователи и по совместительству maintainer’ы) ходим в backend со словми «сделайте, плз, чтобы работало fetch size вне транзакций», но они такие: «ой, вам зачем? не будем»

Самый явный пример из недавнего — это когда «ошибка во время commit’а» возвращалось из базы как «commit successfully rolledback»
Т.е. де-факто, клиент думал, что ошибки нет, а транзакция откачена. Половина драйверов умеет это распознавать, половина нет. Но backend пока не удалось убедить в том, что «если операция commit не смогла зафиксировать, то это должна быть ошибка, а не просто запись в логе»
источник

VS

Vladimir Sitnikov in pro.jvm
Alexandr Emelyanov
как работает тот же батчинг в spring data? каким образом там привязывается Stream к курсору? оно бы не работало, если бааза сама закрывает
Полагаю, он работает через preparedstatement.addbatch. Там нет проблем с курсорами, т.к. мы грузим данные в базу, а не читаем из неё.

Или речь про какой из batching'ов?
источник

AE

Alexandr Emelyanov in pro.jvm
Vladimir Sitnikov
Полагаю, он работает через preparedstatement.addbatch. Там нет проблем с курсорами, т.к. мы грузим данные в базу, а не читаем из неё.

Или речь про какой из batching'ов?
эм. я про чтение, а не про запись
источник

VS

Vladimir Sitnikov in pro.jvm
Alexandr Emelyanov
эм. я про чтение, а не про запись
Не пользовался, не знаю. Может, и не работает он. Как обычно: «реально рабочий fetchsize только при autocommit=false»
источник

AE

Alexandr Emelyanov in pro.jvm
а, ну да. мы там все явно в транзакцию заворачиваем
источник

VP

Vladimir Petrakovich in pro.jvm
Vladimir Sitnikov
По факту, в PostgreSQL сделать fetch size можно только в рамках транзакции. Это ограничение базы. Обойти его драйвер не может. Ну и периодически мы (как пользователи и по совместительству maintainer’ы) ходим в backend со словми «сделайте, плз, чтобы работало fetch size вне транзакций», но они такие: «ой, вам зачем? не будем»

Самый явный пример из недавнего — это когда «ошибка во время commit’а» возвращалось из базы как «commit successfully rolledback»
Т.е. де-факто, клиент думал, что ошибки нет, а транзакция откачена. Половина драйверов умеет это распознавать, половина нет. Но backend пока не удалось убедить в том, что «если операция commit не смогла зафиксировать, то это должна быть ошибка, а не просто запись в логе»
Понятно, спасибо. Ну setFetchSize() всё-таки преподносится как "hint", а значит надо курить доки драйвера, чтобы понять, как он работает.
Но остаётся лёгкое ощущение того, что опять абстракция протекла.
источник

VS

Vladimir Sitnikov in pro.jvm
Vladimir Petrakovich
Понятно, спасибо. Ну setFetchSize() всё-таки преподносится как "hint", а значит надо курить доки драйвера, чтобы понять, как он работает.
Но остаётся лёгкое ощущение того, что опять абстракция протекла.
Абстракция потекла даже в том, что fetchSize это «количество строк»
А по-хорошему, это должно быть «количество байт», ведь, именно от чрезмерного количества байт случается OutOfMemory, а от нехватки «количества байт» случаются тормоза на чрезмерном количестве сетевых операций.

Поэтому будет забавно, когда очередная версия драйвера плюнет на это всё, и будет грузить данные согласно памяти, а не количеству строк. Тут, конечно, снова проблема, что база не умеет в «fetch size по байтам»

В этом плане, MSSQL JDBC, вроде, никогда не использовал fechsize, а у них реализован адаптивный fetch.
источник

L

Loljeene in pro.jvm
Vladimir Sitnikov
По факту, в PostgreSQL сделать fetch size можно только в рамках транзакции. Это ограничение базы. Обойти его драйвер не может. Ну и периодически мы (как пользователи и по совместительству maintainer’ы) ходим в backend со словми «сделайте, плз, чтобы работало fetch size вне транзакций», но они такие: «ой, вам зачем? не будем»

Самый явный пример из недавнего — это когда «ошибка во время commit’а» возвращалось из базы как «commit successfully rolledback»
Т.е. де-факто, клиент думал, что ошибки нет, а транзакция откачена. Половина драйверов умеет это распознавать, половина нет. Но backend пока не удалось убедить в том, что «если операция commit не смогла зафиксировать, то это должна быть ошибка, а не просто запись в логе»
Какие страхи. Не припомню чтобы у меня с оракловыми драйверами такое было...
источник

KS

Kirill Shelopugin in pro.jvm
Vladimir Sitnikov
>я могу вообще не делать commit никогда,

commit делать не вредно. В pgjdbc это быстрая операция и по сети она не ходит, если транзакции по факту нет.
Вопрос вообще изначально возник из-за того, что меня ораклисты начали ногами пинать за то, что мы после всех операций, включая select, делаем commit, говорят, плохо. На вопрос а что там в pg скидывали выдержку из доки pg, которую я выше цитировал, говорили, что, дескать, В PostgreSQL даже select 1 открывает транзакцию. Но видимо это были неправильные ораклисты, раз ничего не открывает и можно смело без коммита делать select
источник

VS

Vladimir Sitnikov in pro.jvm
Loljeene
Какие страхи. Не припомню чтобы у меня с оракловыми драйверами такое было...
С оракловым драйвером тоже могу рассказать:
1) fetch size == 10 по умолчанию. Это крайне мало, и, если запрос возвращает более 100 строк, то это заметно тормозит выборку
2) Драйвера старых версий (10g,11g) выделяли место под fetchSize сразу. Иными словами, если запрос возвращает 1000 колонок, и указать fetchSize=1000, то база запросто выделит 100 мегабайт на один resultset, даже, если по факту вернётся одна строка
источник

L

Loljeene in pro.jvm
Vladimir Sitnikov
С оракловым драйвером тоже могу рассказать:
1) fetch size == 10 по умолчанию. Это крайне мало, и, если запрос возвращает более 100 строк, то это заметно тормозит выборку
2) Драйвера старых версий (10g,11g) выделяли место под fetchSize сразу. Иными словами, если запрос возвращает 1000 колонок, и указать fetchSize=1000, то база запросто выделит 100 мегабайт на один resultset, даже, если по факту вернётся одна строка
Fetch всегда принудительно ставил.
2) не застал, хотя работал на 10 оракле, но уже с новыми драйверами
источник

VS

Vladimir Sitnikov in pro.jvm
Loljeene
Fetch всегда принудительно ставил.
2) не застал, хотя работал на 10 оракле, но уже с новыми драйверами
Т.е. даже setFetchSize(1) для запросов, которые возвращают 1 строку? Правда?
источник