LINQ to SQL: слишком высокая загрузка ЦП: что происходит, когда несколько пользователей

Я использую LINQ to SQL и вижу, как взлетает мой процессор. Смотрите скриншот ниже. У меня три вопроса

  • Что я могу сделать, чтобы уменьшить использование процессора. Я сделал профилирование и в основном удалил все. Поможет ли превращение каждого оператора LINQ to SQL в скомпилированный запрос?

  • Я также обнаружил, что даже в случае скомпилированных запросов простые операторы, такие как ByID(), могут занять 3 миллисекунды на сервере с 3,25 ГБ ОЗУ 3,17 ГГц - это станет медленнее на менее мощном компьютере. Или скомпилированный запрос будет тем быстрее, чем больше он будет использоваться?

  • Загрузка ЦП (на локальном сервере достигает 12-15%) для одного пользователя будет умножаться на количество пользователей, обращающихся к серверу, - когда приложение помещается на работающий сервер. т.е.2 пользователя одновременно будут означать 15*2 = 30% загрузки ЦП. Если это так, то мое приложение ограничено максимум 4-5 пользователями одновременно. Или LINQ to SQL .net не разделяет использование процессора. http://www.freeimagehosting.net/uploads/5f10e1f694.png

5 ответов

Профиль. Профиль. Профиль.

Профиль, чтобы точно узнать, какой запрос занимает больше всего ресурсов, и повысить производительность этого запроса. Вы можете использовать свойство Log DataContext для просмотра SQL - см. Эту статью. Вы можете получить планы запросов для запросов в SQL Server - см. Эту статью.

Примеры способов улучшить запрос:

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

После того, как вы это сделаете, снова профиль, чтобы проверить, если вы улучшили производительность этого запроса. Если нет, повторяйте, пока не получите.

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

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

Я заметил подобное поведение с некоторыми приложениями здесь; Используя ANTS Profiler, мы сократили загрузку ЦП до кода Linq to SQL. Мы нашли несколько основных мест, где это становится проблемой:

  1. Сложные запросы Linq to SQL. Использование нескольких объединений, а также ограничения предложений и т.п. Проблема заключается в том, что механизм Linq to SQL должен преобразовывать оператор C# в оператор SQL. Я считаю, что это преобразование по умолчанию можно использовать повторно, если один и тот же код вызывается одним и тем же DataContext, но если вы создаете новый DataContext для каждого выполнения, то код преобразования с интенсивным использованием ЦП выполняется каждый раз. Эту проблему можно решить либо путем замены сложного запроса Linq to SQL хранимой процедурой, либо с помощью предварительно скомпилированного запроса Linq to SQL ( вот сообщение в блоге, показывающее, как создать скомпилированный запрос).
  2. Отражение на основе присвоения свойств. Мы обнаружили, что простые запросы, такие как DataContext.Orders.FirstOrDefault(o => o.OrderID = orderID) может быть очень загруженным процессором, так как они используют отражение, чтобы установить все свойства для возвращаемых значений из запроса. Мы не исследовали это за пределами этой точки; Мы просто заменили часть нашего кода на основе Linq to SQL стандартным доступом к данным на C# (например, SqlCommand, SqlClient) написанным от руки кодом, чтобы получить соответствующие данные столбца в соответствующие свойства, но только в тех местах, которые ANTS сказал нам, были наиболее важный. Внесение этого изменения, как правило, значительно снижало загрузку ЦП (например, снижение нагрузки с 2000 мс до 39 мс).
  3. Общая проблема производительности Linq (не относится только к Linq to SQL); Хотя написание запросов Linq действительно приводит к большему количеству намеренного раскрытия кода, чем аналогичные итеративные подходы, мы обнаружили, что иногда запросы оказываются очень неэффективными (обычно путем многократного повторения коллекции или создания декартового произведения, где в действительности нет необходимости)., У меня нет примеров этого, но ANTS сумел помочь найти и эти проблемы (обычно в поисках чрезвычайно высокого числа обращений для конкретной строки кода). Обычно они могут быть исправлены с небольшими изменениями в запросе Linq (или в некоторых случаях заменой запроса Linq на пару операторов).

Возможно, важно отметить, что наше использование Linq to SQL основано на файлах DBML, которые создает GUI, поэтому атрибуты украшают классы со всей информацией о сопоставлении столбцов и тому подобном.

Это именно то, что мы нашли в отношении Linq to SQL; Мне было бы интересно посмотреть, какой опыт у других. Я очень рекомендую ANTS Performance Profiler для определения того, где в вашем приложении сконцентрирована загрузка ЦП; Обратите внимание, что если высокая загрузка ЦП основана на SQL (что не похоже на ваш случай), то ANTS, вероятно, не поможет (как и весь мой ответ:)).

Скомпилированные запросы не станут "быстрее" с большей пользой. Основное преимущество скомпилированных запросов состоит в том, чтобы избавить ядро ​​LINQ от необходимости многократно выполнять процесс перевода при каждом его вызове.

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

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

После нескольких недель профилирования и отладки трассировки выяснилось, что злодейка выполняла jit-компиляцию запросов во время выполнения.

Мы прошли наш уровень данных и преобразовали все запросы в скомпилированные запросы, и наше использование ЦП мгновенно изменилось с постоянных 100% до среднего от 5% до 20% с некоторыми скачками до 80%, когда запросы были скомпилированы впервые.

  1. Есть ли общие запросы, которые можно кэшировать?
  2. Можно ли переписать запросы linq
  3. Большая часть обработки запросов выполняется на веб-сервере или в SQL?
  4. Вы используете и сервер SQL, и веб-сервер на одном компьютере? У вас есть тестовая среда, которая имитирует производственную среду?
Другие вопросы по тегам