2016-12-22 4 views
0

У меня есть консольное пакетное приложение, которое включает в себя процесс, который использует SqlDataAdapter.Fill (DataTable) для выполнения простого SELECT в таблице.Заполнение (DataTable) преуспевает в тестировании, зависает в Production

private DataTable getMyTable(string conStr) 
    { 
     DataTable tb = new DataTable(); 
     StringBuilder bSql = new StringBuilder(); 
     bSql.AppendLine("SELECT * FROM MyDB.dbo.MyTable"); 
     bSql.AppendLine("WHERE LEN(IdString) > 0");     
     try 
     { 
      string connStr = ConfigurationManager.ConnectionStrings[conStr].ConnectionString; 
      using (SqlConnection conn = new SqlConnection(connStr)) 
      { 
       conn.Open(); 
       using (SqlDataAdapter adpt = new SqlDataAdapter(bSql.ToString(), conn)) 
       { 
        adpt.Fill(tb); 
       } 

      } 
      return tb; 
     }   
     catch (SqlException sx) 
     { 
      throw sx; 
     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 
    } 

Этот метод выполняется синхронно, и успешно работает в нескольких тестовых средах в течение многих месяцев тестирования - и при запуске из командной строки или запускаются под контролем работы AutoSys.

При переходе в производство процесс зависает - по методу Fill, насколько мы можем это понять. Хуже того, вместо того, чтобы выходить из строя, он, по-видимому, начал порождать новые запросы, а через пару часов потреблял более 5 ГБ памяти на сервере приложений. Это повлияло на другие активные приложения, что сделало меня очень непопулярным. Никакого исключения не было.

Строка соединения примерно такая же ванильная, как и они.

"data source=SERVER\INSTANCE;initial catalog=MyDB;integrated security=True;" 

Извинения, если я использую неправильные термины относительно того, что сообщает SQL DBA ниже, но когда мы имели след положить на SQL Server, он показал идентификатор приложения (в соответствии с которым работа AutoSys была запущена) принимаются как действительный логин. Затем сервер обработал запрос SELECT. Однако он никогда не возвращал ответ. Вместо этого он перешел в статус «ожидающей команды». Поток запросов, казалось, оставался открытым в течение нескольких минут, а затем исчез.

Администратор DBA сказал, что не было признаков тупика, но ему нужно было бы контролировать в реальном времени, чтобы определить, есть ли блокировка.

Это происходит только в производственной среде; в тестовых средах серверы SQL всегда отвечали менее чем за секунду.

Идентификатор приложения AutoSys не является новым - он использовался несколько лет с другими SQL-серверами и не имел проблем. Администратор баз данных даже запускал запрос SELECT на рабочем сервере SQL, зарегистрированном в качестве этого идентификатора, и он ответил нормально.

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

Нам нужно решить эту проблему рано или поздно. Объем данных, на которые мы смотрим, в настоящее время составляет всего несколько строк, но будет увеличиваться в течение следующих нескольких месяцев. Из того, что происходит, я полагаю, что это связано с коммуникацией и/или безопасностью между сервером приложений и SQL-сервером.

Любые дополнительные идеи или предметы для расследования приветствуются. Всем спасибо.

+0

С большими базами данных может потребоваться много времени для завершения запроса в VS. Предотвращайте зависание. Я использую BackGroundWorker для выполнения работы. Вместо прямого запроса к базе данных я использую cmd.exe, который является исполняемым файлом командной строки (поставляется с SQL Server) для выполнения запроса и создания файла csv с результатами. Затем читайте результаты в приложении VS. Я запускаю cmd.exe из C#, используя класс процесса изнутри backgbroundworker. – jdweng

+0

@jdweng: Я думаю, что это хорошие моменты. если это один простой оператор select, запустите его из инструмента командной строки sql, исключайте возможность, что что-то не так внутри приложения. Насколько велика таблица? Вы можете запустить select с помощью TOP 1000, чтобы убедиться, что данные результата соответствуют ожиданиям. Запись данных в csv сначала звучит странно для меня в первый момент, но с реальными большими данными это может быть способ. –

+0

В моем приложении sqlcmd.exe занимал 30 минут или больше в базе данных 10 ГБ. Это было часами в качестве запроса в C#. И мои окна для приложения зависли во время выполнения запроса. Единственный метод, который я нашел для получения результатов sqlcmd.exe в C#, был с файлом csv. – jdweng

ответ

0

Хотя это может быть вызвано некоторыми странными разрешениями/ADO.NET вопросы, как уже упоминалось @user1895086, я, тем не менее рекомендовал бы перепроверить несколько вещей, которые еще раз:

  1. Убедитесь, что запросы выполняются вручную DBA и выполняется в вашем App же - либо жёстко его или, по крайней мере, log перед запуском. Лучше быть в безопасности, чем сожалеть.
  2. Попробуйте выбрать только несколько строк - всегда рекомендуется не выбирать всю таблицу, если вы можете ее избежать, и в нашем случае запрос SELECT TOP 1 (или 100) может не проявлять таких проблем. Возможно, данных гораздо больше, чем вы думаете, и ADO.Net просто покорно пытается загрузить все эти строки. Или, возможно, нет.
  3. Попробуйте SqlDataReader, чтобы убедиться, что SqlDataAdapter не вызывает никаких проблем. Да, он использует тот же DataAdapter internally, но мы бы по крайней мере исключили эти дополнительные операции из списка подозреваемых.
  4. Попытайтесь получить руку на дампе с этими 5 ГБ памяти - analyzing memory dumps не является тривиальной задачей, но не будет слишком сложно понять, что едят эти здоровенные куски памяти. Потому что я почему-то сомневаюсь, что ADO.NET просто породит множество дополнительных объектов без причины.
+0

Я принял этот ответ из-за предложения сравнить запрос, отправляемый приложением с тем, что было получено SQL Server. Фактически это происходило в методе, выполненном после вышеописанного, и доступ к другой БД с помощью Entity Framework. Предполагалось, что выражение LINQ должно заставить EF выбирать, самое большее, несколько сотен строк. Вместо этого запрос, который он преобразовал из LINQ, пытался загрузить всю память в 1,7 миллиона строк в таблицу, и делал это по 3 отдельным потокам запросов. – 66AndStillLearning

1

Это может быть связано с разрешениями. SQL Server делает некоторые нечетные вещи, вместо того, чтобы иногда давать правильное сообщение об ошибке.

Мое предложение, и это может повысить производительность в любом случае, заключается в том, чтобы написать хранимую процедуру на стороне сервера, которая выполняет выбор, и вызвать хранимую процедуру. Таким образом, администратор баз данных может обеспечить вам надлежащий доступ к хранимой процедуре, не допуская прямого доступа к таблице, если по какой-либо причине это блокируется, плюс вы должны увидеть небольшое повышение производительности.

+1

Хотя я согласен с почти всем здесь, почему вы думаете, что хранимая процедура будет предлагать повышение производительности по специальному запросу? –

+0

Это входит в дискуссию, которая бушует между программистами и имеет какое-то время, особенно сейчас, когда окно сужается. Было время, когда оно значительно изменилось, но теперь оно больше основано на окружающей среде. Тем не менее, использование хранимых процедур обычно повышает производительность очень незначительно (поскольку, как представляется, СУБД дает больше свободы для оптимизации запроса. Почему? Причины. Я не являюсь администратором базы данных), предотвращая некоторые ошибки, которые могут возникать при использовании ad-hoc, и он также позволяет изменять параметры запроса без необходимости повторной компиляции кода и повторного развертывания для потребителей. – CDove

+0

Это не повышает производительность. Выполнение компилируется и кэшируется для специального запроса так же, как хранимая процедура, начиная с sql 6.5 (почти два десятилетия назад). Я не говорю, что предпочитаю специальные запросы к хранимым процедурам. Напротив, я все в пользу хранимых процессов и никогда не буду писать свой собственный специальный запрос по большинству причин, о которых вы только что упоминали. Тем не менее, давно ошибочно, что хранимая процедура выполняется быстрее, чем запрос ad hoc. Это просто неправда. Ознакомьтесь с этой статьей о хранимых процедурах. https://sqlperformance.com/2013/05/t-sql-queries/another-argument-for-stored-procedures. –

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