«План запросов LINQ» ужасно неэффективен, но «план запросов Query Analyzer» идеально подходит для того же SQL! - PullRequest
10 голосов
/ 22 февраля 2010

У меня есть запрос LINQ to SQL, который генерирует следующий SQL:

exec sp_executesql N'SELECT COUNT(*) AS [value]
FROM [dbo].[SessionVisit] AS [t0]
WHERE ([t0].[VisitedStore] = @p0) AND (NOT ([t0].[Bot] = 1)) AND 
([t0].[SessionDate] > @p1)',N'@p0 int,@p1 datetime',
@p0=1,@p1='2010-02-15 01:24:00'

(Это фактический SQL, взятый из SQL Profiler на SQL Server 2008.)

План запросов, сгенерированный, когда я запускаю этот SQL из Query Analyser, идеален. Он использует индекс, содержащий VisitedStore, Bot, SessionDate. Запрос возвращается мгновенно.

Однако, когда я запускаю это из C # (с LINQ), используется другой план запроса, который настолько неэффективен, что даже не возвращается через 60 секунд. Этот план запроса пытается выполнить поиск ключа в кластерном первичном ключе, который содержит пару миллионов строк. У него нет шансов вернуться.

Что я просто не могу понять, так это то, что EXACT один и тот же SQL выполняется - либо из LINQ, либо из Query Analyzer, но план запроса другой.

Я выполнил два запроса много раз, и теперь они выполняются изолированно от любых других запросов. Дата - DateTime.Now.AddDays(-7), но я даже жестко закодировал эту дату, чтобы устранить проблемы с кэшированием.

Есть ли что-нибудь, что я могу изменить в LINQ to SQL, чтобы повлиять на план запроса или попытаться отладить это дальше? Я очень, очень смущен!

Ответы [ 2 ]

6 голосов
/ 22 февраля 2010

Это довольно распространенная проблема, которая меня тоже удивила, когда я впервые ее увидел. Первое, что нужно сделать, это убедиться, что ваша статистика актуальна. Вы можете проверить возраст статистики с:

SELECT 
    object_name = Object_Name(ind.object_id),
    IndexName = ind.name,
    StatisticsDate = STATS_DATE(ind.object_id, ind.index_id)
FROM SYS.INDEXES ind
order by STATS_DATE(ind.object_id, ind.index_id) desc

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

exec sp_updatestats

Помимо статистики, еще одна вещь, которую вы можете проверить, это SET . Они могут быть разными в Query Analyzer и в вашем приложении Linq2Sql.

Другая возможность состоит в том, что SQL Server использует старый кэшированный план для вашего запроса Linq2Sql. Планы могут кэшироваться отдельно для каждого пользователя, поэтому, если вы запустите Query Analyzer от имени другого пользователя, это может объяснить разные планы. Обычно вы можете добавить Option (RECOMPILE) к запросу приложения, но я думаю, что это сложно с Linq2Sql. Вы можете очистить весь кеш с помощью DBCC FREEPROCCACHE и посмотреть, ускоряет ли это запрос Linq2Sql.

0 голосов
/ 23 февраля 2010

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

надеюсь, это, по крайней мере, поможет кому-то в той же лодке, что и я

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