Узкое место в производительности - Linq to SQL или база данных - как мне сказать? - PullRequest
3 голосов
/ 13 февраля 2010

В настоящее время я пытаюсь повысить производительность своего веб-сайта для отчетов, использующего linq to sql и базу данных sql server express 2008. Я обнаружил, что, когда я подхожу к миллиону строк в моих более «уродливых» таблицах, производительность становится реальной проблемой, в частности, для создания одного отчета требуется 3 минуты.

По сути, у меня есть цикл, который для каждого пользователя обращается к базе данных и собирает на них набор данных. Затем эти данные запрашиваются различными способами (и по мере необходимости загружается больше строк), пока у меня не получится симпатичный небольшой сводный объект, который я могу запустить для набора диаграмм silverlight. Используется отложенная загрузка, и отчеты извлекают данные из приблизительно 8 связанных таблиц.

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

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

Поскольку я работаю в экспрессе, у меня нет доступа к профилировщику. Я рассматриваю возможность переписать свои запросы в скомпилированный linq для sql, но боюсь, что причиной может быть база данных.

Я понимаю, что этот вопрос является немного открытым, и на него трудно ответить, не зная гораздо больше о моей настройке (схема базы данных и т. Д.), Но любой совет о том, как найти узкие места, более ценится!

Спасибо

UPDATE: Спасибо за все отличные советы, ребята, и некоторые ссылки на некоторые отличные инструменты.

ОБНОВЛЕНИЕ для интересующихся Я не смог ускорить свои запросы, настроив linq. Кажется, проблема в том, что большая часть кода доступа к моей базе данных находится в цикле. Я не вижу выхода из этого. По сути, я создаю отчет, просматривая данные ряда пользователей - отсюда и цикл. Вытягивание всех записей заранее кажется немного сумасшедшим - 800 000 + строк. Я чувствую, что есть намного лучший способ, но это технологический скачок для меня слишком далеко!

Однако добавление еще одного индекса к одному из внешних ключей в одной из таблиц повысило производительность, поэтому теперь генерация отчета занимает 20 секунд, а не 3 минуты!

Ответы [ 3 ]

2 голосов
/ 13 февраля 2010

Я использовал этот замечательный инструмент: Linq2Sql profiler .Он работает на стороне приложения, поэтому нет необходимости в профилировании сервера баз данных.

Вам необходимо добавить одну строку кода инициализации в ваше приложение, а затем в отдельном профилировщике настольного приложения отобразится запрос SQL для каждого запроса LINQ с точной строкой кода, где он был выполнен (cs или aspx), временем базы данных.и время выполнения приложения, и оно даже обнаруживает некоторые распространенные проблемы производительности, такие как n + 1 запросы (запрос выполняется для итерации) или неограниченные наборы данных.Вы должны заплатить за это, но пробная версия также доступна.

2 голосов
/ 13 февраля 2010

Поскольку вы используете SQL Express, у которого нет Profiler, есть бесплатный сторонний профилировщик, который можно загрузить здесь . Я использовал его при запуске SQL Express. Это позволит вам отслеживать, что происходит в базе данных.

Кроме того, вы можете запросить динамические административные представления, чтобы увидеть, каковы дорогостоящие запросы: например ТОП 10 запросов, которые заняли больше всего времени

SELECT TOP 10 t.text, q.*, p.query_plan
FROM sys.dm_exec_query_stats q
    CROSS APPLY sys.dm_exec_sql_text(q.sql_handle) t
    CROSS APPLY sys.dm_exec_query_plan (q.plan_handle) AS p
ORDER BY q.total_worker_time DESC
2 голосов
/ 13 февраля 2010

Для этого я использую 2 инструмента, LinqPad и Visual Studio Debugger. Во-первых, посмотрите LinqPad , даже бесплатная версия очень мощная, показывает время выполнения, сгенерированный SQL, и вы можете использовать его для запуска любого фрагмента кода ... это чрезвычайно полезно .

Во-вторых, вы можете использовать отладчик Visual Studio, это то, что мы используем в нашем DataContext (примечание: используйте это только в отладке, это снижение производительности и совершенно не нужно вне отладки)

#if DEBUG
  private readonly Stopwatch Watch = new Stopwatch();

  private static void Connection_StateChange(object sender, StateChangeEventArgs e)
  {
    if (e.OriginalState == ConnectionState.Closed && e.CurrentState == ConnectionState.Open) 
    {
      Current.Watch.Start();
    }
    else if (e.OriginalState == ConnectionState.Open && e.CurrentState == ConnectionState.Closed)
    {
      Current.Watch.Stop();

      string msg = string.Format("SQL took {0}ms", Current.Watch.ElapsedMilliseconds);
      Trace.WriteLine(msg);
    }
  }
#endif

private static DataContext New
{
  get
  {
    var dc = new DataContext(ConnectionString);
#if DEBUG
    if (Debugger.IsAttached)
    {
      dc.Connection.StateChange += Connection_StateChange;
      dc.Log = new DebugWriter();
    }
#endif
    return dc;
  }
}

В отладочной сборке, когда операция завершается с каждым контекстом, мы видим метку времени в окне отладки и SQL, который он запускал. Класс DebugWriter, который вы видите, можно найти здесь (Фото: Крис Вандермоттен) . Мы можем быстро увидеть, занимает ли запрос время. Чтобы использовать его, мы просто инициируем DataContext:

var DB = DataContext.New;

(Профилировщик для меня не вариант, так как мы не используем SQL-сервер, этот ответ просто дать вам несколько альтернатив, которые были очень полезны для меня)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...