Ніколи не закінчується пошук у магазині запитів


10

Скажу відразу , що моє запитання / проблема виглядає схожа на цю попередній, але так як я не впевнений , якщо причина або початкова інформація є таким же, я вирішив розмістити своє питання ще з деякими деталями.

Випуск під рукою:

  • в чужу годину (наприкінці робочого дня) виробничий екземпляр починає поводитися нерівномірно:
    • високий процесор для екземпляра (від базової лінії ~ 30% він збільшився приблизно вдвічі і все ще зростає)
    • збільшена кількість транзакцій в секунду (хоча завантаження програми не побачило жодних змін)
    • збільшена кількість непрацюючих сеансів
    • дивні події блокування між сеансами, які ніколи не відображали такої поведінки (навіть читання невмілих сесій викликало блокування)
    • Топ інтервалу, який чекав інтервалу, був засувкою без сторінки на 1-му місці, а замки посіли 2 місце

Початкове розслідування:

  • використовуючи sp_whoIsActive, ми побачили, що запит, виконаний нашим інструментом моніторингу, вирішує запускати надзвичайно повільно і захоплювати багато процесора, чого раніше не було;
  • рівень його ізоляції був прочитаний без підтвердження;
  • ми подивилися на план, який ми побачили нерозумні цифри: StatementEstRows = "3.86846e + 010" з приблизно 150 ТБ передбачуваних даних, які потрібно повернути
  • ми підозрювали, що причина монітора запитів була причиною, тому ми відключили цю функцію (ми також відкрили квиток у нашого постачальника, щоб перевірити, чи знають вони про будь-яку проблему)
  • від тієї першої події це сталося ще кілька разів, і кожен раз, коли ми вбиваємо сеанс, все приходить у норму;
  • ми розуміємо, що запит надзвичайно схожий на один із запитів, використовуваних MS в BOL для моніторингу магазину запитів - запити, які нещодавно регресували у виконанні (порівнюючи різні моменти часу)
  • ми запускаємо один і той же запит вручну і спостерігаємо однакову поведінку (CPU використовується постійно зростаючим, збільшуючи очікування засувок, несподівані блокування .. тощо)

Запит провини:

Select qt.query_sql_text, 
    q.query_id, 
    qt.query_text_id, 
    rs1.runtime_stats_id AS runtime_stats_id_1,
    interval_1 = DateAdd(minute, -(DateDiff(minute, getdate(), getutcdate())), rsi1.start_time), 
    p1.plan_id AS plan_1, 
    rs1.avg_duration AS avg_duration_1, 
    rs2.avg_duration AS avg_duration_2,
    p2.plan_id AS plan_2, 
    interval_2 = DateAdd(minute, -(DateDiff(minute, getdate(), getutcdate())), rsi2.start_time), 
    rs2.runtime_stats_id AS runtime_stats_id_2
From sys.query_store_query_text AS qt 
Inner Join sys.query_store_query AS q 
    ON qt.query_text_id = q.query_text_id 
Inner Join sys.query_store_plan AS p1 
    ON q.query_id = p1.query_id 
Inner Join sys.query_store_runtime_stats AS rs1 
    ON p1.plan_id = rs1.plan_id 
Inner Join sys.query_store_runtime_stats_interval AS rsi1 
    ON rsi1.runtime_stats_interval_id = rs1.runtime_stats_interval_id 
 Inner Join sys.query_store_plan AS p2 
    ON q.query_id = p2.query_id 
Inner Join sys.query_store_runtime_stats AS rs2 
    ON p2.plan_id = rs2.plan_id 
Inner Join sys.query_store_runtime_stats_interval AS rsi2 
    ON rsi2.runtime_stats_interval_id = rs2.runtime_stats_interval_id
Where rsi1.start_time > DATEADD(hour, -48, GETUTCDATE()) 
    AND rsi2.start_time > rsi1.start_time 
    AND p1.plan_id <> p2.plan_id
    AND rs2.avg_duration > rs1.avg_duration * 2
Order By q.query_id, rsi1.start_time, rsi2.start_time

Налаштування та інформація:

  • SQL Server 2016 SP1 CU4 Enterprise на кластері Windows Server 2012R2
  • Магазин запитів увімкнено та налаштовано за замовчуванням (налаштування не змінено)
  • база даних, імпортована з екземпляра SQL 2005 (і все ще на рівні сумісності 100)

Емпіричне спостереження:

  • завдяки надзвичайно дурній статистиці ми взяли всі * plan_persist ** об’єкти, які використовуються в поганому оціночному плані (фактичного плану ще немає, тому що запит так і не завершився) та перевірили статистику, деякі з індексів, використаних у плані, не мали жодної статистики (DBCC SHOWSTATISTICS не повернув нічого, виберіть із sys.stats показав функцію NULL stats_date () для деяких індексів

Швидке і брудне рішення:

  • вручну створити відсутні статистичні дані щодо системних об'єктів, пов’язаних із магазином запитів або
  • змусити запуск запиту використовувати новий CE (traceflag) - який також створить / оновить необхідні статистичні дані або
  • змінити рівень сумісності бази даних на 130 (так він за замовчуванням використовує новий CE)

Отже, моє справжнє питання було б:

Чому запит у магазині запитів може спричинити проблеми з роботою у всьому екземплярі? Ми знаходимося на території помилок із магазином запитів?

PS: За короткий час я завантажу декілька файлів (екрани друку, IO статистика та плани).

Файли додані на Dropbox .

План 1 - початковий нерозумний кошторисний план у виробництві

План 2 - фактичний план, старий СЕ, в тестовій середовищі (та ж поведінка, ті ж дурні статистики)

План 3 - фактичний план, новий CE, в тестовій середовищі


1
Ми вимкнули магазин запитів, ми впевнені, що було першопричиною (у нас було більше 1 проблеми напевно). З моєї сторони, процесор розширював би все, що ми натиснули, щоб відобразити статистику із магазину запитів.
A_V

Відповіді:


6

Як я вже говорив у відповіді, емпіричний тест показав, що на системних об'єктах sys.plan_persisted * були індекси без будь-якої (жодної) статистики, створеної над ними. Я підозрюю, що це тому, що база даних мігрується з екземпляра SQL 2005 і деякий час зберігається на рівні сумісності 100, тому новий CE не використовувався.

Перевірка підрахунків рядків:

Select count(1) from NoNameDB.sys.plan_persist_runtime_stats with (nolock) --60362   
Select count(1) from NoNameDB.sys.plan_persist_plan with (nolock) --1853    
Select count(1) from NoNameDB.sys.plan_persist_runtime_stats_interval with (nolock) --671    
Select count(1) from NoNameDB.sys.plan_persist_query with (nolock) --1091    
Select count(1) from NoNameDB.sys.plan_persist_query_text with (nolock) --911

Це показало, що початкові оцінки були помилковими. Зроблено з'єднання DAC, інакше таблиці недоступні для запиту.

Перевірка статистики:

DBCC SHOW_STATISTICS ('sys.plan_persist_runtime_stats_interval', plan_persist_runtime_stats_interval_cidx);    
DBCC SHOW_STATISTICS ('sys.plan_persist_runtime_stats', plan_persist_runtime_stats_idx1);    
DBCC SHOW_STATISTICS ('sys.plan_persist_runtime_stats', plan_persist_runtime_stats_cidx);    
DBCC SHOW_STATISTICS ('sys.plan_persist_plan', plan_persist_plan_cidx);    
DBCC SHOW_STATISTICS ('sys.plan_persist_plan', plan_persist_plan_idx1);    
DBCC SHOW_STATISTICS ('sys.plan_persist_query', plan_persist_query_cidx)    
DBCC SHOW_STATISTICS ('sys.plan_persist_query_text', plan_persist_query_text_cidx);

Це показало, що деякі індекси мали порожні статистичні дані (відсутні, жодні, нульові).

Початкове виправлення:

UPDATE STATISTICS sys.plan_persist_runtime_stats WITH fullscan;
UPDATE STATISTICS sys.plan_persist_plan WITH fullscan;
UPDATE STATISTICS sys.plan_persist_runtime_stats_interval WITH fullscan;
UPDATE STATISTICS sys.plan_persist_query WITH fullscan;
UPDATE STATISTICS sys.plan_persist_query_text WITH fullscan;

Цей вид виправив статистику і змусив завершити запит за 10-12 секунд.

Друге виправлення :

(перевірено лише на тестовому середовищі) і, швидше за все, належним, оскільки він показав найкращу статистику для запиту, було зміна рівня сумісності бази даних до 130. Кінцевим результатом було те, що запит закінчився приблизно за 10-12 секунд статистика звичайних цифр (10 к рядків).

Проміжне виправлення :

DBCC TRACEON (2312) -- new CE

Деякі пов'язані довідки щодо статистики в прихованих таблицях системи.


3

Основна проблема, яка видно, якщо ви відкриєте фактичний план у SSMS та дивитесь на використання процесора (або вивчаєте XML), - це вузол 32, TVF. Винуватець у повільних запитах у магазині запитів - це неодноразовий доступ до ТВФ в пам'яті .

Вартість TVF

Не має значення, скільки рядків повертається з цих телевізійних каналів, лише скільки разів до них звертаються. Виправити буде все, що ви можете зробити, щоб відштовхувати свої плани від їх читання кілька разів.

Виходячи з моєї обмеженої налагодження (як на навички, так і на витрачений час), моя гіпотеза полягає в тому, що вся сукупність пам'яті, призначеної для конкретного компонента пам'яті даних Query Store, сканується при кожному виконанні TVF. Я не був в змозі впливати на цей розподіл пам'яті або sp_query_store_flush_dbабо DBCC FREESYSTEMCACHE.

Поки що успішні обхідні шляхи включають довідники щодо плану, підказки (до цього OPTION(HASH JOIN, LOOP JOIN)часу я працював досить добре для мене) та виконання запитів у магазині запитів на вузлі, що доступний лише для читання.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.