TSQL: поиск запросов, вызывающих слишком много компиляций SQL и перекомпиляций SQL по отдельности


8

Я хочу выяснить, что является причиной высокой компиляции SQL (не повторной компиляции), которую я вижу в счетчиках монитора производительности.

Вот мое мнение: если я вижу много компиляций SQl, то это означает, что запросы в нашей системе не кэшируются по следующим причинам:

  • Многие специальные запросы
  • Выполнение запросов, которые SQl не кеширует, например:

    ОБНОВЛЕНИЕ table1 SET col1 = 'Строка длиннее 8000 символов .....' WHERE key_column = некоторый int

  • Планы истекают и удаляются из кэша, потому что: в кеше недостаточно места или планы не используются достаточно долго.

Единственное, что подходит для захвата вставок в кеш в профилировщике, - это хранимые процедуры-> SP: CacheInserts, но он смотрит только после кеша хранимых процедур.

Поэтому я попробовал следующее, чтобы получить adhoc запросы:

SELECT [cp].[refcounts] -- when Refcounts becomes 0, plan is excluded from cache.
    , [cp].[usecounts] 
    , [cp].[objtype] 
    , st.[dbid] 
    , st.[objectid] 
    , st.[text] 
    , [qp].[query_plan] 
FROM sys.dm_exec_cached_plans cp     
CROSS APPLY sys.dm_exec_sql_text ( cp.plan_handle ) st     
CROSS APPLY sys.dm_exec_query_plan ( cp.plan_handle ) qp ;

Я думал, что запросы, которые вызывали компиляцию, должны быть с objtype = Adhoc, но это также может относиться к повторной компиляции. Теперь мне нужно запустить профилировщик, перехватить запросы, вызывающие перекомпиляцию, а затем исключить его из приведенного выше списка.

Я иду в правильном направлении?

Есть ли один запрос, который я могу использовать для выполнения только SQL-компиляций без особой работы?

Ресурсы, которые помогли мне в достижении вышеупомянутых знаний:

http://social.msdn.microsoft.com/Forums/en/sqldatabaseengine/thread/954b4fba-3774-42e3-86e7-e5172abe0c83 http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=143946 http: //technet.microsoft.com/en-nz/library/cc966425(en-us).aspx
http://www.sqlservercentral.com/Forums/Topic914951-360-1.aspx

Любая помощь очень ценится.

Ответы:


7

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

Performance: Performance statistics
Stored Procedures: RPC:Completed
TSQL: SQL:BatchCompleted
TSQL: SQL: BatchStarting

Установите флажок Показать все столбцы и выберите каждый из столбцов в разделе «Производительность: только событие статистики производительности». Остальные события можно оставить с настройками по умолчанию.

Затем выберите Фильтры столбцов и выполните фильтрацию по DatabaseName и / или LoginName / ApplicationName / HostName и т. Д., Если вы их знаете. Цель состоит в том, чтобы ограничить число строк, отображаемых в Profiler, и сосредоточиться только на ваших потребностях.

Затем нажмите Run и дайте ему поработать некоторое время (2-3 минуты столько, сколько вам нужно). Проанализируйте результаты, рассматривая прежде всего: Событие статистики производительности.

Если статистика производительности встречается часто, это означает, что план запроса был кэширован впервые, скомпилирован, перекомпилирован или исключен из PlanCache. Насколько мне известно, если у запроса нет плана запроса в кэше планов , вы увидите 2 строки события PerformanceStatistics, за которыми следуют SQL: BatchStarting , затем SQL: BatchCompleted . Это означает, что план запроса был сначала скомпилирован, кэширован, а затем запрос запущен и завершен.

Посмотрите на следующие столбцы в разделе Статистика производительности:

SPID - ID of the session on which the event occurred. You can use it to identify the       
       row on SQL:BatchCompleted event which will display the SQL Query text and other  
       usefull information (Read/Writes, StartTime/EndTime)
Duration - Total time, in microseconds, spent during compilation.
EventSubClass - 0 = New batch SQL text that is not currently present in the cache.
                1 = Queries within a stored procedure have been compiled.
                2 = Queries within an ad hoc SQL statement have been compiled.
                3 = A cached query has been destroyed and the historical performance         
                    data associated with the plan is about to be destroyed.
                4 = A cached stored procedure has been removed from the cache and the  
                    historical performance data associated with it is about to be 
                    destroyed.

                5 = A cached trigger has been removed from the cache and the historical  
                    performance data associated with it is about to be destroyed.

Учитывая номер EventSubClass, вы можете узнать, что произошло с планом запроса, и принять конкретные меры. Кроме того, вы можете добавить другие столбцы к хранимым процедурам и классам событий TSQL, если вы пересекаетесь с HostName, WindowsUser или другой информацией из трассировки Profiler. Также трассировка может быть сохранена в таблице SQL, что делает анализ более простым и гораздо более настраиваемым. Вот ссылка, более подробно описывающая класс событий статистики производительности.


4

Что ж, сначала посмотрим, есть ли давление на кеш.

select bpool_visible from sys.dm_os_sys_info
go

Умножьте это число на 8, чтобы получить память в K. 75% от 0-4G + 10% от 4G-64G + 5% больше - это предел ограничения кэша плана . Если вы достигнете 75% этого предела, SQL Server начнет очистку планов из кэша. Эта очистка происходит, когда новый план запроса добавляется в кэш, так что поток сделает паузу для выполнения этой работы. Второе, что может привести к очистке планов, - это если число планов в 4 раза превышает количество хеш-сегментов (хеш-таблица отображает дескриптор plan_handle в план). В 32-битной системе их 10 000, а в 64-битной - 40 000.

select type, sum(pages_allocated_count) as pages_used from sys.dm_os_memory_objects 
where type in ('MEMOBJ_CACHESTOREOBJCP', 'MEMOBJ_CACHESTORESQLCP', 'MEMOBJ_CACHESTOREXPROC')
group by type
go

Решение о том, что производить очистку, принимается не по использованию, а по стоимости плана, сначала удаляются самые дешевые планы (стоимость производства, а не выполнения). Вы можете увидеть это, если добавите столбцыoriginal_cost и current_costк вашему запросу sys.dm_exec_cached_plans. Специальный план начинается с 0 и увеличивается на 1 каждый раз, когда он используется. Когда происходит кэш-нагрузка, SQL Server вычитает половину из каждой стоимости, а затем удаляет те, которые достигли 0.

Если у вас много специальных SQL, попробуйте:

exec sp_reconfigure 'optimize for ad hoc workloads', 1
go
reconfigure
go

В этом режиме SQL Server кэширует только «заглушку», размером приблизительно 300 байт (обычный план запроса - минимум 24 КБ), содержащий хэш и указатель на текст SQL, когда он впервые видит конкретный оператор SQL, затем впоследствии кэширует полный план, если он выполняется снова. Это не обязательно сократит саму компиляцию, но уменьшит нагрузку на память в кеше плана.

Примечание: это работает в 2008 году, не пробовал в 2005 году.

Еще один трюк

alter database ... set parameterization forced
go

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


Спасибо! Я знал об этой опции «принудительной параметризации», но боялся ее использовать. Единственный недостаток, который я вижу при использовании этого, - то, что он заполнит кеш. Я прав?
Manjot

3

У вас есть много часто запускаемых заданий SQL Server на этом поле? Обратите внимание, что в 2005 году запросы заданий агента НЕ кэшируются и могут также привести к раздуванию кеша и компиляции sql.

Посмотрите на количество планов с низким количеством повторного использования. Это ваши виновники.

Некоторые примечания по планированию кэширования приведены ниже.

http://www.sqlskills.com/BLOGS/KIMBERLY/post/Plan-cache-adhoc-workloads-and-clearing-the-single-use-plan-cache-bloat.aspx

http://www.sqlskills.com/BLOGS/KIMBERLY/post/Clearing-the-cache-are-there-other-options.aspx


0

Этот эффект известен как «загрязнение плана запроса», когда многие похожие запросы SQL генерируют отдельные, но эквивалентные планы выполнения.

Специальные запросы вызывают издержки при отдельном разборе, но обычно не загрязняют план запроса, поскольку их планы не сохраняются. Это отличается для запросов только с одним параметром (под MS SQL Server), они будут рассматриваться как параметризованный запрос.

Существует несколько типичных случаев загрязнения плана запроса:

  • SQL-запросы только с одним жестко закодированным литеральным параметром (например, «выберите идентификатор, имя от лица, где идентификатор = 1234»)
  • особенно если используется с командами / хранимыми процедурами, которые вынуждают базу данных хранить план запроса, такой как sp_prepexec или sp_executesql под MSSQL (я думаю, что «немедленно выполнить» под Oracle работает аналогичным образом)
  • частично параметризованные запросы с большой разницей в жестко закодированных литеральных значениях, таких как «select * from SoccerMatches sm, где sm.Date>?» и см. дата <? и HomeClubId = 5678 и GuestClubId = 1234 '. Они сохранят планы запросов из-за параметров, но создадут новый план запросов для каждого измененного HomeClub или GuestClub (особенно, поскольку значения даты / времени являются отличным поводом для ввода параметров во многих API БД, когда запросы не выполняются из-за локально различной даты форматы).
  • Другим источником загрязнения плана запросов могут быть фреймворки, такие как ADO.NET с недостаточными драйверами в сочетании со значениями string / (n) varchar. Некоторые реализации / драйверы устанавливают размеры параметров на фактическую длину строки, вызывая отдельный план запроса для каждой другой длины параметра строки в запросе. Лучшей практикой, как представляется, является использование максимального размера поля (например, varchar (4000)) или драйвера, который устанавливает правильную длину
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.