4

У меня есть программа, которая посылает несколько запросов параллельно экземпляру SQL Server. Из всех моих одновременных запросов один из них всегда блокируется в течение нескольких секунд на db.open().SqlConnection висит на открытии

void MyMethod() 
{ 
    var brands = new List<string>{"Chevy", "Honda", "Ford", "GM"}; 
    var foundCars = new ConcurrentBag<Car>(); 

    Parallel.ForEach(brands, brand => 
    { 
     logger.Trace(brand + " before enqueue"); 
     foundsCars.Enqueue(FindCar(brand)); 
     logger.Trace(brand + " after enqueue"); 
    }); 
} 

public Car FindCars(string brand) 
{ 
    using (var db = new SqlConnection(connectionString)) 
    { 
    sqlLogger.Trace("Brand " + " brand " + " before db open"); 
    db.Open(); 
    sqlLogger.Trace("Brand " + " brand " + " after db open"); 
    using (var cmd = new SqlCommand(sqlCmd, db)) 
    { 
     while (reader.Read()) 
     {    
      //SQL SELECT Stuff going on 
     } 
    } 
    } 
} 

Если бы я взглянуть на мой след, я бы увидеть что-то вроде этого, порядок зависит от времени отклика дб я думаю, в этом случае Honda является данные, медленно обрабатываются, но это не всегда будет :

12:00:00.0000 Chevy before enqueue 
12:00:00.0000 Honda before enqueue 
12:00:00.0000 Ford before enqueue 
12:00:00.0000 GM before enqueue 
12:00:00.0200 Brand Chevy before db open 
12:00:00.0300 Brand Honda before db open 
12:00:00.0200 Brand Ford before db open 
12:00:00.0200 Brand GM before db open 
12:00:00.0300 Brand Chevy after db open 
12:00:00.0300 Brand Ford after db open 
12:00:00.0300 Brand GM after db open 
12:00:00.0400 Chevy after enqueue 
12:00:00.0400 Ford after enqueue 
12:00:00.0400 GM after enqueue 
12:00:07.0000 Brand Honda after db open <-- usually around 7 seconds late 
12:00:07.0100 Honda after enqueue 

Я не могу воспроизвести эту проблему локально на мой экземпляр SQL Server 2008, но это происходит все время на 2012 экземпляра SQL Server. Проблема кажется проблемой конфигурации. Это всегда происходит, когда я отправляю параллельные запросы и независимо от запроса SELECT. Если бы я выполнил блокирующий запрос в SQL Server Management, он вернется в sub 100ms.

Вот моя строка соединения:

<add key="SqlConnectionString" value="Data Source=10.0.20.20;Initial Catalog=CarsDB;Integrated Security=SSPI;Connection Timeout=240;" /> 

Edit:

У меня есть вставки "Min Pool Size = 30" в моей строке соединения, похоже, только первый, второй или третьей время, в течение которого метод запускается в течение +15 секунд, тогда все остальные вызовы метода составляют до 500 мс.

У меня также есть SQL Server 2012, запущенный в нашем тестовом environement с теми же метаданными в таблицах, что и там, где проблема видна, и я не могу реплицировать эту проблему. Кажется, что проблема конфигурации.

+0

Можете ли вы добавить строку отладки, которая показывает время после того, как соединение db выходит из инструкции 'using'. 'using (var db = new SqlConnection (connectionString)) {/*...*/} sqlLogger.Trace (« Бренд »+« бренд »+« после закрытия db »);' затем обновите свой вопрос, указав порядок заявлений ? –

+0

Действительно ли это? Вы действительно думаете, что создание нескольких параллельных подключений к одной и той же таблице приведет к ускорению работы SQL. На другом конце находится один набор головок физического диска. Вы действительно думаете, что множественные соединения - это хорошее использование ресурсов? Если пять боссов сразу скажут вам, что им нужно, это означает, что вы можете работать в 5 раз быстрее? – Paparazzi

+0

Я действительно делаю, но это в правильном порядке, поэтому я пропустил дополнительный журнал. Все используемые инструкции корректно располагаются после возврата sql. Я не использую db.close() Должен ли использовать инструкцию using? – guiomie

ответ

0

Попробуйте использовать MARS в вашей ConnectionString. Это должно выглядеть как этот Data Source=10.0.20.20;Initial Catalog=CarsDB;Integrated Security=SSPI;Connection Timeout=240;MultipleActiveResultSets=True;

+0

MARS не повлияет на то, что он делает. Он имеет только один активный считыватель для каждого соединения. –

1

Если вы не многораздельной таблица этого безумия

Parallel.ForEach(brands, brand => 
{ 
    logger.Trace(brand + " before enqueue"); 
    foundsCars.Enqueue(FindCar(brand)); 
    logger.Trace(brand + " after enqueue"); 
}); 

Несколько соединения собираются после того, как та же таблица не быстрее, не говоря уже о накладных расходах нескольких соединений. С другой стороны, у вас есть одна физическая запись для чтения. Разве вы не открываете и не закрываете соединение, путь проходит намного дольше, чем простое чтение? На самом деле вы просто выстраиваете таблицу и читаете ее. Читатель очень быстро.

0

Похоже, что исчерпание пула соединений. Parallel.ForEach подвержен спаму безумных потоков. Насколько я могу судить, неограниченное количество для некоторых рабочих нагрузок IO. Ограничьте степень параллелизма на здравое значение.

+0

У меня была аналогичная логика с использованием Задачи в сочетании с WhenAll(), и проблема сохранялась. – guiomie

+0

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

+0

Мы говорим от 20 до 40 параллельных задач, из моего прошлого опыта это не так много. Вы так думаете? – guiomie

0

Переключение интегрированной безопасности с SSPI на пользователя/пароль в строке подключения исправило проблему. Кажется, что одна из наших проблем имеет проблемы с Active Directory, а другая - нет.

Смежные вопросы