metaclass: (Default)
metaclass ([personal profile] metaclass) wrote2010-07-02 07:04 am

Как же удолбут.

Тема "сессий" и "транзакций" при подключениях к различным базам данных судя по всему является очередным потаенным вуду для разработчиков. Причем даже для разработчиков самих БД и драйверов доступа к ним.

Иначе я не могу объяснить тот факт, что в некоторых серверах невозможно открыть одновременно две транзакции в одном соединении. Или то, что из трех ADO.NET провайдеров (Firebird, MSSQL, Postgresql) одновременно открыть два SQL запроса в одном соединении и читать одновременно из них - можно только в Firebird, два остальных ругаются типа "уже открыт DataReader".

Ну вот вопрос как в ADO.NET ленивым образом (не загружая в память) прочитать список сущностей из БД, и для каждой сущности прочитать вложенные для нее?
Ну всегда обычное решение было - цикл по одному DataReader, из него берем некое поле, подсовываем его значение в параметр второй команде, выполняем ExecuteReader и пытаемся читать во вложенном цикле. В Firebird работает, в других хрен.

PS: В Npgsql есть параметр PreloadReader=true, который позволяет обойти это ограничение и который не рекомендуется использовать, т.к. он грузит весь DataReader в память и смысл ленивой итерации теряется. И написано, что это ограничение - by design, упомянуто в доке на ADO.NET.

По моему, архитекторов ADO.NET надо убить, это же идиотизм клинический.
(deleted comment)

[identity profile] metaclass.livejournal.com 2010-07-02 07:43 am (UTC)(link)
Для MSSQL это работает, известное дело.
Интересно, почему оно не является поведением по умолчанию.
(deleted comment)

[identity profile] denisioru.livejournal.com 2010-07-02 04:28 pm (UTC)(link)
Да, и особенно весело с MARS, когда используется Application Roles

[identity profile] norguhtar.livejournal.com 2010-07-02 07:55 am (UTC)(link)
Честно говоря у меня есть ощущение, что вы хотите странного. Я вот ситуацию того что больше одной транзакции в одном соединении открыть нельзя не считаю вполне нормальным.

[identity profile] metaclass.livejournal.com 2010-07-02 08:01 am (UTC)(link)
Ну с транзакциями хрен с ним - все равно уже давно никто не использует длительные транзакции в БД, все занимаются извращениями в стиле "загрузили в одной короткой, час юзер редактировал, затем сохранили в другой короткой", эффективно убивая вообще весь смысл транзакций.

Но вот невозможность читать из двух SQL запросов одновременно - это какой-то бред тяжкий, имхо.

[identity profile] norguhtar.livejournal.com 2010-07-02 08:11 am (UTC)(link)
И как вы себе представляете одновременное чтение из двух SQL запросов в одном подключении? С моей точки зрения это приведет к неоправданному усложнению кода как со стороны сервера так и со стороны клиента.

[identity profile] metaclass.livejournal.com 2010-07-02 08:19 am (UTC)(link)
А в чем сложность то? Всю жизнь в дельфи+firebird так делали. Препарим два запроса, один выполняем, читаем в цикле, внутри цикла выполняем другой, читаем во вложенном цикле.
В API это выглядит как создание запроса, получение его хендла и затем использование этого хендла первым параметром во всех функциях(prepare, fetch, close).

[identity profile] norguhtar.livejournal.com 2010-07-02 08:39 am (UTC)(link)
В реализации. В случае соединения разделение транзакций и получения и отправки данных ложится на tcp/ip. В случае же одного соединения, надо будет городить это разделение внутри соединения, что приведет к усложеннию кода как со стороны клиента, так и со стороны сервера.

[identity profile] metaclass.livejournal.com 2010-07-02 08:22 am (UTC)(link)
Встречный вопрос: как без этого функционала сделать ленивую обработку двух таблиц - основной и подчиненной. Какое-нибудь элементарное задание вроде "обработать 10 млн проводок с детализацией"

[identity profile] norguhtar.livejournal.com 2010-07-02 08:41 am (UTC)(link)
use connection pool luke!
Я вот вообще этим не запариваюсь. У меня JPA это все делает.

[identity profile] volodymir-k.livejournal.com 2010-07-02 09:03 am (UTC)(link)
Это и называется быдлокодинг. Если программер работает на БД с 20 записями и верит, что 10 млн строк это то же самое.

Попробуйте продумать алгоритм расчёта зарплат для 20 тыс.рабочих согласно белорусскому законодательству, желательно в пределах 3 часов. Могу примерно припомнить исходные таблицы:
- журналы рабочего времени по видам работ
- тарифы по видам работ
- таблица совместителей
- накопленные налоги по сотрудникам за последние 2 года
- справочник МРОТ по месяцам
- справочник налогов по месяцам
- справочник размеры пособий по уходу за ребенком
- выплаченные пособия за ребенком
- больничные листы
... где-то ещё штук 20 таблиц, забыл уже.

[identity profile] norguhtar.livejournal.com 2010-07-02 09:16 am (UTC)(link)

Это и называется быдлокодинг. Если программер работает на БД с 20 записями и верит, что 10 млн строк это то же самое.

Это называется вы не знаете чем, я занимаюсь :)


Попробуйте продумать алгоритм расчёта зарплат для 20 тыс.рабочих согласно белорусскому законодательству, желательно в пределах 3 часов.

Я вам могу встречную задачу по тарификации услуг доступа к сети предложить. Какое это имеет отношение к JPA и connection pool?

[identity profile] volodymir-k.livejournal.com 2010-07-02 01:38 pm (UTC)(link)
> Какое это имеет отношение к JPA и connection pool?

Вы всё еще не догадались???
Я намекаю, что программер должен не высасывать сразу все данные в память, а читать кусками; для этого и нужно понимание, какие соединения делают какие транзакции, вместо тупого использования connection pool.

Я вообще не понимаю, как можно в системах batch обработки использовать пулы. Поток вычисления-то один. Разве что тупо брать соединения, когда левая пятка в коде захочет?

[identity profile] norguhtar.livejournal.com 2010-07-02 04:46 pm (UTC)(link)

Я намекаю, что программер должен не высасывать сразу все данные в память, а читать кусками; для этого и нужно понимание, какие соединения делают какие транзакции, вместо тупого использования connection pool.

Вы шо считаете меня идиотом да? Вообще в JPA для ограничения идиотов по умолчанию фетчится только первая 1000 строк. Да и я не фетчу 1000 строк при таких обновлениях.



Я вообще не понимаю, как можно в системах batch обработки использовать пулы. Поток вычисления-то один. Разве что тупо брать соединения, когда левая пятка в коде захочет?

В случае batch достаточно и одного подключения. Как бе у меня подразумевается обычно:

Одно подключение для длинных транзакций
N-подключений для множества коротких одновременных транзакций

[identity profile] vaddimka.livejournal.com 2010-07-03 12:49 am (UTC)(link)
мне кажется, вы не совсем понимаете всю концепцию connection pool'ов.
пул никак не связан со способом фетча данных.
можно читать результаты тяжелого запроса в одном подключении, дергать множество мелких - в другом. то же самое с несколькими транзакциями
Ребе, вероятно, смутило что ранее он использовал некое API, которое менеджило подключения к БД за него; с другой стороны все решается достаточно примитивным врэппером.

[identity profile] metaclass.livejournal.com 2010-07-03 06:10 am (UTC)(link)
Оно ничего не менеджило, это нативная фича сервера и клиентской либы. Соединение там в норме одно на весь сеанс работы.

[identity profile] vaddimka.livejournal.com 2010-07-03 12:27 pm (UTC)(link)
А, круто. Интересно как там interleaving реализован.

[identity profile] metaclass.livejournal.com 2010-07-02 09:08 am (UTC)(link)
Интересно, как в JPA этот вопрос обходят. Подозреваю, что таки исключительно непересекающимися фетчами результатов.

[identity profile] norguhtar.livejournal.com 2010-07-02 09:18 am (UTC)(link)
Где так и есть. Только вот ленивые запросы там с осторожностью надо использовать иначе можно на больших объемах словить пачку запросов в базу.

[identity profile] norguhtar.livejournal.com 2010-07-02 10:13 am (UTC)(link)
Кстати да. Я тут подумал. А что мешает использовать join запрос?

[identity profile] metaclass.livejournal.com 2010-07-02 10:20 am (UTC)(link)
И что это будет? Денормализованный датасет типа "на каждую запись в детализации (коих over 9000) повторяем запись-владелец"?

[identity profile] norguhtar.livejournal.com 2010-07-02 10:27 am (UTC)(link)
Да. А дальше обрабатываем. В чем собственно проблема? В том что с этим не удобно работать?

[identity profile] metaclass.livejournal.com 2010-07-02 10:29 am (UTC)(link)
В том что это маразм, очевиднейший. Сначала делаем декартово произведение, денормализуем, сосем по не самому быстрому каналу на клиента увеличенный по сравнению с нужным результат, а потом его нормализуем обратно, закатывая солнце вручную.
Проще уж на сервере все обработать тогда, ничего на клиента/миддлварь не вытаскивая.

[identity profile] norguhtar.livejournal.com 2010-07-02 11:47 am (UTC)(link)
Если у вас обрабатываются все данные это самый быстрый способ их получить и обработать. Если выборочно относительно того какие данные в первой таблице, то можно делать отдельный ленивый select. Опять же никто offset и limit не отменял.

[identity profile] vp.livejournal.com 2010-07-02 10:37 am (UTC)(link)
Не, это явный перебор.
Приемлемо ТОЛЬКО в случае, когда ну вообще никаких средств не осталось..

[identity profile] norguhtar.livejournal.com 2010-07-02 11:53 am (UTC)(link)
Если вы обрабатываете данные в обоих таблицах это самый правильный и быстрый вариант для получения данных. Если вы обрабатываете выборочно данные во второй подчиненной таблице, то можно использовать запросы. Иначе у вас будет пиздец-пиздец по производительности. Как раз из-за перманентного дерганья второй таблицы.

[identity profile] metaclass.livejournal.com 2010-07-02 11:58 am (UTC)(link)
Пиздец-пиздец будет только в кривых серверах, которые не умеют запросы препарить и держать отпрепаренными. Таблица по всякому будет в кэше сервера, если запрос не закрывать каждый раз - оно летает, проверено.
Другое дело что, судя по всему, ADO.NET это корректно делать не умеет, т.к. затачивалась под кривые сервера, коих большинство.

[identity profile] norguhtar.livejournal.com 2010-07-02 12:29 pm (UTC)(link)
Вообще время работы первого запроса будет ниже чем суммарное время второго. Вообщем как делать сильно зависит от того что делать. Ну и к слову JPA умеет из join который я привел разворачивать два объекта, так что с точки зрения удобства тут все в порядке.

[identity profile] vp.livejournal.com 2010-07-02 03:32 pm (UTC)(link)
ADO ж вообще задумывался как обобщенный интерфейс к БД. Вот скорее всего они и привели его к наименьшему общему знаменателю, выкинув такого рода фичи серверов, которые не обобщаются.

[identity profile] molnij.livejournal.com 2010-07-02 11:25 am (UTC)(link)
Если такое "подключение" умеет единственно - выполнять ровно один запрос, то лично у меня возникает вопрос в его смысле. Можно смело выкинуть подключение оставив запрос\команду\etc упростив многоэтажный пирог абстракций доступа к данным и не потерять ничего.

[identity profile] norguhtar.livejournal.com 2010-07-02 04:36 pm (UTC)(link)
Последовательно оно умеет сколько угодно. Параллельно надо вписывать уже фабрику подключений.

[identity profile] volodymir-k.livejournal.com 2010-07-02 08:57 am (UTC)(link)
В далёком 1998 году, в обсуждении компонент Дельфи, один мегаэксперт Толя Тенцер высказал своё мнение, что у MSSQL Server банально проблема с потоковым протоколом. Не предусмотрена фича по дизайну, и не реализована в протоколе. Кстати дизайн Микрософт тоже унаследовал от Сайбейза. И в принципе, SQL как придуманный в 1980-х язык не предусматривал современных фич типа авторизации, постраничной выгрузки и т.п., о многопотомности вообще никто не думал. Нужны 2 транзакции - берите два соединения.

В принципе, Вы можете сами посмотреть доки по jtds проекту, там описываются протоколы, скорее всего фича корректно не получится.

[identity profile] plumqqz.livejournal.com 2010-07-02 11:15 am (UTC)(link)
Иначе я не могу объяснить тот факт, что в некоторых серверах невозможно открыть одновременно две транзакции в одном соединении.

Не вполне понимаю, что мешает открыть два соединения. Или сорок четыре, если требуется.

[identity profile] metaclass.livejournal.com 2010-07-02 11:19 am (UTC)(link)
Не, с транзакциями это не так сильно мешает, хотя и маразм.
А вот два запроса в одной транзакции-соедиении - это что-то невменяемое.

[identity profile] plumqqz.livejournal.com 2010-07-02 01:04 pm (UTC)(link)
Ну, открыть два соединения и пустить там по запросу - в чем проблемы?

[identity profile] metaclass.livejournal.com 2010-07-02 02:41 pm (UTC)(link)
А транзакцию куды? Я ж хочу чтобы запросы были в одной транзакции, чтобы консистентное состояние БД видеть.

[identity profile] molnij.livejournal.com 2010-07-02 11:28 am (UTC)(link)
А какая связка умеет делать две транзакции внутри одного соединения?
Просто, насколько помню встречавшиеся мне варианты транзакции везде не имеют собственных хэндлов(следствие стандата SQL?) и тогда неясно, как указывть транзакцию для очередного выполняемого запроса.

[identity profile] metaclass.livejournal.com 2010-07-02 11:36 am (UTC)(link)
Firebird умеет. Судя по всему что здесь пишут, это единственный сервер, который это умеет.

[identity profile] molnij.livejournal.com 2010-07-02 11:58 am (UTC)(link)
т.е. он отдает какой-то идентификатор транзакции, которую потом нужно указывать при выполнении запросов? Если да - то как-то очень уж похоже на функционал сессии, если нет - неясно как потом разруливается доступ к незафиксированным данным

[identity profile] metaclass.livejournal.com 2010-07-02 12:00 pm (UTC)(link)
Да, хендл транзакции отдает апишная функция что-то вроде start_trans.
Сессия это дорогой объект - новый коннект к базе данных тяжел. А транзакция поверх уже существующего коннекта дешевле.

[identity profile] metaclass.livejournal.com 2010-07-02 11:36 am (UTC)(link)
В стандарте SQL про API ничего не сказано вроде.

[identity profile] volodymir-k.livejournal.com 2010-07-02 01:41 pm (UTC)(link)
ODBC как раз такое API, вроде бы часть стандарта.

[identity profile] zamotivator.livejournal.com 2010-07-02 02:51 pm (UTC)(link)
Ага, Microsoft слабало какую-то хуйню, а потом её застандартизировало.
Хуйнёй и вуду оно от этого быть не перестало.

[identity profile] volodymir-k.livejournal.com 2010-07-07 09:26 pm (UTC)(link)
В моей реальности последовательность была немножко иной:
ODBC uses as its basis the various Call Level Interface (CLI) specifications from the SQL Access Group, X/Open (now part of The Open Group), and the ISO/IEC.
1.0: released in September 1992[4]

The work with the Call Level Interface began in a subcommittee of the US-based SQL Access Group.

The SQL Access Group (SAG) was a group of software companies that was formed in 1989 to define and promote standards for database portability and interoperability. Initial members were Oracle Corporation, Informix, Ingres, DEC, Tandem, Sun and HP.

Так что слабал не микрософт.

[identity profile] belpartizan.blogspot.com (from livejournal.com) 2010-07-07 07:01 am (UTC)(link)
Про .Net ничего не скажу, но в Java:

1) Несколько параллельных транзакций в одном соединении не поддерживается, но есть SavePoint (которые поддерживаются некоторыми базами и позволяют делать, в частности, вложенные транзакции)

2) Параллельные ResultSet поддерживаются на одном коннекте (я не припомню проблем с параллельным разбором нескольких одновременно)