Ваши вопросы повсюду, поэтому я постараюсь ответить на них все.Кеш процедур только такой большой.Кэш вашей процедуры, возможно, был заполнен планами одноразового использования (это не влияет на статистику, хотя статистика может влиять на кэш плана).Вы можете прочитать много подробностей о планах одноразового использования в блоге Кимберли Триппа: « Планирование кэша и оптимизация для рабочих нагрузок adhoc » - включая запрос к sys.dm_exec_cached_plans , который поможетопределить, когда в кэш заполняется множество одноразовых планов.Как она предлагает, вы можете предотвратить это вздутие живота с помощью оптимизации для специальных рабочих нагрузок.Если вы сталкиваетесь с необходимостью делать это часто, я бы сказал, что планирование freeproccache в качестве задания - это бинты, а не решение.
Чтобы очистить «плохой» план, сначала вам нужновыявить «плохой» план.Это может быть план, размер которого превышает определенный размер и / или который не был выполнен в течение некоторого времени, или который вы определили с помощью долгосрочного запроса и т. Д. К сожалению, нелегко определить план, который является жертвой параметра.сниффинг, если вы уже не знаете запрос или запросы, на которые влияют.Предположим, вы хотите найти в кэше самые старые планы, которые не запускались более недели:
;WITH x AS
(
SELECT TOP 10
qs.[sql_handle], qs.plan_handle,
txs = qs.statement_start_offset,
txe = qs.statement_end_offset,
[size] = cp.size_in_bytes,
[uses] = SUM(cp.usecounts),
[last] = MAX(qs.last_execution_time)
FROM
sys.dm_exec_query_stats AS qs
INNER JOIN
sys.dm_exec_cached_plans AS cp
ON qs.plan_handle = cp.plan_handle
WHERE
qs.last_execution_time < DATEADD(DAY, -7, CURRENT_TIMESTAMP)
GROUP BY
qs.[sql_handle], qs.plan_handle, cp.size_in_bytes,
qs.statement_start_offset, qs.statement_end_offset
ORDER BY
[size] DESC
)
SELECT
x.plan_handle,
size, uses, [last],
[statement] = COALESCE(NULLIF(
SUBSTRING(t.[text], x.txs/2,
CASE WHEN x.txe = -1 THEN 0 ELSE (x.txe - x.txs)/2 END
), ''), t.[text])
FROM x
CROSS APPLY sys.dm_exec_sql_text(x.[sql_handle]) AS t;
Теперь вам нужно убедиться, что вы действительно хотите очистить этот план.Например, если вы узнаете этот запрос как что-то, что генеральный директор может выполнить завтра, возможно, лучше оставить его там.Если вы хотите очистить план, вы можете очистить его напрямую, сказав:
DBCC FREEPROCCACHE([paste plan handle from above query here]);
Это звучит гораздо больше, чем выполнение DBCC FREEPROCCACHE
в глобальном масштабе, но если у вас много хорошо планирует в кеше, это, безусловно, будет лучше для ваших пользователей в целом.
Тем не менее, это действительно звучит как лейкопластырь.Если ваш кэш заполняется мусором и производительность снижается до тех пор, пока вы не освободите кэш, вам нужно взглянуть на более высокий уровень архитектуры, способа отправки запросов и т. Д. Это поведение, которое я ожидал бы отсамая первая итерация LINQ2SQL, где она будет кешировать версию плана для запроса для каждого строкового аргумента различной длины.Таким образом, если бы у вас был параметр «Январь», вы получили бы другой план, чем с параметром «Февраль», потому что он определил бы тип данных как VARCHAR(7)
против VARCHAR(8)
.Я уверен, что поведение исправлено, но я не знаю достаточно о вашей среде / приложении, чтобы предложить, где именно искать «плохие идеи».