2013-02-13 3 views
10

мне нужно подтверждение/объяснение от вас плюсов/гуру со следующим, потому что моя команда говорит мне «не имеет значения», и это fustrating меня :)производительность SQL, .Net Оптимизация против Best Practices

фона : У нас есть SQL Server 2008, который используется нашим основным веб-приложением MVC3 /. Net4. У нас около 200 + одновременных пользователей в любой момент. Сервер сильно ударяется (блокировки, тайм-ауты, общая медлительность), и я пытаюсь применить вещи, которые я узнал на протяжении своей карьеры и в моем последнем классе сертификации MS. Это вещи, которые мы все пробурили («закрыть SQL-соединения STAT»), и я пытаюсь объяснить моей команде, что эти «мелочи», хотя и не одни, вносят свой вклад, добавляются в конце.

мне нужно знать, если следующий имеют влияние на производительность или, если это просто «лучшая практика»

1. Использование «ИСПОЛЬЗОВАНИЕ» ключевое слово Большая часть их кода, как это:.

public string SomeMethod(string x, string y) { 
    SomethingDataContext dc = new SomethingDataContext(); 
    var x = dc.StoredProcedure(x, y); 
} 

Хотя я пытаюсь сказать им, что USING закрывает/освобождает ресурсы быстрее:

using (SomethingDataContext dc = new SomethingDataContext()) { 
    var x = dc.StoredProcedure(x, y); 
} 

Их аргумент состоит в том, что GC делает достаточно хорошую очистку работы после выполнения кода, поэтому ИСПОЛЬЗОВАНИЕ не оказывает большого влияния. Правда или ложь и почему?

2. Пулы соединения

Я всегда слышал создание пулов соединений может значительно ускорить любой веб-сайт (по крайней мере .Net ж/MSSQL). я рекомендовал добавить следующее нашим ConnectionStrings в web.config:

... "Аккумулирование = True; Min Pool Size = 3; Максимальный размер пула = 100; Соединение Timeout = 10;". ..

Их аргумент состоит в том, что .Net/MSSQL уже устанавливает пулы соединений за кулисами и не обязательно вводить наш web.config. Правда или ложь? Почему каждый другой сайт говорит, что объединение должно быть добавлено для оптимальной производительности, если оно уже настроено?

3. Минимизация # вызовов к БДУ

Провайдеру Роли/членства, который поставляется с по умолчанию проекта .Net MVC это хорошо - это удобно и делает большинство беготни для вас. Но эти ребята серьезно используют UsersInRoles() и используют его свободно, как глобальную переменную (она попадает в БД каждый раз, когда вызывается этот метод). Я создал «пользовательский объект», который загружает все роли вверх по каждой странице (вместе с некоторыми другими пользовательскими элементами, такими как GUID и т. Д.), А затем запрашивает этот объект, если у пользователя есть роль.

Другие части веб-сайта имеют операторы FOR, которые охватывают более 200 раз и выполняют 20-30 запросов на каждый проход = более 4000 запросов к базе данных. Это как-то делает это за считанные секунды, но то, что я хочу сделать, - это объединение вызовов 20-30 БД в один, так что он делает ОДИН вызов 200 раз (каждый цикл). Но поскольку SQL-профайлер говорит, что запрос занял «0 секунд», это аргумент: он настолько быстр и мал, что серверы могут обрабатывать большое количество запросов БД.

Мое мышление: «Да, эти запросы работают быстро, но они убивают общую производительность SQL-сервера». Это может быть фактором? Я не беспокоюсь ни о чем, или это (существенный) фактор, способствующий общим проблемам производительности сервера?

4. Другие оптимизации кода

Первое, что приходит на ум использует StringBuilder против простой переменной строки. Я понимаю, почему я должен использовать StringBuilder (особенно в циклах), но они говорят, что это не имеет значения - даже если им нужно писать строки 10k +, их аргумент в том, что прирост производительности не имеет значения.

Итак, все, что мы узнаем и пробудили в нас («свести к минимуму объем!»), Просто «лучшая практика» без реального выигрыша в производительности или все они способствуют РЕАЛЬНОЙ/измеримой производительности потеря?

EDIT *** Спасибо, ребята за все ваши ответы! У меня есть новый (5-й) вопрос, основанный на ваших ответах: Они на самом деле не используют «ИСПОЛЬЗОВАНИЕ», так что это значит? Если соединение пулов происходит автоматически, связывает ли он соединения из пула, пока не появится GC? Возможно ли, что каждое открытое соединение с сервером SQL добавляет немного больше нагрузки на сервер и замедляет его?

Основываясь на ваших предложениях, я планирую провести серьезный бенчмаркинг/протоколирование времени подключения, потому что я подозреваю, что a) сервер работает медленно, b) они не закрывают соединения и c) Профайлер говорит, что он работает в 0 секунд, медленность может возникать из соединения.

Я очень ценю вашу помощь. Еще раз спасибо

+0

Не сказать, что исследование не имеет значения, но гуру на SO действительно предоставляют много понимания ... изучение того, что они говорят, очень много исследований –

+0

@ JakeWilson801 Документация от MS не всегда является лучшим источником. (Редактирование: или даже хороший источник) –

+0

Re, используя строковый построитель вместо строк объединения - если вы объединяете строки один раз (т.е. 'var s =" a "+" b "'), тогда строка будет более эффективной, что вам нужно помнить, однако, что экземпляр строки не изменен, поэтому в цикле, например, 'string s =" a "; for (int i = 1, i <1000; i ++) {s + = "a";} 'вы создаете новый экземпляр строки для каждого цикла, это повлияет на распределение памяти и повлияет на общую производительность (независимо от того, будет зависеть от количества конкатенаций). – GarethD

ответ

5

Отделите этот код, внесите изменения & benchmark + профилируйте его с текущей кодовой базой. Тогда у вас появятся доказательства, подтверждающие ваши претензии.

Что касается ваших вопросов, здесь идет:

  1. Вы всегда должны вручную утилизировать классы, которые реализуют IDisposable ГХ не будет на самом деле назвать выбрасывайте однако, если класс также реализует финализации, то он будет вызывать однако в большинстве реализаций они очищают неуправляемые ресурсы.

  2. Это правда, что платформа .NET уже выполняет объединение пулов, я не уверен, что значения по умолчанию, но значения строки соединения будут только там, чтобы вы могли их изменять.

  3. Время выполнения инструкции SQL является лишь частью истории, в профайле SQL все, что вы увидите, это то, как долго выполнялся запрос на работу с системой базы данных, что вам не хватает, это время, которое требуется веб-сервер для подключения и получения результатов от сервера базы данных, поэтому, когда запрос может быть быстрым, вы можете сэкономить на множестве IO & латентности сети путем пакетных запросов.

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

+1

Согласно [этому сайту] (http://www.connectionstrings.com/articles/show/all-sql-server-connection-string-keywords), по умолчанию для объединения пулов равны 0 для min, 100 для макс. –

+0

+1 Этот ответ лучше всего подходит для каждого вопроса. Мне также нравится предложение о ветке и контроле. –

+0

Для # 1 - многие из вас сказали то же самое - что GC не очистит его сразу. Так это связано с одним из пулов соединений? может ли несколько сотен таких открытых соединений замедлить работу сервера? Для # 3 вы просто дали мне ОГРОМНЫЙ аргумент. Я попытаюсь изолировать время соединения и добавить его для каждого из 2000 дБ вызовов за клик и посмотреть, что из этого выйдет - спасибо за хорошую идею! – Losbear

3
  1. объектов, которые реализуют IDisposable и держат на inmanaged ресурсы также осуществлять finilizer, что будет гарантировать, что отчуждать вызывается во время GC, проблема в том, когда она вызывается, то дс может занять много времени, чтобы сделать перед этим вам и вашим мигрантам нужны эти ресурсы. Использование делает вызов для удаления, как только вы закончите с ним.

  2. Вы можете изменить параметры объединения в WebConfig, но его по умолчанию в настоящее время, так что если вы оставить параметры по умолчанию, вы не получает ничего

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

  4. StringBuilder не влияет на производительность в большинстве веб-приложений, было бы очень важно, если вы объединяете 2 раза в одну строку, но я думаю, что это хорошая идея использовать ее, поскольку ее легче читать.

+1

Кроме того: объекты, у которых есть финализатор (и для которого SuppressFinalize was't called), требуют двух сборщиков мусора, пока они не будут полностью удалены. –

+0

В дополнение к моему собственному комментарию: типы, которые имеют финализатор и правильно реализуют одноразовый шаблон, вызовут SuppressFinalize в своей функции Dispose. Утилизируя такие типы, необходимость во второй сборке мусора поэтому удаляется. (Это должно относиться к моему первому комментарию лучше к вопросу) –

1

Ну, я не гуру, но у меня есть предложение: если они говорят, что вы не правы, скажите им, «Докажи Напишите мне тест Покажите мне, что 4000 звонков просто! так же быстро, как 200 звонков и оказывают такое же влияние на сервер! "

То же самое происходит. Если вы не в состоянии заставить их доказать свою правоту, докажите их не так, с ясными, хорошо документированными тестами, которые показывают, что вы говорите правильно.

Если они не открыты даже для убедительных доказательств, собранных со своего сервера, с кодом, на который они могут смотреть и проверять, тогда вы можете тратить свое время на эту команду.

+0

Я не могу сказать «Докажите это» (насколько мне бы хотелось), потому что приложение было написано до того, как я вышел на борт. Так что теперь мое бремя доказать им, почему они должны вернуться и исправить свой код :) – Losbear

+0

@Losbear Это может быть тяжелая битва! Но направление, которое вы сказали (в других комментариях), вы планируете использовать в звуках, как хороший. Повторите тест и повторите попытку и покажите им твердые цифры. Удачи тебе! –

0

используя пункт просто синтаксический сахар, вы, по сути делает

try 
{ 
    resouce.DoStuff(); 
} 
finally 
{ 
    resource.Dispose() 
} 

Dispose, вероятно, будет вызываться в любом случае, когда объект мусора, но только если каркасные программисты сделали хороший работа по внедрению the disposable pattern. Итак, аргументы против ваших коллег здесь:

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

ii) Да, GC в конечном итоге очистит этот объект, но это может занять некоторое время, в зависимости от того, насколько старый этот объект. Очистка Gen 2 GC выполняется только один раз в секунду.

Так на коротком:

  1. см.выш

  2. да, объединение устанавливаются по умолчанию для истинного и максимального размера пула до 100

  3. вы правильно, безусловно, лучшая область чтобы продвигаться вперед.

  4. преждевременная оптимизация - корень всего зла. Сначала получите №1 и №3. Используйте специальные методы профилирования и db SQL (добавьте индексы, дефрагментируйте их, заблокируйте блокировки и т. Д.).

  5. Да, может быть.лучший способ - измерить его - посмотреть на первичную счетчик SQLServer: Общая статистика - User Connections; here - статья, описывающая, как это сделать.

Всегда измеряйте свои улучшения, не изменяйте код без доказательств!

+0

Согласовано - единственное, с чем моя команда и я соглашаемся, ни один из нас не хочет вкладывать слишком много работы в то, что не собирается чтобы помочь в этом; таких как преобразование строковых переменных в объекты строковой архитектуры LOL. Я думаю, что в конце концов, только твердые цифры из профилировщика убедят этих парней :) Thanks Bogdan – Losbear

2

Я думаю, что у вас есть два отдельных вопроса.

  1. Выполнение кода
  2. Производительность базы данных SQL Server

SQL Server

Есть ли у вас какие-либо контроль на месте для SQL Server? Знаете ли вы конкретно, какие запросы запускаются, что вызывает взаимоблокировки?

Я хотел бы прочитать this article on deadlocks и рассмотреть возможность установки блестящего Who is active, чтобы узнать, что действительно происходит на вашем SQL Server. Вы также можете рассмотреть возможность установки sp_Blitz от Brent Ozar. Это должно дать вам отличное представление о том, что происходит в вашей базе данных, и дать вам инструменты для исправления этой проблемы.

Другой код выдает

Я не могу комментировать другие вопросы кода с верхней части моей головы. Поэтому я сначала посмотрю на SQL-сервер.

Запомнить

  1. Monitor
  2. Выявление проблем
  3. Профиль
  4. Fix
  5. Перейти к 1
+0

Да, я посмотрел на SQL Profiler на реальном сервере и попытался показать им, что «посмотрите, этот ONE нажал 2 000 + звонков !» но их аргумент «но он сделал все эти 2k звонков за 2 секунды».Я пытаюсь пойти выше этого и встретить его с «этими двумя секундами», но я не на 100% уверен, потому что эти 2 секунды были смешаны с 200 другими одновременными пользователями. – Losbear

4

Oye. Конечно, вы не можете позволить GC закрыть ваши подключения к базе данных для вас. GC может не произойти в течение долгого времени ... иногда через несколько часов. Это происходит не сразу, как только переменная выходит за рамки. Большинство людей используют IDisposable, используя() {} синтаксис, который замечательный, но, по крайней мере, что-то, где-то нужно вызвать connection.Close()

0

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

Я смог определить, что ошибка произошла только тогда, когда был закрыт экземпляр SmtpClient, который произошел, когда был удален SmtpClient, что происходило только во время сбора мусора.

И я заметил, что это часто брал через две минуты после того, как кнопку «Отправить» была нажата ...

Излишне говорить, что код теперь корректно реализует using блоки для обоих SmtpClient и MailMessage экземпляров.

Просто слово мудрого ...

+0

2 минуты лучше, чем я думал, хе-хе - я думал, что GC зацикливается каждые 5 или 10 минут (что очень плохо). спасибо за то, что дал мне идею (я знаю, что может быть + или - несколько минут), как часто проходит GC. – Losbear

0

1 был решен значительно выше (я согласен с этим распоряжаться хорошо, однако, и нашел, что это хорошая практика).

2 является немного удержанием от предыдущих версий ODBC, в котором соединения SQL Server были настроены независимо в отношении объединения. Раньше это было не по умолчанию; теперь он по умолчанию.

Что касается 3 и 4, то 4 не повлияет на производительность вашего SQL Server - StringBuilder может ускорить процесс в пользовательском интерфейсе, что может привести к ускорению закрытия ваших SQL-ресурсов быстрее, но они выиграли Не уменьшайте нагрузку на SQL Server.

3 звучит как самое логичное место для сосредоточения, для меня. Я стараюсь как можно быстрее закрыть мои подключения к базе данных и сделать возможным наименьшее количество вызовов. Если вы используете LINQ, потяните все в IQueryable или что-нибудь (список, массив, что угодно), чтобы вы могли манипулировать им & создавать любые структуры пользовательского интерфейса, в которых вы нуждаетесь, освобождая соединение до любого из этих хокумов.

Все это говорит о том, что вам нужно потратить более качественное время на профайлер. Вместо того, чтобы смотреть на количество времени, которое выполнялось каждый раз, посмотрите на использование памяти процессора &. Просто потому, что они быстры, это не значит, что они не «голодные» казни.

1

Рискуя просто повторять то, что другие здесь сказали, вот мой 2с по этому вопросу

Во-первых, вы должны тщательно выбирать свои сражения ... Я бы не идти на войну со своими коллегами на всех 4 потому что, как только вы не сможете доказать одну из них, все кончено, и с их точки зрения они правы, и вы ошибаетесь. Также имейте в виду, что никто не любит, когда говорят, что их красивый код - уродливый ребенок, поэтому я полагаю, что вы будете дипломатичным - не говорите «это медленно», скажите: «Я нашел способ сделать это даже быстрее ».... (конечно, ваша команда может быть вполне разумной, поэтому я основываю это на собственном опыте :) Итак, вам нужно выбрать одну из 4 областей выше, чтобы заняться первым.

Мои деньги на # 3. 1, 2 и 4 могут иметь значение, но в моем собственном опыте не так много, но то, что вы описали в # 3, звучит как смерть тысячами papercuts для бедного старого сервера! Запросы, вероятно, выполняются быстро, потому что они параметризованы, поэтому они кэшируются, но вам нужно помнить, что «0 секунд» в профилировщике может составлять 900 миллисекунд, если вы понимаете, что я имею в виду ... добавьте это для многих и все начинает замедляться; это также может быть основным источником блокировок, потому что, если каждый из этих вложенных запросов снова и снова сталкивается с одной и той же таблицей, независимо от того, насколько быстро он работает, с количеством пользователей, о которых вы упомянули, уверен, что у вас будет спор. Возьмите SQL и запустите его в SSMS, но включите статистику клиентов, чтобы вы могли видеть не только время выполнения, но и количество данных, отправляемых обратно клиенту; это даст вам более четкое представление о том, какие накладные расходы причастны.

Действительно, единственный способ доказать это - это настроить тест и измерить, как упомянули другие, но также обязательно запустить также профилирование на сервере - блокировки, очереди ввода-вывода и т. Д., Чтобы вы можете показать, что не только ваш путь быстрее, но и меньше нагрузки на сервер.

Чтобы коснуться вашего пятого вопроса - я не уверен, но я бы предположил, что любое SqlConnection, которое не используется автоматически (с использованием), считается еще «активным» и больше не доступно из пула.Сказанное - накладные расходы на соединение довольно низки на сервере, если соединение фактически ничего не делает, но вы можете снова доказать это, используя счетчики производительности SQL.

Удачи вам в этом, не можем дождаться, чтобы узнать, как вы поживаете.

+0

Спасибо Стивен. Да, я планирую быть дипломатичным, LOL :) Я тоже подозреваю, что № 3, но я думаю, мне было интересно, какое влияние все эти проблемы будут иметь вместе - или это ОДНА проблема, которая может вызвать общую медлительность , Еще раз спасибо за ваш 2c - я опубликую свои результаты, когда завтра буду завтракать :) – Losbear