Обратная связь по степени параллелизма (DOP feedback) теперь включена по умолчанию в SQL Server 2025 (Preview), Azure SQL Database, SQL Database в Microsoft Fabric и в политике Always-up-to-date для Azure SQL Managed Instance.
🚀 Введение
В SQL Server 2025 мы сделали DOP feedback включённым по умолчанию. Изначально появившаяся в SQL Server 2022, эта функция теперь является частью механизмов самооптимизации платформы, помогая нагрузкам масштабироваться эффективнее без ручной настройки. Работает при уровне совместимости базы данных 160 и выше.
⚙️ Что такое DOP feedback?
DOP feedback относится к семейству возможностей Intelligent Query Processing (IQP). Он динамически подстраивает количество потоков (DOP), используемых запросом, на основе показателей производительности во время выполнения — таких как время CPU и общее время исполнения. Если запрос, сгенерировавший параллельный план, систематически работает хуже из-за избыточного параллелизма, функция уменьшает DOP для будущих выполнений без перекомпиляции. На данный момент корректировка касается только уменьшения DOP для отдельных запросов. Для работы должен быть обязательно включён Query Store в режиме read write.
- Постоянность: данные сохраняются в Query Store. (На читаемых вторичных репликах пока не поддерживается).
- Адаптивность: система изменяет DOP, наблюдает за результатами и при ухудшении откатывает к предыдущему значению.
- Ограниченность: управление идёт через параметр
DOP_FEEDBACK
на уровне базы или через хинтDISABLE_DOP_FEEDBACK
в запросе.
🧪 Как это работает
- Первый запуск: SQL Server компилирует и выполняет запрос с текущим DOP.
- Мониторинг: собираются статистики выполнения и сравниваются между запусками.
- Корректировка: если найдена неэффективность, DOP снижается (минимум 2).
- Валидация: если производительность стабильно улучшается — новое значение сохраняется, если нет — откат к предыдущему.
SELECT
qspf.feature_desc,
qsq.query_id,
qsp.plan_id,
qspf.plan_feedback_id,
qsqt.query_sql_text,
qsp.query_plan,
qspf.state_desc,
qspf.feedback_data,
qspf.create_time,
qspf.last_updated_time
FROM sys.query_store_query AS qsq
INNER JOIN sys.query_store_plan AS qsp
ON qsp.query_id = qsq.query_id
INNER JOIN sys.query_store_query_text AS qsqt
ON qsqt.query_text_id = qsq.query_text_id
INNER JOIN sys.query_store_plan_feedback AS qspf
ON qspf.plan_id = qsp.plan_id
WHERE qspf.feature_id = 3;
🆕 Что нового в SQL Server 2025?
- Включено по умолчанию.
- Улучшена стабильность и логика валидации.
- Более тесная интеграция с другими функциями IQP (Memory Grant feedback, Cardinality Estimation feedback, PSP optimization).
- Устойчивость к рестартам и фейловерам (Query Store сохраняет данные).
🧩 Как понять, что DOP feedback полезен?
Если включён параллелизм и:
- MAXDOP = 0 или > 2;
- есть запросы с временем выполнения 10+ секунд при DOP ≥ 4;
- количество выполнений ≥ 15,
то стоит проверить Query Store. Пример запроса:
SELECT TOP 20
qsq.query_id, qsrs.plan_id,
[replica_type] =
CASE
WHEN replica_group_id = '1' THEN 'PRIMARY'
WHEN replica_group_id = '2' THEN 'SECONDARY'
WHEN replica_group_id = '3' THEN 'GEO SECONDARY'
WHEN replica_group_id = '4' THEN 'GEO HA SECONDARY'
ELSE TRY_CONVERT(NVARCHAR (200), qsrs.replica_group_id)
END,
AVG(qsrs.avg_dop) as dop,
SUM(qsrs.count_executions) as execution_count,
AVG(qsrs.avg_duration)/1000000.0 as duration_in_seconds,
MIN(qsrs.min_duration)/1000000.0 as min_duration_in_seconds
FROM sys.query_store_runtime_stats qsrs
INNER JOIN sys.query_store_plan qsp ON qsp.plan_id = qsrs.plan_id
INNER JOIN sys.query_store_query qsq ON qsq.query_id = qsp.query_id
GROUP BY qsrs.plan_id, qsq.query_id, qsrs.replica_group_id
ORDER BY dop desc, execution_count desc;
🧠 Внутренние механизмы
DOP feedback анализирует «скользящее окно» последних запусков (обычно 15), оценивая:
- среднее время CPU,
- стандартное отклонение времени CPU,
- скорректированное время выполнения,
- стабильность производительности.
🧭 Рекомендации
- Всегда включать Query Store.
- Использовать Extended Events для мониторинга.
IF EXISTS (SELECT *
FROM sys.server_event_sessions
WHERE name = 'dop_xevents')
DROP EVENT SESSION [dop_xevents] ON SERVER;
GO
CREATE EVENT SESSION [dop_xevents] ON SERVER
ADD EVENT sqlserver.dop_feedback_analysis_stopped,
ADD EVENT sqlserver.dop_feedback_eligible_query,
ADD EVENT sqlserver.dop_feedback_provided,
ADD EVENT sqlserver.dop_feedback_reassessment_failed,
ADD EVENT sqlserver.dop_feedback_reverted,
ADD EVENT sqlserver.dop_feedback_stabilized
-- ADD EVENT sqlserver.dop_feedback_validation,
-- ADD EVENT sqlserver.maxdop_feedback_received
WITH (
MAX_MEMORY = 4096 KB,
EVENT_RETENTION_MODE = ALLOW_SINGLE_EVENT_LOSS,
MAX_DISPATCH_LATENCY = 30 SECONDS,
MAX_EVENT_SIZE = 0 KB,
MEMORY_PARTITION_MODE = NONE,
TRACK_CAUSALITY = OFF,
STARTUP_STATE = OFF
);
🔍 Структура JSON feedback_data
Пример:
{
"LastGoodFeedback": {
"dop": "2",
"avg_cpu_time_ms": "12401",
"avg_adj_elapsed_time_ms": "12056",
"std_cpu_time_ms": "380",
"std_adj_elapsed_time_ms": "342"
},
"BaselineStats": {
"dop": "4",
"avg_cpu_time_ms": "17843",
"avg_adj_elapsed_time_ms": "13468",
"std_cpu_time_ms": "333",
"std_adj_elapsed_time_ms": "328"
}
}
Для извлечения метрик можно использовать JSON_VALUE
:
SELECT
qspf.plan_id,
qs.query_id,
qt.query_sql_text,
qsp.query_plan_hash,
qspf.feature_desc,
JSON_VALUE(qspf.feedback_data, '$.LastGoodFeedback.dop') AS last_good_dop,
JSON_VALUE(qspf.feedback_data, '$.LastGoodFeedback.avg_cpu_time_ms') AS last_good_avg_cpu_time_ms,
JSON_VALUE(qspf.feedback_data, '$.LastGoodFeedback.avg_adj_elapsed_time_ms') AS last_good_avg_adj_elapsed_time_ms,
JSON_VALUE(qspf.feedback_data, '$.LastGoodFeedback.std_cpu_time_ms') AS last_good_std_cpu_time_ms,
JSON_VALUE(qspf.feedback_data, '$.LastGoodFeedback.std_adj_elapsed_time_ms') AS last_good_std_adj_elapsed_time_ms,
JSON_VALUE(qspf.feedback_data, '$.BaselineStats.dop') AS baseline_dop,
JSON_VALUE(qspf.feedback_data, '$.BaselineStats.avg_cpu_time_ms') AS baseline_avg_cpu_time_ms,
JSON_VALUE(qspf.feedback_data, '$.BaselineStats.avg_adj_elapsed_time_ms') AS baseline_avg_adj_elapsed_time_ms,
JSON_VALUE(qspf.feedback_data, '$.BaselineStats.std_cpu_time_ms') AS baseline_std_cpu_time_ms,
JSON_VALUE(qspf.feedback_data, '$.BaselineStats.std_adj_elapsed_time_ms') AS baseline_std_adj_elapsed_time_ms
FROM sys.query_store_plan_feedback AS qspf
JOIN sys.query_store_plan AS qsp
ON qspf.plan_id = qsp.plan_id
JOIN sys.query_store_query AS qs
ON qsp.query_id = qs.query_id
JOIN sys.query_store_query_text AS qt
ON qs.query_text_id = qt.query_text_id
WHERE qspf.feature_desc = 'DOP Feedback'
AND ISJSON(qspf.feedback_data) = 1;
🧪 Почему это важно
Эти данные помогают:
- анализировать регрессии (сравнение baseline и feedback),
- строить телеметрию и отчёты,
- обеспечить прозрачную адаптацию SQL Server к нагрузке.
Комментариев нет:
Отправить комментарий