24.8.25

Умный параллелизм: обратная связь по степени параллелизма (DOP) в SQL Server 2025

Автор: theSQLSith. Smarter Parallelism: Degree of parallelism feedback in SQL Server 2025

Обратная связь по степени параллелизма (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 в запросе.

🧪 Как это работает

  1. Первый запуск: SQL Server компилирует и выполняет запрос с текущим DOP.
  2. Мониторинг: собираются статистики выполнения и сравниваются между запусками.
  3. Корректировка: если найдена неэффективность, DOP снижается (минимум 2).
  4. Валидация: если производительность стабильно улучшается — новое значение сохраняется, если нет — откат к предыдущему.

Пример запроса для анализа результатов:


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 к нагрузке.

Комментариев нет:

Отправить комментарий