Как лучше организовать паралельное исполнение запросов
От: AlexNek  
Дата: 10.11.14 23:06
Оценка:
Пока раздумываем над следующей ситуацией:
есть приложение которое исполняет некоторые запросы паралельно (Для примера — обновление материального въюва и чтение/запись других данных).
Сейчас все запросы к базе оформляются в виде плагина, так так требуется поддержка и MS SQl и Oracle.
Доступ к выбранному плагину осуществляется через синглтон и набор интерфейсов.
Делать параметр синхронное/асинхронное выполнение для плагинов БД пока совсем не хочется, а нужны оба типа выполения. Пока есть идея, чтобы на стороне плагина все запросы выполнялись с ожиданием исполнения, как обычно. А в ситуациях когда требуется, просто исполнять запросы из нескольких потоков. В текущей версии сделано так
OracleConnection conn = new OracleConnection(oradb);
conn.Open();

OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.CommandText = "запрос"; 
OracleDataReader dr = cmd.ExecuteReader();


И для каждого треда держится свой OracleConnection. При этом сказали, что Connection Pool работает весьма фигово, особенно если пароль изменяется. Так что для соединений был заведен еще отдельный треад который пытается держать соединения открытыми. Данные поступают от оборудования почти ежесекундно, и поэтому постоянно открывать и закрывать соединение получается накладно.
Но что то мне подобный принцип не очень нравится, для "универсального" решения не тянет вроде.

Про общие принципы есть ссылки
http://msdn.microsoft.com/en-us/library/gg415714.aspx
https://docs.oracle.com/cd/B28359_01/server.111/b28310/manproc006.htm#ADMIN11187
а вот конкретных рекомендаций не густо.

Чем можете из опыта поделится? Думаю, что отдельно для Оракла и отдельно для Микрософта, а после общее найдется.
Re: Как лучше организовать паралельное исполнение запросов
От: Olaf Россия  
Дата: 11.11.14 05:43
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN>...


AN>И для каждого треда держится свой OracleConnection. При этом сказали, что Connection Pool работает весьма фигово, особенно если пароль изменяется. Так что для соединений был заведен еще отдельный треад который пытается держать соединения открытыми. Данные поступают от оборудования почти ежесекундно, и поэтому постоянно открывать и закрывать соединение получается накладно.

AN>Но что то мне подобный принцип не очень нравится, для "универсального" решения не тянет вроде.
У вас часто меняется пароль пользователя или все соединения работают под разными пользователями? На самом деле он работает не «фигово», просто строка соединения является ключом по которому организуется пул, и если у вас при каждом соединении меняется один из параметров строки, то вы не получаете от пула никакого эффекта, т.к. соединение создается каждый раз новое, а не извлекается из пула по ключу.
Универсальное решение здесь напрашивается одно – использовать пул соединений, который работает как для Oracle, так и для Sql Server. Однако остается открытый вопрос – время жизни соединения в пуле. Я точно не помню чему равно это значение, но Microsoft витиевато повествует о длительном времени нахождения соединения в пуле, которое в любом случае больше 1 секунды, о которой вы говорили.

AN>Про общие принципы есть ссылки

AN>http://msdn.microsoft.com/en-us/library/gg415714.aspx
AN>...

В статье, которую вы привели, рассказывается о параллелизме на самом сервере, т.е. когда оптимизатор принимает решение распараллелить выполнение одного запроса. А вас, как я понял, интересует все-таки параллельное обращение к СУБД со стороны клиента, т.е. обновление материального въюва и чтение/запись других данных.
Что касается реализации, то детали не расскажу, но коллеги по цеху используют библиотеку TPL в связке с EF и SQL Server.
Re[2]: Как лучше организовать паралельное исполнение запросов
От: AlexNek  
Дата: 11.11.14 07:02
Оценка:
Здравствуйте, Olaf, Вы писали:

O>Здравствуйте, AlexNek, Вы писали:


AN>>...


AN>>И для каждого треда держится свой OracleConnection. При этом сказали, что Connection Pool работает весьма фигово, особенно если пароль изменяется. Так что для соединений был заведен еще отдельный треад который пытается держать соединения открытыми. Данные поступают от оборудования почти ежесекундно, и поэтому постоянно открывать и закрывать соединение получается накладно.

AN>>Но что то мне подобный принцип не очень нравится, для "универсального" решения не тянет вроде.
O>У вас часто меняется пароль пользователя или все соединения работают под разными пользователями?
не часто, но как я понял человечека, были проблемы просто с заменой пароля, сам я еще не пробовал.

O>открытый вопрос – время жизни соединения в пуле. Я точно не помню чему равно это значение, но Microsoft витиевато повествует о длительном времени нахождения соединения в пуле, которое в любом случае больше 1 секунды, о которой вы говорили.

А сколько будет время открытия/закрытия соединения? Если даже 100 мс, то это уже много.

AN>>Про общие принципы есть ссылки

AN>>http://msdn.microsoft.com/en-us/library/gg415714.aspx
AN>>...

O>В статье, которую вы привели, рассказывается о параллелизме на самом сервере, т.е. когда оптимизатор принимает решение распараллелить выполнение одного запроса. А вас, как я понял, интересует все-таки параллельное обращение к СУБД со стороны клиента, т.е. обновление материального въюва и чтение/запись других данных.

Со стороны клиента пока не нашел ничего толкового.... может не то искал.
Хотя бы, нужно ли обязательно другое соединение для паралельного запроса? Подозреваю что да, но хотелось бы четко знать.

O>Что касается реализации, то детали не расскажу, но коллеги по цеху используют библиотеку TPL в связке с EF и SQL Server.

не удалось подружить последнюю EF с ораклом, старая версия работает, а вот с новой не получилось.
Re: Как лучше организовать паралельное исполнение запросов
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.11.14 07:33
Оценка:
Здравствуйте, AlexNek, Вы писали:
AN>И для каждого треда держится свой OracleConnection.
Зачем "держится"?
AN>При этом сказали, что Connection Pool работает весьма фигово, особенно если пароль изменяется.
Бред какой-то. Судя по всему, кто-то не разобрался с пулом, однажды наступил на грабли, и теперь всех запугивает.
AN>Так что для соединений был заведен еще отдельный треад который пытается держать соединения открытыми.
Не надо этого делать.
AN>Данные поступают от оборудования почти ежесекундно, и поэтому постоянно открывать и закрывать соединение получается накладно.
Правильно. Для этого и придуман пул.
AN>Но что то мне подобный принцип не очень нравится, для "универсального" решения не тянет вроде.
AN>Чем можете из опыта поделится? Думаю, что отдельно для Оракла и отдельно для Микрософта, а после общее найдется.
Могу поделиться тем, что совместное использование одного соединения для нескольких операций — редкая штука. У Microsoft это называется MARS — multiple active record-sets — и я совершенно не уверен, что оно из коробки ещё и потокобезопасно.
Поэтому нормальный способ — это прекратить страдать фигнёй, и в коде рабочих потоков делать вот так:
using(var conn = new OracleConnection(oradb))
{
  conn.Open();
  using (var cmd = new OracleCommand())
  {
     cmd.Connection = conn;
     cmd.CommandText = "запрос";  
     using (var dr = cmd.ExecuteReader())
     {
       ... быстро делаем всю работу!
     }
  }
}

Если хотите выносить детали конкретной СУБД в плагин, то плагин либо должен полностью содержать вот такие блоки "получил-использовал-отпустил", либо выставлять IDisposable так, чтобы основной код мог быть написан с using().
Таким образом, вам не придётся мучительно думать о возможном наличии второго потока, который сейчас использует это же соединение, или о том, как правильно распараллелить работу, или об удержании соединений открытыми, или о стоимости переоткрытия соединения заново.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Как лучше организовать паралельное исполнение запросов
От: Vaako Украина  
Дата: 11.11.14 10:09
Оценка:
Здравствуйте, Sinclair, Вы писали:

AN>>Чем можете из опыта поделится? Думаю, что отдельно для Оракла и отдельно для Микрософта, а после общее найдется.

S>Могу поделиться тем, что совместное использование одного соединения для нескольких операций — редкая штука. У Microsoft это называется MARS — multiple active record-sets — и я совершенно не уверен, что оно из коробки ещё и потокобезопасно.
S>Поэтому нормальный способ — это прекратить страдать фигнёй, и в коде рабочих потоков делать вот так:
S>
S>using(var conn = new OracleConnection(oradb))
S>{
S>  conn.Open();
S>  using (var cmd = new OracleCommand())
S>  {
S>     cmd.Connection = conn;
S>     cmd.CommandText = "запрос";  
S>     using (var dr = cmd.ExecuteReader())
S>     {
S>       ... быстро делаем всю работу!
S>     }
S>  }
S>}
S>

S>Если хотите выносить детали конкретной СУБД в плагин, то плагин либо должен полностью содержать вот такие блоки "получил-использовал-отпустил", либо выставлять IDisposable так, чтобы основной код мог быть написан с using().
S>Таким образом, вам не придётся мучительно думать о возможном наличии второго потока, который сейчас использует это же соединение, или о том, как правильно распараллелить работу, или об удержании соединений открытыми, или о стоимости переоткрытия соединения заново.

Одобряю все что тут написано.
Re[2]: Как лучше организовать паралельное исполнение запросов
От: AlexNek  
Дата: 11.11.14 17:44
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, AlexNek, Вы писали:

AN>>И для каждого треда держится свой OracleConnection.
S>Зачем "держится"?
Чтобы избежать накладных расходов по открытию и закрытию.
AN>>При этом сказали, что Connection Pool работает весьма фигово, особенно если пароль изменяется.
S>Бред какой-то. Судя по всему, кто-то не разобрался с пулом, однажды наступил на грабли, и теперь всех запугивает.
Я пока не разбирался в деталях попробую вытянуть тест кейс.
AN>>Так что для соединений был заведен еще отдельный треад который пытается держать соединения открытыми.
S>Не надо этого делать.
AN>>Данные поступают от оборудования почти ежесекундно, и поэтому постоянно открывать и закрывать соединение получается накладно.
S>Правильно. Для этого и придуман пул.
Не тестил пока сколько времени занимает, но любая добавка весьма нежелательна.
AN>>Но что то мне подобный принцип не очень нравится, для "универсального" решения не тянет вроде.
AN>>Чем можете из опыта поделится? Думаю, что отдельно для Оракла и отдельно для Микрософта, а после общее найдется.
S>Могу поделиться тем, что совместное использование одного соединения для нескольких операций — редкая штука. У Microsoft это называется MARS — multiple active record-sets — и я совершенно не уверен, что оно из коробки ещё и потокобезопасно.
S>Поэтому нормальный способ — это прекратить страдать фигнёй, и в коде рабочих потоков делать вот так:
S>
S>using(var conn = new OracleConnection(oradb))
S>{
S>  conn.Open();
S>  using (var cmd = new OracleCommand())
S>  {
S>     cmd.Connection = conn;
S>     cmd.CommandText = "запрос";  
S>     using (var dr = cmd.ExecuteReader())
S>     {
S>       ... быстро делаем всю работу!
S>     }
S>  }
S>}
S>

Здесь есть один ньюанс, который в принципе невозможен — "быстро делаем всю работу". Хотя бы обновление мат. въюва занимает от получаса до часа. А в SQL будет может и поболее, так как прийдется его таблицой эмулировать.
S>Если хотите выносить детали конкретной СУБД в плагин, то плагин либо должен полностью содержать вот такие блоки "получил-использовал-отпустил", либо выставлять IDisposable так, чтобы основной код мог быть написан с using().
S>Таким образом, вам не придётся мучительно думать о возможном наличии второго потока, который сейчас использует это же соединение, или о том, как правильно распараллелить работу, или об удержании соединений открытыми,
Как быть с медленными операциями? На миллионах записей сильно не съэкономишь...
S>или о стоимости переоткрытия соединения заново.
Это весьма важная вещь, так как запись в некоторые таблицы нужно производить настолько быстро насколько возможно, где 200 мс уже много.
Данные поступают от оборудования и его может быть довольно много.
Re[3]: Как лучше организовать паралельное исполнение запросов
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.11.14 18:37
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN>Чтобы избежать накладных расходов по открытию и закрытию.

Это плохое решение сформулированной проблемы. Правильное решение — пул соединений.
AN>Я пока не разбирался в деталях попробую вытянуть тест кейс.
AN>Не тестил пока сколько времени занимает, но любая добавка весьма нежелательна.
Какая "добавка"?

AN>Здесь есть один ньюанс, который в принципе невозможен — "быстро делаем всю работу". Хотя бы обновление мат. въюва занимает от получаса до часа. А в SQL будет может и поболее, так как прийдется его таблицой эмулировать.

AN>Как быть с медленными операциями? На миллионах записей сильно не съэкономишь...
Ну, вообще-то для таких медленных задач стоимостью открытия нового соединения можно и пренебречь. Т.е. один из вариантов тюнинга — это отказ от пула соединений для медленных задач; это позволяет избежать исчерпания пула. Его обычно делают лимитированным для того, чтобы ошибка в программе с утечкой соединений не положила нафиг сервер.

S>>или о стоимости переоткрытия соединения заново.

AN>Это весьма важная вещь, так как запись в некоторые таблицы нужно производить настолько быстро насколько возможно, где 200 мс уже много.
за 200мс вы успеете много-много раз получить соединение из пула и вернуть его обратно.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Как лучше организовать паралельное исполнение запросов
От: AlexNek  
Дата: 11.11.14 20:24
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, AlexNek, Вы писали:


AN>>Чтобы избежать накладных расходов по открытию и закрытию.

S>Это плохое решение сформулированной проблемы. Правильное решение — пул соединений.
Попробую разобраться отчего от него отказались.
AN>>Я пока не разбирался в деталях попробую вытянуть тест кейс.
AN>>Не тестил пока сколько времени занимает, но любая добавка весьма нежелательна.
S>Какая "добавка"?
Добавка времени на исполнение запроса.

AN>>Здесь есть один ньюанс, который в принципе невозможен — "быстро делаем всю работу". Хотя бы обновление мат. въюва занимает от получаса до часа. А в SQL будет может и поболее, так как прийдется его таблицой эмулировать.

AN>>Как быть с медленными операциями? На миллионах записей сильно не съэкономишь...
S>Ну, вообще-то для таких медленных задач стоимостью открытия нового соединения можно и пренебречь.
Это самой собой, но плагин то не знает заранее сколько времени потребует исполнения данной команды, да и для некоторых запросов время исполнения зависит от многих факторов.

S>Т.е. один из вариантов тюнинга — это отказ от пула соединений для медленных задач; это позволяет избежать исчерпания пула. Его обычно делают лимитированным для того, чтобы ошибка в программе с утечкой соединений не положила нафиг сервер.

То бишь его можно включать и выключать runtime? Но как объединить медленные и быстрые запросы без паралельного выполнения?

S>>>или о стоимости переоткрытия соединения заново.

AN>>Это весьма важная вещь, так как запись в некоторые таблицы нужно производить настолько быстро насколько возможно, где 200 мс уже много.
S>за 200мс вы успеете много-много раз получить соединение из пула и вернуть его обратно.
да пусть даже лишнии 20 мс, на 1000 запросов будет уже дополнительно 20 секунд. Но это все нужно конечно мерять возможно тормоз будет в другом месте.
Re[5]: Как лучше организовать паралельное исполнение запросов
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.11.14 04:10
Оценка:
Здравствуйте, AlexNek, Вы писали:
AN>Это самой собой, но плагин то не знает заранее сколько времени потребует исполнения данной команды, да и для некоторых запросов время исполнения зависит от многих факторов.
Какой у плагина интерфейс? Что он выставляет наружу? Специфичные методы типа UpdateReportView или общие GetSqlCommand(string sql)?

S>>Т.е. один из вариантов тюнинга — это отказ от пула соединений для медленных задач; это позволяет избежать исчерпания пула. Его обычно делают лимитированным для того, чтобы ошибка в программе с утечкой соединений не положила нафиг сервер.

AN>То бишь его можно включать и выключать runtime?
Обычно SQL-провайдер выставляет параметр "брать ли соединение из пула" в connection string.
AN>Но как объединить медленные и быстрые запросы без паралельного выполнения?
Я не понимаю, что вы называете "параллельным выполнением".
AN>да пусть даже лишнии 20 мс, на 1000 запросов будет уже дополнительно 20 секунд. Но это все нужно конечно мерять возможно тормоз будет в другом месте.
Конечно. Если вы будете искусственно удерживать простаивающее соединение с сервером, это скорее всего вызовет "тормоза в другом месте".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: Как лучше организовать паралельное исполнение запросов
От: AlexNek  
Дата: 12.11.14 06:57
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, AlexNek, Вы писали:

AN>>Это самой собой, но плагин то не знает заранее сколько времени потребует исполнения данной команды, да и для некоторых запросов время исполнения зависит от многих факторов.
S>Какой у плагина интерфейс? Что он выставляет наружу? Специфичные методы типа UpdateReportView или общие GetSqlCommand(string sql)?
Вообще то общий подход такой, что приложение не имеет права использовать SQL или подстройку под спейифику БД. Имеется набор команд и набор операций.
Вот команда "обновить" для примера
  public interface IDbInterfaceUpdate : IDbConnection
  {
      int UpdateData(string operation, uint dataUsageFlags, DbDataItem dataItem, CommonSqlParameters updateFilters, IBackNotification notification);
  }

Операция для данной команды будет имя таблицы, которая пользуется только как имя операции.
dataUsageFlags — Набор битовых флагов какие поля пользовать для генерации SQL
dataItem — как бы строка таблицы
updateFilters — часть для генерации where
notification — сообщения мз плагина.

S>>>Т.е. один из вариантов тюнинга — это отказ от пула соединений для медленных задач; это позволяет избежать исчерпания пула. Его обычно делают лимитированным для того, чтобы ошибка в программе с утечкой соединений не положила нафиг сервер.

AN>>То бишь его можно включать и выключать runtime?
S>Обычно SQL-провайдер выставляет параметр "брать ли соединение из пула" в connection string.
Пока не пользовали, надо будет глянуть.
AN>>Но как объединить медленные и быстрые запросы без паралельного выполнения?
S>Я не понимаю, что вы называете "параллельным выполнением".
Запускаем обновление мат. въюва время выполнения весьма приличное. В это же время от оборудования приходит команда на запись данных. Нужно ее также исполнить.
То есть два запроса должны исполнятся паралельно
AN>>да пусть даже лишнии 20 мс, на 1000 запросов будет уже дополнительно 20 секунд. Но это все нужно конечно мерять возможно тормоз будет в другом месте.
S>Конечно. Если вы будете искусственно удерживать простаивающее соединение с сервером, это скорее всего вызовет "тормоза в другом месте".
Кстати, вспомнил еще "полезность" открытого соединения:
Часть приложения выполненена в виде сервиса с протоколированием всех ошибок. Предположим, соединение с базой исчезло. Тогда будет одно сообщение об ошибке и ни один запрос больше не будет выполняться.
Как только соединение удалось восстановить, сообщаем и продолжаем. Для варианта с открытием/закрытием прийдется что то добавлять.
А "тормоз в другом месте" имелось в виду совсем другое, часть вообще не связанная напрямую с базой.
Re[7]: Как лучше организовать паралельное исполнение запросов
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.11.14 07:16
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN>Здравствуйте, Sinclair, Вы писали:


S>>Здравствуйте, AlexNek, Вы писали:

AN>>>Это самой собой, но плагин то не знает заранее сколько времени потребует исполнения данной команды, да и для некоторых запросов время исполнения зависит от многих факторов.
S>>Какой у плагина интерфейс? Что он выставляет наружу? Специфичные методы типа UpdateReportView или общие GetSqlCommand(string sql)?
AN>Вообще то общий подход такой, что приложение не имеет права использовать SQL или подстройку под спейифику БД. Имеется набор команд и набор операций.
AN>Вот команда "обновить" для примера
AN>
AN>  public interface IDbInterfaceUpdate : IDbConnection
AN>  {
AN>      int UpdateData(string operation, uint dataUsageFlags, DbDataItem dataItem, CommonSqlParameters updateFilters, IBackNotification notification);
AN>  }
AN>

Это ровно одна операция, и при этом она может в зависимости от параметров оказаться как длинной, так и быстрой?
Есть ли возможность развести быстрые и медленные команды?

AN>Запускаем обновление мат. въюва время выполнения весьма приличное. В это же время от оборудования приходит команда на запись данных. Нужно ее также исполнить.

AN>То есть два запроса должны исполнятся паралельно
Значит каждый из запросов надо отдавать в отдельный экземпляр IDbConnection. Не вижу с этим ровно никаких проблем. Команда "обновить" внутри себя должна просто получать соединение, выполнять SQL, возвращать соединение. Всё. Никакой потребности следить за соединениями за пределами плагина.

AN>Кстати, вспомнил еще "полезность" открытого соединения:

AN>Часть приложения выполненена в виде сервиса с протоколированием всех ошибок. Предположим, соединение с базой исчезло. Тогда будет одно сообщение об ошибке и ни один запрос больше не будет выполняться.
Запросы и так не будут выполняться — ведь соединения "с базой" (вы, наверное, имеете в виду доступность сервера) нет, а чудес не бывает.
AN>Как только соединение удалось восстановить, сообщаем и продолжаем. Для варианта с открытием/закрытием прийдется что то добавлять.
У вас уже есть код, который занимается восстановлением соединения. Перенесёте его в то место, где теперь открывается соединение.

AN>А "тормоз в другом месте" имелось в виду совсем другое, часть вообще не связанная напрямую с базой.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: Как лучше организовать паралельное исполнение запросов
От: AlexNek  
Дата: 12.11.14 18:27
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, AlexNek, Вы писали:


AN>>Здравствуйте, Sinclair, Вы писали:


S>>>Здравствуйте, AlexNek, Вы писали:

AN>>>>Это самой собой, но плагин то не знает заранее сколько времени потребует исполнения данной команды, да и для некоторых запросов время исполнения зависит от многих факторов.
S>>>Какой у плагина интерфейс? Что он выставляет наружу? Специфичные методы типа UpdateReportView или общие GetSqlCommand(string sql)?
AN>>Вообще то общий подход такой, что приложение не имеет права использовать SQL или подстройку под спейифику БД. Имеется набор команд и набор операций.
AN>>Вот команда "обновить" для примера
AN>>
AN>>  public interface IDbInterfaceUpdate : IDbConnection
AN>>  {
AN>>      int UpdateData(string operation, uint dataUsageFlags, DbDataItem dataItem, CommonSqlParameters updateFilters, IBackNotification notification);
AN>>  }
AN>>

S>Это ровно одна операция, и при этом она может в зависимости от параметров оказаться как длинной, так и быстрой?
Это ровно один прототип, операция в первом параметре. Грубо предсказать можно, но зависит от размера базы, да и не хотелось бы привязываться еще и к вероятному времени выполнения.
S>Есть ли возможность развести быстрые и медленные команды?
Для чего? На конкретной базе в конкретный день и при "конкретной погоде" будет одно, завтра будет другое. Хотя тенденция конечно есть.

AN>>Запускаем обновление мат. въюва время выполнения весьма приличное. В это же время от оборудования приходит команда на запись данных. Нужно ее также исполнить.

AN>>То есть два запроса должны исполнятся паралельно
S>Значит каждый из запросов надо отдавать в отдельный экземпляр IDbConnection. Не вижу с этим ровно никаких проблем. Команда "обновить" внутри себя должна просто получать соединение, выполнять SQL, возвращать соединение. Всё. Никакой потребности следить за соединениями за пределами плагина.
Ребята сегодня тестик соорудили, говорят единицы микросекунд. А проблемы были раньше при конкретной версии Оракла, баг в драйвере.
S>... в отдельный экземпляр IDbConnection
Так в принципе и решили, осталась только решить как идентифицировать вызывающий треад. Хотя может это и не нужно.

AN>>Кстати, вспомнил еще "полезность" открытого соединения:

AN>>Часть приложения выполненена в виде сервиса с протоколированием всех ошибок. Предположим, соединение с базой исчезло. Тогда будет одно сообщение об ошибке и ни один запрос больше не будет выполняться.
S>Запросы и так не будут выполняться — ведь соединения "с базой" (вы, наверное, имеете в виду доступность сервера) нет, а чудес не бывает.
Каждый необслуженный запрос будет выдавать ошибку в лог, что совсем не требуется.

AN>>Как только соединение удалось восстановить, сообщаем и продолжаем. Для варианта с открытием/закрытием прийдется что то добавлять.

S>У вас уже есть код, который занимается восстановлением соединения. Перенесёте его в то место, где теперь открывается соединение.
Там оно открывается и держится. И тот код совесем не хочется пользовать. Все в одной миске со спагетти.
Re[4]: Как лучше организовать паралельное исполнение запросов
От: . Великобритания  
Дата: 12.11.14 20:31
Оценка: +1
Здравствуйте, Sinclair, Вы писали:

S> Ну, вообще-то для таких медленных задач стоимостью открытия нового соединения можно и пренебречь. Т.е. один из вариантов тюнинга — это отказ от пула соединений для медленных задач; это позволяет избежать исчерпания пула. Его обычно делают лимитированным для того, чтобы ошибка в программе с утечкой соединений не положила нафиг сервер.

Не надо отказываться от пула, как минимум на уровне кода.
Пусть везде будет взятие из пула и возвращение. А дальше уже конфигурированием контекста приложения управлять всем этим. Например, завести два пула, вероятно разного размера — для быстрых и для медленных операций и инжектить в соответствующие части приложения.
Или два пула — для важных операций, и для неважных, которые могут пережить исчерпание.
А "отказаться от пула" всегда можно опять таки конфигурированием — задать неограниченный макс размер и короткий ttl (создание соединения на каждый запрос) или наоборот — пул с размером 1 (расшариваемое между всеми соединение).
avalon/1.0.432
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[5]: Как лучше организовать паралельное исполнение запросов
От: AlexNek  
Дата: 12.11.14 20:36
Оценка:
Здравствуйте, ., Вы писали:

.>Здравствуйте, Sinclair, Вы писали:


S>> Ну, вообще-то для таких медленных задач стоимостью открытия нового соединения можно и пренебречь. Т.е. один из вариантов тюнинга — это отказ от пула соединений для медленных задач; это позволяет избежать исчерпания пула. Его обычно делают лимитированным для того, чтобы ошибка в программе с утечкой соединений не положила нафиг сервер.

.>Не надо отказываться от пула, как минимум на уровне кода.
Уже так и решили, накладных расходов практически нет.
.>Пусть везде будет взятие из пула и возвращение. А дальше уже конфигурированием контекста приложения управлять всем этим. Например, завести два пула, вероятно разного размера — для быстрых и для медленных операций и инжектить в соответствующие части приложения.
.>Или два пула — для важных операций, и для неважных, которые могут пережить исчерпание.
А каким образом сделать несколько пулов или имелось в виду просто несколько соединений? Какое оптимальное количество соединений для пула?
Re[6]: Как лучше организовать паралельное исполнение запросов
От: . Великобритания  
Дата: 12.11.14 20:48
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN> .>Не надо отказываться от пула, как минимум на уровне кода.

AN> Уже так и решили, накладных расходов практически нет.
Вообще говоря "пул" это лишь паттерн проектирования, сам по себе он не может вносить накладные расходы в принципе (если, конечно, может быть пару вызовов виртуальных методов не считать).

AN> А каким образом сделать несколько пулов или имелось в виду просто несколько соединений?

Ну как, создать их. Я не знаю что там у вас. С т.з. структуры кода будет как-то так:
interface Pool
{
  Connection getConnection();
}
...
class Plugin1
{
   Pool pool;
   void myMethod()
   {
     pool.getConnection()...use...close();
   }
}
...
class Plugin2
{
   Pool pool;
   void myMethod()
   {
     pool.getConnection()...use...close();
   }
}

class ApplicationContext
{
   void configure()
   {
      Pool poolFast = new PoolImpl(connectionString);
      Pool poolSlow = new PoolImpl(connectionString);
      Plugin1 p1 = new Plugin(poolFast);
      Plugin1 p2 = new Plugin(poolSlow);
   }
}


AN> Какое оптимальное количество соединений для пула?

Подбирается только опытным путём.
Не знаю какие вы там имплементации пулов используете, но обычно они умеют задать минимальное, максимальное число соединений, время жизни (т.е. если взялось из пула больше минимума, потом вернулось и не использовалось некоторое время, то соединения закрывается), препроверка здоровья соединения (некий тривиальный запрос, обычно "select 1 from dual", который выполняется перед тем как вернуть из пула), детектор утечек соединений, сбор всякой статистики использования и прочие вкусности.
avalon/1.0.432
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[7]: Как лучше организовать паралельное исполнение запросов
От: AlexNek  
Дата: 12.11.14 21:40
Оценка:
Здравствуйте, ., Вы писали:

.>Здравствуйте, AlexNek, Вы писали:


AN>> .>Не надо отказываться от пула, как минимум на уровне кода.

AN>> Уже так и решили, накладных расходов практически нет.
.>Вообще говоря "пул" это лишь паттерн проектирования, сам по себе он не может вносить накладные расходы в принципе (если, конечно, может быть пару вызовов виртуальных методов не считать).
Ааа, там мы о разных пулах говорим, я имел в виду уже готовую имплементацию от Оракла и SQL.

AN>> Какое оптимальное количество соединений для пула?

.>Подбирается только опытным путём.
.>Не знаю какие вы там имплементации пулов используете, но обычно они умеют задать минимальное, максимальное число соединений, время жизни (т.е. если взялось из пула больше минимума, потом вернулось и не использовалось некоторое время, то соединения закрывается),
.>препроверка здоровья соединения (некий тривиальный запрос, обычно "select 1 from dual", который выполняется перед тем как вернуть из пула), детектор утечек соединений, сбор всякой статистики использования и прочие вкусности.
вот это уже интересней, в стандартных есть?
Re[3]: Как лучше организовать паралельное исполнение запросо
От: koodeer  
Дата: 12.11.14 22:04
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN>А сколько будет время открытия/закрытия соединения? Если даже 100 мс, то это уже много.


Время будет 0. Соединение остаётся открытым в пуле и при следующем обращении берётся уже готовое, а не открывается заново.

PS: блин, я тормоз, только сейчас заметил тему; уже всё разжёвано раньше.
Отредактировано 12.11.2014 22:10 koodeer . Предыдущая версия .
Re[8]: Как лучше организовать паралельное исполнение запросов
От: . Великобритания  
Дата: 12.11.14 22:05
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN> .>Вообще говоря "пул" это лишь паттерн проектирования, сам по себе он не может вносить накладные расходы в принципе (если, конечно, может быть пару вызовов виртуальных методов не считать).

AN> Ааа, там мы о разных пулах говорим, я имел в виду уже готовую имплементацию от Оракла и SQL.
Судя по вопросам ты наверное из .net, там да, всё плохо. Что Майкрософт дал, то и жрите. Для java есть куча разных имплементаций пула, большинство которых работают с любой СУБД, или даже вообще не с СУБД, а с любым ресурсом.

AN> вот это уже интересней, в стандартных есть?

Не знаю что там у вас в .net стандартное, но надеюсь что тебе стало понятнее о чём это всё и что вообще бывает. Скажем тут есть min/max pool size, period of inactivity, и т.п.
avalon/1.0.432
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[9]: Как лучше организовать паралельное исполнение запросов
От: AlexNek  
Дата: 12.11.14 22:25
Оценка:
Здравствуйте, ., Вы писали:

.>Здравствуйте, AlexNek, Вы писали:


AN>> .>Вообще говоря "пул" это лишь паттерн проектирования, сам по себе он не может вносить накладные расходы в принципе (если, конечно, может быть пару вызовов виртуальных методов не считать).

AN>> Ааа, там мы о разных пулах говорим, я имел в виду уже готовую имплементацию от Оракла и SQL.
.>Судя по вопросам ты наверное из .net, там да, всё плохо. Что Майкрософт дал, то и жрите. Для java есть куча разных имплементаций пула, большинство которых работают с любой СУБД, или даже вообще не с СУБД, а с любым ресурсом.

Да .NET. Можно и самому сделать, но раз уж есть готовое к базе.....

AN>> вот это уже интересней, в стандартных есть?

.>Не знаю что там у вас в .net стандартное, но надеюсь что тебе стало понятнее о чём это всё и что вообще бывает. Скажем тут есть min/max pool size, period of inactivity, и т.п.
Интересовало именно "препроверка здоровья соединения"
Re[10]: Как лучше организовать паралельное исполнение запросов
От: . Великобритания  
Дата: 12.11.14 22:41
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN> Да .NET. Можно и самому сделать, но раз уж есть готовое к базе.....

Начните с него, но, по-моему, со временем придётся самим делать.

AN> .>Не знаю что там у вас в .net стандартное, но надеюсь что тебе стало понятнее о чём это всё и что вообще бывает. Скажем тут есть min/max pool size, period of inactivity, и т.п.

AN> Интересовало именно "препроверка здоровья соединения"
А.. Хз, может и не умеет.
С другой стороны некоторые критикуют такой подход — каждое взятие соединения выполняет запрос, хоть и быстрый, но round-trip до базы всё равно будет. Если у вас куча очень маленьких быстрых запросов, то накладные расходы ещё одного на каждый могут стать существенными, притом 100% гарантии здоровья соединения всё равно нет, и ошибки придётся обрабатывать в любом случае.
Хотя, например, apache dbcp может всяко быть сконфигурирован — тестировать idle соединения или ограничить время жизни.
avalon/1.0.432
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.