21.5.26

Когда TempDB растёт «вширь»: как RCSI и длинные транзакции незаметно разрушают SQL Server


Автор: Steve Stedman, When TempDB Grows “Up and to the Right”: How RCSI and Open Transactions Quietly Break SQL Server

Одна из самых опасных проблем SQL Server — та, которую вы не замечаете, пока диск не заполнится, а производственная система не упадёт. TempDB особенно хороша в таком типе отказа — она незаметно растёт в фоновом режиме, пока внезапно не становится проблемой для всех.

Недавно мы просматривали отчёт о распределении пространства TempDB (TempDB Allocation History Report), и он прекрасно проиллюстрировал проблему, с которой мы сталкиваемся всё чаще по мере того, как растёт применение READ COMMITTED Snapshot Isolation (RCSI). RCSI обычно является правильным выбором, но когда что-то идёт не так, TempDB может расти взрывным образом, и большинство команд не понимают почему, пока не становится слишком поздно.

Почему отчёт о распределении пространства TempDB важен

Отчёт о распределении пространства TempDB наиболее ценен на производственных системах с реальной рабочей нагрузкой. Тестовые серверы редко показывают что-то интересное, потому что на них нет длительных транзакций, высокой конкурентности или продолжительной пользовательской активности.

Однако на производственных серверах этот отчёт рассказывает подлинную историю. Он показывает, как используется пространство TempDB с течением времени, включая:

  • Хранилище версий (version store)
  • Пользовательские объекты (user objects)
  • Внутренние объекты (internal objects)
  • Временные таблицы (temporary tables)

Когда TempDB начинает неожиданно расти, этот отчёт позволяет визуально определить коренную причину вместо того, чтобы гадать.

RCSI — не враг

Давайте проясним: RCSI — это не плохая функция. На самом деле, мы рекомендуем её примерно для 99% производственных сред SQL Server. Она кардинально снижает блокировки, позволяя читателям обращаться к версиям строк вместо ожидания блокировок.

Но у RCSI есть цена, и эта цена оплачивается в TempDB.

Когда RCSI включена, SQL Server хранит старые версии строк в хранилище версий (version store), которое находится в TempDB. В нормальных условиях эти версии автоматически удаляются после завершения транзакций.

Проблема возникает, когда они не завершаются.

Открытые транзакции и хранилище версий

Открытая транзакция при включённой RCSI предотвращает очистку старых версий строк в хранилище версий. Пока эта транзакция остаётся открытой, SQL Server должен сохранять каждую версию строки, необходимую для поддержки согласованного чтения.

Именно здесь всё идёт наперекосяк.

Мы видели клиентов, у которых приложение оставляло транзакцию открытой на часы или даже дни, в то время как другая активность продолжалась нормально. Каждая операция обновления, удаления или вставки в течение этого времени создавала всё новые версии. Хранилище версий продолжало расти, и TempDB следовала за ним.

В одном реальном случае у клиента образовалась TempDB размером четыре терабайта в системе, где ни одна из пользовательских баз данных даже близко не была такого размера. Виновником оказалась одна единственная открытая транзакция в сочетании с RCSI.

Что показал бы график

Когда вы смотрите на отчёт о распределении пространства TempDB в подобном сценарии, проблема выявляет себя мгновенно.

Если график почти полностью состоит из использования хранилища версий, вы знаете, что проблема связана с RCSI. Никаких догадок. Никакого копания в десятках запросов. Просто чёткий сигнал, указывающий на открытые транзакции.

То, что вы часто увидите, — это шаблон роста «вверх и вправо» (up and to the right growth pattern). Это хорошо, когда вы смотрите на цифры продаж. Это ужасно, когда вы смотрите на размер TempDB.

TempDB должна колебаться. Она должна расти и сжиматься. Когда она только растёт — и никогда не возвращается обратно — у вас проблема с очисткой.

Связываем с открытыми транзакциями

Именно здесь объединение отчётов становится мощным инструментом.

Когда проблема заключается в росте хранилища версий TempDB, отчёт об открытых транзакциях (Open Transactions Report) почти всегда подтверждает это. Обычно вы найдёте:

  • Длительные транзакции
  • Спящие сеансы (sleeping sessions), удерживающие транзакции открытыми
  • Код приложения, который никогда не выполняет фиксацию (COMMIT) или откат (ROLLBACK) должным образом

Пока эти транзакции остаются открытыми, TempDB будет продолжать расти. Резервные копии не помогут. Перезапуск заданий не поможет. Единственное реальное исправление — это выявление и устранение открытой транзакции.

Почему большинство команд упускают это из виду

Большинство ИТ-команд не следят за TempDB достаточно внимательно. Ещё меньше понимают, как взаимодействуют RCSI, очистка хранилища версий и открытые транзакции.

К тому времени, когда TempDB заполняет диск, ущерб уже нанесён. Сервер может перестать отвечать, приложения падают, и внезапно все спрашивают: «Как это произошло?»

Ответ почти всегда один: это произошло медленно, тихо и без надлежащего мониторинга.

Как мы выявляем это до того, как это перерастёт в кризис

Именно такие проблемы предотвращаются с помощью проактивного мониторинга SQL Server, нужно непрерывно отслеживать использование TempDB, рост хранилища версий и открытые транзакции. Когда TempDB начинает демонстрировать тенденцию к росту «вширь», мы расследуем это немедленно — задолго до того, как диск заполнится.

Такая видимость позволяет нам:

  • Выявлять раздувание хранилища версий, связанное с RCSI, на раннем этапе
  • Точно определять открытые транзакции, вызывающие задержки очистки
  • Работать с командами разработчиков для исправления коренной причины
  • Предотвращать сбои вместо того, чтобы реагировать на них
Пример запроса по использованию tempdb:
SELECT SUM(user_object_reserved_page_count) * 8 / 1024.0 AS user_objects_mb, SUM(internal_object_reserved_page_count) * 8 / 1024.0 AS internal_objects_mb, SUM(version_store_reserved_page_count) * 8 / 1024.0 AS version_store_mb, SUM(unallocated_extent_page_count) * 8 / 1024.0 AS unallocated_mb, SUM(version_store_reserved_page_count) * 8 / 1024.0 / NULLIF( (SUM(user_object_reserved_page_count) + SUM(internal_object_reserved_page_count) + SUM(version_store_reserved_page_count) + SUM(unallocated_extent_page_count)) * 8 / 1024.0, 0) * 100 AS version_store_pct FROM tempdb.sys.dm_db_file_space_usage;
Чтобы найти виновную открытую транзакцию, из-за которой пухнет хранилище версий, выполните следующий запрос. Он покажет все открытые транзакции, которые держат версии в TempDB, отсортированные по длительности:
SELECT tst.session_id, tst.transaction_id, tat.transaction_begin_time, DATEDIFF(SECOND, tat.transaction_begin_time, GETDATE()) AS open_duration_seconds, tat.transaction_state, s.program_name, s.host_name, s.login_name, s.status, tst.session_id AS blocker_session_id FROM sys.dm_tran_active_transactions tat JOIN sys.dm_tran_session_transactions tst ON tst.transaction_id = tat.transaction_id JOIN sys.dm_exec_sessions s ON s.session_id = tst.session_id WHERE tat.transaction_state = 2 -- активная (не зафиксирована) AND tat.transaction_begin_time IS NOT NULL ORDER BY tat.transaction_begin_time ASC; -- самые старые сверху

Что делать

  1. Найти проблемную транзакцию по session_id.
  2. Проверить, можно ли её закрыть (KILL <session_id> — крайняя мерия, если это не системный процесс).
  3. Исправить код приложения, который не завершает транзакцию (добавить COMMIT или ROLLBACK).
  4. Настроить мониторинг, чтобы алерт срабатывал при version_store_mb > 10 ГБ или при наличии транзакций старше N секунд.





Накопительный пакет обновления SQL Server 2025 CU5 - KB5084896

Описание: KB5084896

Скачать: SQLServer2025-KB5084896-x64.exe

Дата выпуска: 20.05.2026

SQL Server 2025 — Версия: 17.0.4045.5

20.5.26

«Нет, мы не обновляемся. Что мы упускаем?»

Автор: Thomas Rushton, “No, we’re not upgrading. What are we missing out on?”

SQL Server 2016 — покойся с миром, RIP, скатертью дорога (хотя последнее звучит как-то слишком сурово). SQL Server 2016 выходит из расширенной поддержки (extended support) 14 июля — в День взятия Бастилии, без комментариев — 2026 года. Это следует из политики фиксированного жизненного цикла Microsoft (Fixed Lifecycle Policy): выпуск, примерно пять лет основной поддержки (mainstream support), в течение которой вы получаете исправления, обновления безопасности, улучшения производительности и функциональности, и ещё примерно пять лет расширенной поддержки (extended support), в течение которой вы получаете обновления безопасности и не многое другое. После этой даты Microsoft крайне редко выпускает какие-либо обновления за пределами платной программы расширенных обновлений безопасности (Extended Security Update, ESU), поэтому продолжение использования продукта, срок поддержки которого истёк (EOL product), следует рассматривать как экстренную меру только для краткосрочного использования.

Тащим "багаж" через планы запросов: почему широкие запросы становятся неподъёмными


Автор: Kendra Little, Carrying Baggage Through Query Plans: Why Wide Queries Get Heavy

Я постоянно вижу этот шаблон: «широкий» запрос, который возвращает много столбцов и менее 100 тысяч строк, выполняется медленно. SQL Server замедляется, когда тащит большие объёмы «багажа» через весь план запроса, подобно путешественнику-одиночке, который таскает по аэропорту огромные чемоданы вместо того, чтобы забрать их поближе к месту назначения.

SQL Server часто минимизирует доступ к данным, захватывая все столбцы, которые ему понадобятся, на раннем этапе выполнения запроса, а затем выполняя соединения и фильтрацию. Это означает, что презентационные столбцы (presentation columns) подхватываются рано.

Презентационные столбцы: Термин, который я позаимствовала у Эрика Дарлинга (Erik Darling). Он относится к описательным столбцам, которые нужны вам в конечном результирующем наборе, но вы не используете их для соединения или фильтрации.

Этот шаблон — подхватывание «багажа» данных на раннем этапе и перетаскивание его через план — также является одной из причин, почему SQL Server любит память так же, как:

  • енот любит мусор,
  • пингвин любит хорошо прошлёпать,
  • администратор баз данных любит говорить «нет»,
  • инструкция MERGE любит хаос,
  • я люблю свободный проход в магазине.

19.5.26

Чего ждёт SOS_SCHEDULER_YIELD в SQL Server: причины и реакция


Автор: Steve Stedman, Decoding SOS_SCHEDULER_YIELD Wait Type in SQL Server: Causes and Solutions

Узнайте о типе ожидания SOS_SCHEDULER_YIELD в SQL Server: выявите причины, такие как конкуренция за ЦП, и найдите решения для настройки производительности с помощью экспертных советов. Этот тип ожидания возникает, когда задача добровольно уступает своё время ЦП, чтобы позволить другим задачам выполняться, что является естественной частью модели кооперативного планирования SQL Server. Однако, когда эти ожидания становятся частыми или продолжительными, они могут указывать на глубинные проблемы, ухудшающие производительность системы, что делает критически важным понимание их последствий.

По своей сути, SOS_SCHEDULER_YIELD отражает давление на ресурсы ЦП, поскольку задачи выстраиваются в очередь для выполнения. Хотя случайные уступки ожидаемы в загруженной среде, чрезмерные ожидания могут указывать на конкуренцию за ЦП, плохо оптимизированные запросы или даже аппаратные ограничения. Определение того, является ли этот тип ожидания симптомом более серьёзной проблемы, требует системного подхода к мониторингу и анализу, что в конечном итоге может привести к значительному повышению производительности.

В этой статье мы разберём тип ожидания SOS_SCHEDULER_YIELD, изучим его причины и то, когда он становится проблемой для вашей среды SQL Server. Мы проведём вас через методы диагностики, чтобы выявить корневые проблемы, и предоставим практические решения для снижения их влияния. Будь вы администратором баз данных (DBA) или разработчиком, понимание и устранение этого типа ожидания поможет обеспечить работу вашей базы данных на пике эффективности.

18.5.26

Неудобная правда о скалярных функциях


Автор: Luca Biondi, The Dangerous Truth About Scalar Functions in 45 Seconds

Скалярные пользовательские функции (Scalar UDF) — это тихие убийцы производительности SQL Server. В этой статье я расскажу, почему они скрывают свою истинную стоимость и как превращают быстрый запрос в покадровую катастрофу.

В двух словах

  • Скалярные UDF принудительно вызывают покадровое выполнение (RBAR — Row-By-Agonizing-Row): они обходят мощные алгоритмы оптимизатора, основанные на работе с наборами данных. 
  • Подавление параллелизма (Parallelism): Традиционные скалярные функции заставляют весь ваш запрос выполняться в одном потоке. 
  • Скрытые затраты: Планы выполнения часто показывают стоимость UDF как 0%, маскируя огромные накладные расходы на ЦП. 
  • Исправление: Используйте встроенные табличные функции (Inline Table-Valued Functions, iTVF) или функцию встраивания скалярных функций (Scalar Inlining), появившуюся в SQL Server 2019+. 

17.5.26

Клонирование с помощью аварийно-устойчивых снимков в Hyper-V


Автор: Anthony Nocentino, Crash-Consistent Snapshot Cloning - Hyper-V Edition

Если вы следили за моей серией статей о резервном копировании через снимки с помощью T-SQL (T-SQL Snapshot Backup), то большая часть из того, о чём я рассказывал, требовала участия SQL Server в создании снимка: заморозка операций записи, резервное копирование метаданных, скоординированный рабочий процесс. Эта статья покрывает другую сторону этого вопроса: клонирование, устойчивое к аварийному отказу (crash-consistent cloning). Никакой заморозки записи. Никакого резервного копирования. Никакого восстановления на момент времени. Просто клон тома «сырых» данных, который SQL Server автоматически восстанавливает при подключении.

15.5.26

Новая официальная документация о принудительной параметризации (Forced Parameterization)


Автор: Brent Ozar, New Official Documentation on Forced Parameterization

Я обожаю хорошую документацию.

Много лет я указывал людям на документацию SQL Server 2008 о принудительной параметризации (Forced Parameterization) — действительно полезном инструменте для уменьшения раздувания кэша планов, получения более точных переиспользуемых планов запросов и включения функций интеллектуальной обработки запросов (Intelligent Query Processing) SQL Server 2019 и 2022, многие из которых полагаются на один и тот же текст запроса, поступающий повторно с течением времени, чтобы настроить его. Однако эта документация была довольно скудной.

14.5.26

"Подводные камни" неявных преобразований


Автор: Luca Biondi, The Hidden Cost of Implicit Conversions in 45 Seconds

Неявные преобразования — это молчаливые убийцы производительности, которые превращают молниеносные поиск по индексу (Index Seek) в мучительно медленные просмотры индекса (Index Scan). В этой статье я
покажу вам, как обнаружить их за 45 секунд и вернуть ваши такты ЦП!

В двух словах

  • Убийство SARGability: Неявные преобразования не позволяют SQL Server эффективно использовать поиск по индексу. 
  • Накладные расходы на ЦП: Преобразование каждой строки в таблице во время сравнения значительно увеличивает использование ЦП. 
  • Старшинство типов данных (Data Type Precedence): SQL Server всегда преобразует тип с более низким приоритетом в тип с более высоким. 
  • Исправление: Согласуйте типы данных столбца и параметра или используйте явное приведение типов в правильном направлении. 

13.5.26

Бывают дни, когда я хочу бросить всё это с кэшем планов и Хранилищем запросов!

Автор: Brent Ozar, There Are Days When I Feel Like Giving Up on the Plan Cache and Query Store

В теории мониторинг производительности SQL Server довольно прост:

  1. Изучите главные типы ожиданий (wait types) на сервере.
  2. Найдите запросы, вызывающие эти типы ожиданий.
  3. Исправьте эти запросы или улучшите реакцию сервера на них (индексы, настройки и т.д.).

Но на практике шаг 2 ужасен, потому что:

  • Приложения отправляют на сервер баз данных непараметризованные строки.
  • Пользователи Entity Framework строят запросы с FromSqlRaw или string.Format().
  • Пользователи Entity Framework пишут запросы с .Contains, который создаёт непараметризованный список IN, даже когда ищут всего одно значение (в EF9 стало лучше).
  • Люди пишут неаккуратный динамический SQL, который просто вставляет значения прямо в строку запроса.
  • Разработчики SaaS-решений помещают каждого клиента в собственную базу данных, и планы не переиспользуются между базами данных.

Исправление безопасности для SQL Server 2025 CU4 - KB5089899

Описание: KB5089899

Скачать: SQLServer2025-KB5089899-x64.exe

Дата выпуска: 12.05.2026

SQL Server 2025 — Версия: 17.0.4040.1

Исправление безопасности для SQL Server 2025 GDR - KB5091223

Описание: KB5091223

Скачать: SQLServer2025-KB5091223-x64.exe

Дата выпуска: 12.05.2026

SQL Server 2022 — Версия: 17.0.1115.1