Причина того, що size_in_bytesполе sys.dm_exec_cached_plansDMV, принаймні, з точки зору "Складені плани", є більшим, ніж CachedPlanSizeатрибут QueryPlanвузла в плані XML, тому що Скомпільований план - це не те саме, що план запитів. Складений план складається з декількох об'єктів пам'яті, комбінований розмір яких дорівнює size_in_bytesполі. Отже, опис " Кількість байтів, спожитих об'єктом кешу ", який ви знайшли в документації, є точним; просто неправильно трактувати те, що розуміється під "об'єктом кешу", даючи назву DMV, і що термін "план" має багато значень.
Складений план - це контейнер, в якому зберігаються різні фрагменти інформації, що стосуються партії запитів (тобто, не лише одне твердження), один (або більше) з цих фрагментів є планом (ими) запитів. У складених планах є об'єкт пам'яті верхнього рівня MEMOBJ_COMPILE_ADHOC, який є рядком sys.dm_os_memory_objects, пов'язаним через memory_object_addressполе в обох DMV. Цей об'єкт пам'яті містить таблицю символів, збір параметрів, посилання на пов'язані об'єкти, кеш-пам'ять аксесуара, кеш метаданих TDS та, можливо, деякі інші елементи. Складені плани поділяються між сесіями / користувачами, які виконують ту саму партію з тими ж налаштуваннями сесії. Однак деякі пов'язані об'єкти не діляться між сесіями / користувачами.
У складених планах також є один або більше залежних об'єктів, які можна знайти, передавши plan_handle(в sys.dm_exec_cached_plans) у sys.dm_exec_cached_plan_dependent_objectsDMF. Існує два типи залежних об'єктів: виконуваний план (об'єкт пам'яті = MEMOBJ_EXECUTE ) та курсор (об'єкт пам'яті = MEMOBJ_CURSOREXEC ). Буде 0 або більше об'єктів курсору, по одному на кожен курсор. Буде також один або кілька виконуваних об'єктів плану, по одному на кожного користувача, що виконує ту саму партію , отже, виконавчі плани не єділиться між Користувачами. Плани, що виконуються, містять параметр часу виконання та інформацію про локальну змінну, стан часу виконання, такий як оператор, що виконується в даний час, ідентифікатор об'єктів для об'єктів, створених під час виконання (я припускаю, що це стосується табличних змінних, тимчасових таблиць, тимчасових збережених процедур тощо) та, можливо, інші предмети.
Кожен оператор у пакеті з декількома операторами міститься у складеному звіті (Об'єкт пам'яті = MEMOBJ_STATEMENT ). Розмір кожної складеної заяви (тобто pages_in_bytes), розділеної на 1024, повинен відповідати CachedPlanSize="xx"значенням <QueryPlan>вузлів плану XML. Складені заяви часто матимуть один (можливо більше?) Планів запитів, пов’язаних із виконанням (Об'єкт пам'яті = MEMOBJ_XSTMT ). Нарешті, для кожного плану запиту виконання, який є запитом, повинен бути пов'язаний контекст виконання запитів (Об'єкт пам'яті = MEMOBJ_QUERYEXECCNTXTFORSE ).
Стосовно складених заяв, пакети з одним твердженням не мають окремих об'єктів компільованої заяви (тобто MEMOBJ_STATEMENT ) або окремих об'єктів плану запиту виконання (тобто MEMOBJ_XSTMT ). Значення для кожного з цих об'єктів буде зберігатися в головному об'єкті Compiled Plan (тобто MEMOBJ_COMPILE_ADHOC ), і в цьому випадку pages_in_bytesзначення для цього основного об'єкта, розділене на 1024, повинно відповідати CachedPlanSizeрозміру у <QueryPlan>вузлі плану XML. Однак ці значення не прирівнюватимуться до пакетів із кількома заявами.
size_in_bytesЗначення може бути отримано шляхом підсумовування записів в sys.dm_os_memory_objectsDMV (пункти зазначено вище жирним шрифтом), все пов'язані dm_os_memory_objects.page_allocator_addressдля цього Укладач плану. Підступ до отримання правильного значення полягає в тому, щоб спочатку отримати memory_object_addressз sys.dm_exec_cached_plansдля певного складеного плану, а потім скористатися цим, щоб отримати відповідний рядок MEMOBJ_COMPILE_ADHOCsys.dm_os_memory_objects на основі його memory_object_addressполя. Потім перейміть page_allocator_addressзначення sys.dm_os_memory_objectsдля цього рядка та використовуйте його, щоб схопити всі рядки з sys.dm_os_memory_objectsцього page_allocator_addressзначення. (Будь ласка , зверніть увагу , що цей метод не працює для інших кешованих типів об'єктів: дерево розбору , Extended Proc , CLR Укладач Proc і CLR Укладач Func.)
Використовуючи memory_object_addressзначення, отримане від sys.dm_exec_cached_plans, ви можете побачити всі компоненти складеного плану за допомогою наступного запиту:
DECLARE @CompiledPlanAddress VARBINARY(8) = 0x00000001DC4A4060;
SELECT obj.memory_object_address, obj.pages_in_bytes, obj.type
FROM sys.dm_os_memory_objects obj
WHERE obj.page_allocator_address = (
SELECT planobj.page_allocator_address
FROM sys.dm_os_memory_objects planobj
WHERE planobj.memory_object_address = @CompiledPlanAddress
)
ORDER BY obj.[type], obj.pages_in_bytes;
У запиті нижче перелічені всі складені плани sys.dm_exec_cached_plansразом із Планом запитів та висловлюваннями для кожної партії. Запит безпосередньо вище включено до запиту нижче через XML як MemoryObjectsполе:
SELECT cplan.bucketid,
cplan.pool_id,
cplan.refcounts,
cplan.usecounts,
cplan.size_in_bytes,
cplan.memory_object_address,
cplan.cacheobjtype,
cplan.objtype,
cplan.plan_handle,
'---' AS [---],
qrypln.[query_plan],
sqltxt.[text],
'---' AS [---],
planobj.pages_in_bytes,
planobj.pages_in_bytes / 1024 AS [BaseSingleStatementPlanKB],
'===' AS [===],
cplan.size_in_bytes AS [TotalPlanBytes],
bytes.AllocatedBytes,
(SELECT CONVERT(VARCHAR(30), obj.memory_object_address, 1)
AS [memory_object_address], obj.pages_in_bytes, obj.[type]
--,obj.page_size_in_bytes
FROM sys.dm_os_memory_objects obj
WHERE obj.page_allocator_address = planobj.page_allocator_address
FOR XML RAW(N'object'), ROOT(N'memory_objects'), TYPE) AS [MemoryObjects]
FROM sys.dm_exec_cached_plans cplan
OUTER APPLY sys.dm_exec_sql_text(cplan.[plan_handle]) sqltxt
OUTER APPLY sys.dm_exec_query_plan(cplan.[plan_handle]) qrypln
INNER JOIN sys.dm_os_memory_objects planobj
ON planobj.memory_object_address = cplan.memory_object_address
OUTER APPLY (SELECT SUM(domo.[pages_in_bytes]) AS [AllocatedBytes]
FROM sys.dm_os_memory_objects domo
WHERE domo.page_allocator_address = planobj.page_allocator_address) bytes
WHERE cplan.parent_plan_handle IS NULL
AND cplan.cacheobjtype IN (N'Compiled Plan', N'Compiled Plan Stub')
--AND cplan.plan_handle = 0x06000D0031CD572910529CE001000000xxxxxxxx
ORDER BY cplan.objtype, cplan.plan_handle;
Будь ласка, зверніть увагу, що:
TotalPlanBytesполе просто повторно заяву sys.dm_exec_cached_plans.size_in_bytesполя,
AllocatedBytesполе є сумою відповідних об'єктів пам'яті , які зазвичай матчів TotalPlanBytes(тобто size_in_bytes)
AllocatedBytesполе іноді буде більше TotalPlanBytes(тобто size_in_bytes) в зв'язку зі споживанням пам'яті збільшується під час виконання. Це, мабуть, трапляється здебільшого через рекомпіляцію (що має бути очевидним із usecountsполя, що показує 1)
BaseSingleStatementPlanKBполе повинно відповідати CachedPlanSizeатрибут QueryPlanвузла в XML, але тільки при використанні однієї партії запиту.
- для пакетів із декількома запитами повинні бути рядки, позначені як
MEMOBJ_STATEMENTв sys.dm_os_memory_objects, по одному для кожного запиту. pages_in_bytesПоле для цих рядків повинні відповідати окремим <QueryPlan>вузлам плану XML.
Ресурси: