SQL Server 2025 встал на THREADPOOL, а Always On у вас нет: виновата persisted statistics и лечится флагом 15608
Статья для сисадминов и DBA, у которых на одном инстансе SQL Server 2025 живёт не одна база, а два-три десятка и больше: хостинг клиентских баз 1С, консолидированный сервер холдинга, стенд с копиями продакшена. Разберу, почему после ребута такой инстанс может встать намертво с ожиданиями THREADPOOL при простаивающем процессоре, почему причина лежит в функции для читаемых вторичных реплик, которых у вас нет и никогда не было, как отличить это от обычных блокировок за пять минут и как лечится — с точными шагами, запросами и разбором реального выезда.
Инстанс лёг после планового ребута — и это не диск, не память и не 1С
Звонок в 07:12 в понедельник: «Никто не может зайти в 1С, база не отвечает». Клиент — условный агрохолдинг «Поле Подмосковья», 49 рабочих мест: управляющая компания и несколько хозяйств, у каждого своё юрлицо. Один сервер под СУБД, на нём один инстанс SQL Server 2025 (17.x) и 58 баз данных: девять боевых баз 1С (бухгалтерии хозяйств, ЗУП, учёт техники и урожая), копии для разработки, архивы по годам за каждое юрлицо, пара служебных БД под обмены. Ночью отработало обновление Windows, сервер ушёл в перезагрузку и поднялся. Служба SQL Server в состоянии Running, порт 1433 слушается, telnet проходит. А подключения падают по таймауту.
Первое, что я смотрю в такой ситуации, — железо. CPU 4 %, очередь к дискам нулевая, свободной памяти достаточно, tempdb на месте, лог ошибок не забит сообщениями об I/O. То есть все ресурсы простаивают, а сервер при этом мёртвый. Вот это сочетание — «всё зелёное, но никто не может войти» — почти всегда означает одно: кончились рабочие потоки. Не память, не диск, не процессор. Потоки.
Дальше — заход по выделенному административному соединению (DAC), потому что обычным способом уже не пустит: на новый логин тоже нужен worker. И первый же запрос показал сплошной THREADPOOL в ожиданиях. Что дальше делают девять админов из десяти? Правильно — начинают искать «зависший запрос», который держит потоки, а потом от отчаяния поднимают max worker threads. Я тоже так делал, пока не разобрался, откуда взялись 58 лишних потоков, которые заняты вечно.
И вот в чём ловушка этого конкретного случая: у «Поля Подмосковья» нет Always On. Совсем. Ни одной группы доступности, ни одной вторичной реплики, ни одной строчки про readable secondary в конфигурации. А причина отказа — фоновый поток от функции persisted statistics for readable secondary replicas, включённой в SQL Server 2025 по умолчанию. Именно эту связку не видит никто, потому что мозг отказывается связывать «реплик нет» и «сломалось из-за реплик».
- служба SQL Server работает, порт слушается, но новые подключения отваливаются по таймауту
- CPU, диск и память практически не нагружены — все ресурсы простаивают
- в sys.dm_os_waiting_tasks преобладает wait_type THREADPOOL
- в ERRORLOG может появиться сообщение вида «New queries assigned to process on Node 0 have not been picked up by a worker thread in the last 60 seconds» (ошибка 17884) — но его отсутствие ничего не опровергает
- симптом проявляется после старта инстанса или после массового приведения баз в online (восстановление пачки БД, вывод из offline, attach)
Арифметика рабочих потоков: почему 58 баз способны положить 8-ядерный сервер
Напомню механику, потому что без неё дальше ничего не понятно. SQL Server не заводит по потоку ОС на каждый запрос. Он держит пул рабочих потоков (workers) и раздаёт их активным задачам: запрос отработал — worker вернулся в пул. Размер пула задаёт параметр max worker threads, и по умолчанию он равен 0, то есть считается автоматически при старте по формуле «Default Max Workers + ((логических CPU − 4) × Workers per CPU».
Для 64-разрядной системы это выглядит так: до 4 логических процессоров включительно — 512 потоков; 8 CPU — 576; 16 CPU — 704; 32 CPU — 960; 64 CPU — 1472. Для машин больше 64 логических процессоров множитель другой (32 вместо 16), поэтому 128 CPU дают 4480, а 256 — 8576. У «Поля Подмосковья» 8 vCPU, значит потолок 576 потоков. Цифра кажется огромной, пока вы не начнёте вычитать.
Теперь ключевой факт из документации Microsoft: функция persisted statistics for readable secondary replicas создаёт фоновый рабочий поток на каждую базу данных, и создаётся он в момент, когда база приходит в состояние online. Не когда её кто-то открыл, не когда пришёл запрос — просто при выводе в online. 58 баз — 58 потоков, занятых постоянно, пока базы в online. Microsoft прямо пишет, что это создаёт давление на пул рабочих потоков и снижает отзывчивость инстанса даже тогда, когда вторичные реплики не настроены вообще.
Сами по себе 58 потоков из 576 — это 10 %, вроде бы не смертельно. Но потоки не резиновые, и вычитать надо не только их. Утром сервер 1С поднимает пулы соединений, пользователи логинятся волной, регламентные задания стартуют по расписанию, бэкапы догоняют пропущенное окно, плюс системные потоки (LazyWriter, Checkpoint, Log Writer, Service Broker, менеджер блокировок) живут вне лимита max worker threads и всё равно едят ресурсы ОС. Достаточно любого узкого места — медленного диска, длинной блокировки, задержки в сети — и очередь задач за потоками растёт лавиной. Постоянно занятые 58 потоков в этой лавине оказываются той самой соломинкой.
Честно скажу то, чего нет в документации: Microsoft не называет порога, с какого числа баз проблема гарантированно проявляется. Всё зависит от количества логических процессоров, от профиля нагрузки и от того, сколько потоков у вас в норме занято. На восьмиядерной машине с 576 потоками и сотней баз вы поймаете это почти сразу. На 32 ядрах с двадцатью базами — можете не поймать никогда. Проверяйте по фактическим цифрам, а не по ощущению «у нас баз немного».
- ≤ 4 логических CPU — 512 рабочих потоков
- 8 CPU — 576
- 16 CPU — 704
- 32 CPU — 960
- 64 CPU — 1472
- 128 CPU — 4480, 256 CPU — 8576 (для > 64 CPU множитель 32 вместо 16)
Persisted statistics for readable secondary replicas — фича, которую вы не включали
Разберёмся, что это вообще за функция, потому что дальше придётся принимать решение «выключать или нет». До SQL Server 2025 на читаемой вторичной реплике статистика вела себя так: база доступна только на чтение, обновлять постоянную статистику там нельзя, поэтому движок создавал временную статистику в tempdb с суффиксом _readonly_database_statistic в имени. Временную — значит умирающую при рестарте инстанса. После каждого перезапуска реплика заново собирала статистику для своих отчётных запросов, и первые прогоны отчётов были заметно медленнее.
В 2025-й это чинят красиво: временная статистика, созданная на вторичной реплике, отправляется на первичную и сохраняется там как постоянная, а оттуда штатным механизмом синхронизации разъезжается по всем репликам группы доступности. Механизм построен на инфраструктуре Query Store for readable secondary replicas, которая в SQL Server 2025 и Azure SQL Database включена по умолчанию. Для наблюдения добавлены расширенное событие persisted_stats_operation и три новые колонки в представлении sys.stats: replica_role_id, replica_role_desc и replica_name. Идея отличная, реализация — с той самой миной.
Мина в двух словах: функция включена по умолчанию, если включены auto create statistics и параметры конфигурации уровня БД READABLE_SECONDARY_TEMPORARY_STATS_AUTO_CREATE и READABLE_SECONDARY_TEMPORARY_STATS_AUTO_UPDATE. Это дефолт для любой новой базы. И — цитирую документацию — отдельной database scoped configuration, чтобы выключить саму функцию персиста, не предусмотрено. То есть штатного рубильника «мне это не нужно, я без Always On» нет. Фоновый поток на базу создаётся при выводе её в online безусловно.
Посмотреть, что творится со статистикой на конкретной базе, можно вот так — этот запрос я держу в закладках, он показывает и происхождение статистики, и признак временной:
SELECT sch.[name] AS SchemaName,
obj.[name] AS TableName,
s.[name] AS StatsName,
s.is_temporary,
s.replica_role_id,
s.replica_role_desc,
s.replica_name
FROM sys.schemas AS sch
INNER JOIN sys.objects AS obj ON sch.schema_id = obj.schema_id
INNER JOIN sys.stats AS s ON obj.object_id = s.object_id
WHERE sch.[name] <> 'sys'
ORDER BY sch.[name], obj.[name], s.stats_id;Если в ERRORLOG вам попадаются ошибки 9131, 9136, 9137 или 9139 — это тоже про неё: «функция отключена при старте», «таблица или индекс изменены/удалены», «схема изменилась с момента снимка, повтор» и «статистика слишком велика для отправки на первичную реплику» соответственно. На инстансе без групп доступности вы этих ошибок обычно не увидите — фоновый поток просто молча существует и молча держит worker.
- функция появилась в SQL Server 2025 (17.x) и в Azure SQL Database
- работает поверх Query Store for readable secondary replicas, который тоже включён по умолчанию
- нет database scoped configuration для отключения самой персистенции статистики
- новые колонки sys.stats: replica_role_id, replica_role_desc, replica_name
- расширенное событие persisted_stats_operation (канал Operational) со стадиями enqueued / dequeued / processed / failed
Диагностика за пять минут: как отличить это от банальной блокировки
Когда инстанс не пускает, обычным клиентом вы уже не зайдёте — на логин тоже нужен рабочий поток. Поэтому первым делом DAC. SQL Server резервирует под него ограниченные ресурсы, и такое подключение на инстанс допускается только одно (второе получит ошибку 17810); войти может только член роли sysadmin. Из командной строки это sqlcmd -S ИМЯ_СЕРВЕРА -A -E -d master, из SSMS — закрыть Object Explorer и все окна запросов к этому инстансу, затем File → New → Database Engine Query и admin:ИМЯ_СЕРВЕРА в поле сервера. По умолчанию DAC принимает подключения только локально с самого сервера; для входа по сети нужен параметр remote admin connections. Поэтому я включаю его на всех продакшен-инстансах заранее — это одна строчка в sp_configure, и перезапуск не нужен.
Дальше три запроса. Первый показывает, есть ли очередь за рабочими потоками: смотрим work_queue_count — это задачи, которые уже ждут свободного worker'а, а не процессорного времени. Второй считает, сколько потоков реально занято, и сравнивает с настроенным лимитом. Третий показывает ожидания.
-- 1. Очередь за рабочими потоками по планировщикам
SELECT scheduler_id, current_tasks_count, runnable_tasks_count,
current_workers_count, active_workers_count, work_queue_count
FROM sys.dm_os_schedulers
WHERE status = 'VISIBLE ONLINE';
-- 2. Занято потоков против лимита
SELECT SUM(active_workers_count) AS active_workers,
(SELECT CAST(value_in_use AS int)
FROM sys.configurations
WHERE name = 'max worker threads') AS max_worker_threads_setting
FROM sys.dm_os_schedulers
WHERE status = 'VISIBLE ONLINE';
-- 3. Кто чего ждёт
SELECT wait_type, COUNT(*) AS tasks, SUM(wait_duration_ms) AS total_wait_ms
FROM sys.dm_os_waiting_tasks
GROUP BY wait_type
ORDER BY total_wait_ms DESC;Мгновенный срез из sys.dm_os_waiting_tasks показывает, что происходит прямо сейчас; накопленную картину с момента старта даёт sys.dm_os_wait_stats. Если THREADPOOL там стабильно в верхних строках, а max_wait_time_ms измеряется секундами — это не разовый всплеск. Счётчики обнуляются при рестарте, поэтому после перезагрузки сравнивайте с тем, что было до неё, а в мониторинге снимайте дельту.
SELECT wait_type, waiting_tasks_count, wait_time_ms, max_wait_time_ms, signal_wait_time_ms
FROM sys.dm_os_wait_stats
WHERE wait_type IN ('THREADPOOL', 'CXPACKET', 'CXCONSUMER')
OR wait_type LIKE 'LCK_M_%'
ORDER BY wait_time_ms DESC;Как читать результат. Если work_queue_count держится выше нуля на нескольких планировщиках и в ожиданиях лидирует THREADPOOL — потоки кончились, диагноз поставлен. Если же в ожиданиях преобладают LCK_M_*, а в sys.dm_exec_requests у сессий заполнен blocking_session_id и выстраивается цепочка — это классическая блокировка, и тема статьи тут ни при чём: ищите головного блокировщика и разбирайтесь с ним. Разница принципиальная: при блокировке потоков хватает, они просто заняты ожиданием; при THREADPOOL задачам не достаётся даже потока, чтобы начать ждать.
Третий частый виновник, которого путают с дефектом, — параллелизм. Параллельный запрос занимает не один worker, а несколько: по потоку на каждый параллельный поток выполнения в каждой зоне плана. Когда при max degree of parallelism = 0 и низком cost threshold for parallelism утром одновременно стартуют тяжёлые отчёты 1С, два-три десятка параллельных запросов способны выбрать сотни потоков, а если они ещё и стоят в блокировке — держат их долго. Признаки — много ожиданий CXPACKET/CXCONSUMER и сессии, у которых в sys.dm_os_tasks по многу строк с разными exec_context_id. Лечится это настройкой MAXDOP и порога стоимости, а не трейс-флагом; и наоборот, флаг 15608 не поможет, если потоки съел параллелизм.
Отдельно проверьте гипотезу «это фоновые потоки от persisted statistics». Косвенный, но очень надёжный признак: количество баз в online примерно совпадает с необъяснимым постоянным остатком занятых worker'ов, который не уменьшается ночью, в выходные, при нулевой пользовательской активности. Ещё один признак — проблема воспроизводится строго после старта инстанса или после массового вывода баз в online и не воспроизводится, если поднять инстанс с частью баз в offline. Служебные потоки посмотреть можно запросом из документации по max worker threads, там связка sys.dm_exec_sessions → sys.dm_os_tasks → sys.dm_os_workers с фильтром is_user_process = 0.
- вход только по DAC: `sqlcmd -S SERVER -A -E -d master` или `admin:SERVER` в новом окне запроса SSMS
- THREADPOOL + ненулевой work_queue_count = потоки кончились
- LCK_M_* + заполненный blocking_session_id = обычная блокировка, лечится иначе
- CXPACKET/CXCONSUMER + много exec_context_id на сессию = потоки съедает параллелизм, настраивайте MAXDOP и cost threshold for parallelism
- постоянный «фоновый» остаток занятых worker'ов, равный числу баз в online, — прямое указание на нашу проблему
- проверка от обратного: поднять инстанс с частью баз в offline и сравнить цифры
Лечение: trace flag 15608 в параметрах запуска, и только там
Документированное Microsoft временное решение — трейс-флаг 15608, включённый именно как стартовый, с последующим перезапуском SQL Server. В официальном списке trace flags он описан так: отключает функцию Persisted statistics for readable secondary replicas, применяется к SQL Server 2025 (17.x) и новее, область действия — Startup only. Формулировка в разделе known issues тоже однозначная: флаг обязан быть включён при старте, и включение его после запуска не останавливает фоновые потоки, уже созданные для баз, которые успели прийти в online. Это ровно та деталь, на которой люди теряют время: пытаются сделать DBCC TRACEON (15608, -1) на живом инстансе, не видят эффекта и решают, что рекомендация не работает. Работает. Просто она не про DBCC — для флага со scope «Startup only» путь один: параметр запуска -T15608.
На Windows правильный путь — SQL Server Configuration Manager: свойства службы SQL Server, вкладка Startup Parameters, добавить -T15608, нажать Add, применить, перезапустить службу. Не редактируйте параметры через SSMS Startup Parameters вслепую и не дописывайте флаг в чужую строку — каждый параметр отдельной строкой. Если правите реестром (например, из скрипта развёртывания), нужный раздел выглядит так; имя ключа зависит от версии и имени инстанса, для SQL Server 2025 с инстансом по умолчанию это MSSQL17.MSSQLSERVER:
$key = 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL17.MSSQLSERVER\MSSQLServer\Parameters'
Get-ItemProperty -Path $key # смотрим, какие SQLArgN уже есть
New-ItemProperty -Path $key -Name 'SQLArg3' -Value '-T15608' -PropertyType String
Restart-Service -Name 'MSSQLSERVER' -ForceНа Linux то же самое делается штатной утилитой конфигурации, без правки файлов руками:
sudo /opt/mssql/bin/mssql-conf traceflag 15608 on
sudo systemctl restart mssql-serverПосле перезапуска обязательно проверьте, что флаг реально подхватился. Два способа: запрос DBCC TRACESTATUS(15608, -1); должен показать флаг включённым (Status = 1); и в ERRORLOG в самом начале лога будет блок «Registry startup parameters» со всеми -T. Я всегда смотрю именно ERRORLOG — он показывает, что флаг был на старте, а не появился потом. И только после этого можно считать, что фоновые потоки на базы больше не создаются.
Теперь неприятная честность про сроки. По состоянию на редакцию статьи Microsoft от 24 августа 2026 года в разделе известных проблем SQL Server 2025 написано, что исправление «определено для будущего выпуска» — то есть постоянного фикса ещё нет. Последний накопительный пакет на тот момент — CU8 (KB5104822, сборка 17.0.4075.5) от 13 августа 2026 года, он вышел раньше даты правки статьи, значит проблема в нём не закрыта. 8 сентября 2026 года вышло обновление безопасности CU8 + GDR (KB5122769, сборка 17.0.4085.5) — GDR-пакеты несут исправления безопасности, так что рассчитывать на него как на фикс не стоит, но known issues после каждого выпуска я перечитываю. Флаг придётся держать и проверять список known issues и readme каждого нового CU перед тем, как его снимать. Это не «поставил и забыл», это отложенный технический долг.
- Windows: Configuration Manager → свойства службы → Startup Parameters → `-T15608` → Add → перезапуск службы
- Linux: `mssql-conf traceflag 15608 on` + `systemctl restart mssql-server`
- проверка: `DBCC TRACESTATUS(15608, -1)` → Status 1
- контроль по ERRORLOG: блок «Registry startup parameters» на старте инстанса
- флаг имеет scope «Startup only»: `DBCC TRACEON` на живом инстансе проблему НЕ решает
Чем кончилось у «Поля Подмосковья»: 40 минут простоя и два решения вместо одного
Возвращаюсь к утру понедельника. Хронология была такая. 07:12 — звонок. 07:20 — заход по DAC, диагноз: 58 баз в online, из 576 рабочих потоков стабильно занято около 565, work_queue_count растёт, THREADPOOL с суммарным ожиданием в десятки секунд на задачу. Сервер: Windows Server 2022, 8 vCPU, 64 ГБ RAM, SQL Server 2025 Standard уровня CU6 (17.0.4055.5), max worker threads = 0 по умолчанию.
Дальше я сделал две разные вещи, и это важно разделять. Первое — аварийное действие, чтобы дать людям работать прямо сейчас: через DAC поднял max worker threads до 1200. Это применяется командой RECONFIGURE немедленно, без перезапуска движка, что в разгар рабочего дня решает всё. Инстанс задышал через полторы минуты, пользователи вошли, простой составил около 40 минут с момента звонка.
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'max worker threads', 1200;
RECONFIGURE;Второе — настоящее лечение вечером того же дня, в согласованное окно: -T15608 в параметры запуска, перезапуск службы, проверка DBCC TRACESTATUS, и обратно max worker threads = 0. После рестарта с флагом суммарное active_workers_count на холостом ходу упало примерно с 565 до 110, THREADPOOL из ожиданий исчез полностью, логины стали проходить мгновенно. Заодно я вывел в offline 9 архивных баз хозяйств, которые последний раз открывали в позапрошлом году, и перевёз четыре тестовые копии на отдельный инстанс — это уже не про флаг, это про гигиену.
Почему я не оставил задранный max worker threads как постоянное решение? Потому что это маскировка, а не лечение. Microsoft прямо предупреждает: если вам кажется, что проблема в доступности рабочих потоков, скорее всего дело в том, что́ эти потоки занимает, и сначала надо найти корневую причину. Каждый рабочий поток — это стек в памяти (на x64 порядка 2 МБ), 1200 потоков вместо 576 съедают заметный кусок RAM мимо буферного пула, и вы просто отодвигаете стену на пару шагов. Постоянно держать вручную завышенный лимит — значит договориться, что у вас всегда будет то же самое, только позже и внезапнее.
- аварийно (можно днём, без рестарта): `sp_configure 'max worker threads'` + `RECONFIGURE`
- по-настоящему (в окно, с рестартом): стартовый `-T15608`, затем вернуть `max worker threads` в 0
- результат на стенде: занятых worker'ов на холостом ходу ~565 → ~110, THREADPOOL ушёл
- дополнительно: архивные базы в offline, тестовые копии — на отдельный инстанс
Мои приоритеты: что делать до того, как поймали, и на что можно забить
Первое и главное. Если вы разворачиваете SQL Server 2025 и на инстансе будет больше двух-трёх десятков баз — ставьте -T15608 сразу, на этапе установки, вместе с остальными стартовыми параметрами и настройкой tempdb. Это дешевле любой диагностики постфактум. У меня это уже пункт чек-листа ввода инстанса в эксплуатацию, наравне с включением DAC, настройкой max server memory и Instant File Initialization. Никакого риска для инстанса без групп доступности в этом нет.
Второе. Если у вас Always On с читаемыми вторичными репликами и вы реально гоняете отчётность на secondary — тут решение не такое очевидное, и я не буду делать вид, что оно очевидное. Персист статистики со вторичных реплик даёт вам стабильные планы после перезапусков, ради этого фичу и сделали. Мой практический подход: сначала измерить, а не выключать наотмашь. Посчитайте базы в группе доступности, посчитайте пул потоков по формуле, посмотрите фактическое active_workers_count в спокойный час. Если запас двукратный — живите с фичей и мониторьте THREADPOOL. Если запас тает — флаг, и без сантиментов: неотзывчивый инстанс дороже хорошей статистики.
Третье, про обновления. Следите за списком известных проблем SQL Server 2025 перед каждым накопительным пакетом — там же и живёт формулировка про будущее исправление. Как только фикс появится в CU, флаг можно будет снять, но снимать надо тоже с перезапуском и с проверкой по ERRORLOG. И заведите себе привычку читать known issues целиком перед внедрением: помимо нашей темы, там сейчас лежат и падение установки при отключённом TLS 1.2, и отказ старта на машинах с более чем 64 логическими ядрами на NUMA-узел, и проблема с SESSION_CONTEXT в параллельных планах, и access violation на Windows Server 2025 с включённым Lock Pages in Memory. Половина из этого способна испортить вам выходные ровно так же.
Теперь на что можно спокойно забить. Не надо перекраивать affinity mask и раскладывать планировщики руками — к этой проблеме это не имеет отношения. Не надо искать причину в 1С, в драйверах, в антивирусе и в сетевой карте: симптом полностью объясняется арифметикой потоков. Не надо срочно мигрировать на SQL Server 2022 — 2025-я платформа рабочая, у неё просто есть известный дефект с документированным обходом. И не надо паниковать, если у вас на инстансе пять баз и 32 ядра: при таком соотношении вы этого не увидите никогда, а флаг можно поставить просто «на всякий случай», вреда не будет.
И последнее, менее техническое, но важное. Эта история — хороший аргумент против бесконтрольной консолидации. Когда на одном инстансе живут боевые базы клиентов, архивы, копии для разработки и тестовые огрызки, любой такой дефект бьёт сразу по всем. Я развожу продакшен и всё остальное по разным инстансам не из перфекционизма, а именно ради этого: чтобы дефект в фоновом потоке стоил вам одного стенда, а не всего бизнеса на 40 минут.
- новый инстанс 2025 с десятками баз — `-T15608` сразу, в чек-лист установки
- включённый DAC и известный пароль sa/доступ sysadmin — до того, как понадобится
- мониторинг: THREADPOOL в ожиданиях и work_queue_count — в систему мониторинга, с порогом
- архивные и неиспользуемые базы — в offline, тест и разработку — на отдельный инстанс
- перед каждым CU — читать список известных проблем SQL Server 2025 целиком
Частые вопросы
У меня вообще нет Always On и вторичных реплик. Это точно моя проблема?
Да, наличие групп доступности роли не играет. Microsoft прямо пишет, что фоновый поток на каждую базу создаётся при её выводе в online, вызывает давление на пул рабочих потоков и снижает отзывчивость инстанса даже тогда, когда вторичные реплики не настроены. Более того, для сценария без реплик трейс-флаг 15608 всё равно назван необходимым временным обходом.
Можно включить флаг 15608 через DBCC TRACEON, не перезапуская сервер?
Нет, точнее — можно, но толку не будет. В документации сказано явно: флаг должен быть включён при старте, а включение его после запуска не останавливает фоновые потоки, уже созданные для баз, которые пришли в online. Единственный работающий способ — прописать `-T15608` в параметры запуска службы (или через mssql-conf на Linux) и перезапустить SQL Server.
Сколько баз считается «много»? Есть конкретный порог?
Microsoft порога не называет, и я тоже не буду выдумывать цифру. Считайте от пула потоков: он равен 512 при 4 и менее логических CPU и растёт по формуле 512 + ((логических CPU − 4) × 16) до 64 процессоров. Если число баз в online составляет заметную долю от этого пула, а фактическое active_workers_count в спокойный час уже близко к лимиту — вы в зоне риска независимо от абсолютного числа баз.
Не проще ли просто поднять max worker threads и не трогать флаги?
Проще, но это маскировка. Как аварийное действие в рабочее время — да, годится: RECONFIGURE применяется немедленно, без перезапуска движка. Как постоянное решение — нет: каждый поток занимает стек в памяти мимо буферного пула, а сама Microsoft рекомендует искать корневую причину, а не наращивать лимит. Правильная последовательность — временно поднять лимит, в ближайшее окно поставить стартовый флаг, потом вернуть лимит в 0.
Когда выйдет постоянное исправление и можно будет снять флаг?
На редакцию документа от 24 августа 2026 года Microsoft пишет, что исправление определено для будущего выпуска SQL Server 2025, конкретный CU не назван. Последний накопительный пакет на тот момент — CU8, сборка 17.0.4075.5 от 13 августа 2026 года, он вышел раньше и проблему не закрывает; вышедший 8 сентября CU8 + GDR (17.0.4085.5) — пакет безопасности. Проверяйте раздел known issues и readme каждого нового CU; снимать флаг нужно тоже с перезапуском службы и с проверкой по ERRORLOG.
Что делать, если инстанс уже не пускает и войти нечем?
Заходить по выделенному административному соединению: `sqlcmd -S ИМЯ_СЕРВЕРА -A -E` из командной строки или `ADMIN:ИМЯ_СЕРВЕРА` в SSMS в окне нового запроса. SQL Server резервирует под DAC ограниченные ресурсы именно для таких ситуаций; такое подключение на инстанс только одно. По умолчанию DAC пускает только локально: зайдите на сам сервер (RDP или консоль) и подключитесь оттуда. Если и это невозможно, а `remote admin connections` не включён, остаётся перезапуск службы — поэтому включайте удалённый DAC заранее на всех продакшен-инстансах.
Источники
- Microsoft Learn — SQL Server 2025 Known Issues — Раздел «SQL Server might become slow or unresponsive after creating or bringing online a large number of databases», редакция от 24.08.2026: причина — фоновый поток на базу от persisted statistics for readable secondary replicas, обход — стартовый trace flag 15608, постоянное исправление заявлено для будущего выпуска. https://learn.microsoft.com/en-us/sql/sql-server/sql-server-2025-known-issues?view=sql-server-ver17#sql-server-might-become-slow-or-unresponsive-after-creating-or-bringing-online-a-large-number-of-databases
- Microsoft Learn — Persisted statistics for readable secondary replicas — Описание функции для SQL Server 2025 (17.x) и Azure SQL Database: работа поверх Query Store for readable secondary replicas, новые колонки sys.stats (replica_role_id, replica_role_desc, replica_name), событие persisted_stats_operation, раздел Considerations — отдельной database scoped configuration для отключения функции нет. https://learn.microsoft.com/en-us/sql/relational-databases/performance/persisted-stats-secondary-replicas?view=sql-server-ver17
- Microsoft Learn — Server Configuration: max worker threads — Таблица автоматически вычисляемого числа рабочих потоков по количеству логических CPU (512 / 576 / 704 / 960 / 1472 / 4480 / 8576), формула «Default Max Workers + ((logical CPUs − 4) × Workers per CPU)», предупреждение о неотзывчивости инстанса и рекомендация искать корневую причину, а не поднимать лимит. https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/configure-the-max-worker-threads-server-configuration-option?view=sql-server-ver17
- Microsoft Learn — Latest updates and version history for SQL Server — Таблица сборок SQL Server 2025 (17.x): RTM 17.0.1000.7 от 18.11.2025; CU6 — KB5093421, 17.0.4055.5 от 17.06.2026; CU8 — KB5104822, 17.0.4075.5 от 13.08.2026; CU8 + GDR — KB5122769, 17.0.4085.5 от 08.09.2026. https://learn.microsoft.com/en-us/troubleshoot/sql/releases/download-and-install-latest-updates
- Microsoft Learn — DBCC TRACEON: Trace flags — Описание trace flag 15608: отключает функцию Persisted statistics for readable secondary replicas; для полного отключения флаг применяется на первичной и всех вторичных репликах; SQL Server 2025 (17.x) и новее; Scope: Startup only. https://learn.microsoft.com/en-us/sql/t-sql/database-console-commands/dbcc-traceon-trace-flags-transact-sql?view=sql-server-ver17
- Microsoft Learn — Diagnostic Connection for Database Administrators — DAC: sqlcmd -A и admin:<instance> в SSMS, по умолчанию только локальные подключения, remote admin connections, одно DAC-подключение на инстанс (ошибка 17810), рекомендация подключаться к master. https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/diagnostic-connection-for-database-administrators?view=sql-server-ver17
