12.12.25

Почему в моей таблице-куче много пустых страниц?

Автор: Paul Randal, SQLskills SQL101: Why does my heap have a bunch of empty pages?

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

Вот вопрос, который мне часто задают (перефразирую):

«У меня есть большая таблица-куча, в которой пространство не освобождается, когда я удаляю большое количество записей, но когда я сжимаю базу данных, размер кучи уменьшается. Можете объяснить?»

11.12.25

Как оператор SELECT может изменить базу данных?

Автор: Paul Randal, SQLskills SQL101: How can a SELECT cause a database to change?

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

Это интересное заблуждение, о котором меня спрашивали на прошлой неделе: (перефразируя) «Наверняка операция SELECT не может привести к изменению базы данных, потому что она просто читает данные, а не изменяет их каким-либо образом, верно?».

Что ж, нет. На самом деле существует довольно много побочных эффектов у запросов, которые только читают данные и никогда не выполняют изменения данных (не считая, конечно, SELECT ... INTO). Вот четыре, которые сразу приходят на ум…

10.12.25

Производительность REGEX в SQL Server 2025 не так уж плоха!

Автор: Brent Ozar, Update: SQL Server 2025’s REGEX Performance Isn’t So Bad!

Ещё в марте 2025 года, когда Microsoft впервые анонсировала поддержку REGEX в SQL Server 2025 и Azure SQL DB, я провёл быстрое тестирование, и производительность была ужасающей. Она была плохой в трёх разных аспектах:

  1. Использование ЦП было ужасным — сжигалось 60 секунд процессорного времени для проверки нескольких миллионов строк
  2. Он отказывался использовать индекс
  3. Оценка кардинальности была ужасной, жёстко закодирована на уровне 30% от таблицы

После комментария Эрланда Соммарског в этом месяце я вернулся и снова запустил тесты с релизной версией SQL Server 2025. Отличные новости! Microsoft исправила 1 из проблем, и... ну, одна из них немного хитрая. Для демонстрации я собираюсь использовать большую базу данных Stack Overflow за апрель 2024 года, чтобы создать наихудший сценарий, затем начать с индекса на небольшой таблице Users и запросить её через regex, как мы делали в статье от марта 2025 года.

9.12.25

Как хранятся значения по умолчанию?

Автор: Paul Randal, How are default column values stored?

На занятии возник интересный вопрос: как хранится значение столбца по умолчанию и что происходит, если некоторые строки уже существуют при добавлении столбца, а затем значение по умолчанию меняется?

8.12.25

Почему страницы PFS нельзя восстановить

Автор: Paul Randal, Why PFS pages cannot be repaired

В Twitter состоялось краткое обсуждение того, почему страницы PFS (повреждённый заголовок, а не отдельные байты PFS) нельзя восстановить (поводом стал вопрос #sqlhelp о том, почему для них невозможно восстановление отдельной страницы, в отличие от других карт распределения базы данных). Для справки: их также нельзя исправить с помощью автоматического восстановления страниц с зеркала или в группе доступности (AG).

Страницы PFS встречаются каждые 8088 страниц в каждом файле данных и хранят байт информации о себе и о следующих 8087 страницах. Самая важная информация, которую они хранят, — это то, выделена ли страница (используется) или нет. Подробнее о страницах PFS и других картах распределения базы данных можно прочитать в этой записи блога.

Итак, почему их не может восстановить DBCC CHECKDB, когда все остальные карты распределения базы данных могут?

6.12.25

Что такое ожидания LOGMGR_RESERVE_APPEND?

Автор: Paul Randal, What are LOGMGR_RESERVE_APPEND waits?

Мне прислали вопрос по электронной почте о причине возникновения ожиданий LOGMGR_RESERVE_APPEND, и в следующем выпуске рассылки Insider я дал краткое объяснение. Это очень необычный тип ожидания, чтобы видеть его в качестве основного на сервере, и, по сути, его вообще редко встречают.

5.12.25

Код для анализа иерархии транзакций в журнале

Автор: Paul Randal, Code to analyze the transaction hierarchy in the log
Код для анализа иерархии транзакций в журнале транзакций SQL Server

В рассылке для MVP было обсуждение представления sys.dm_tran_database_transactions и того, как с его помощью нельзя точно определить, сколько журнала сгенерировала операция, поскольку оно не предоставляет сводных метрик для подтранзакций внутри внешней транзакции. Это делает его вывод несколько неинтуитивным.

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

Он предоставляет две хранимые процедуры, sp_SQLskillsAnalyzeLog и sp_SQLskillsAnalyzeLogInner, где первая использует вторую, а вторая рекурсивно вызывает саму себя.

4.12.25

Сравнение одноколоночных, многоколоночных и фильтрованных статистик в SQL Server

Автор: Kendra Little, Comparing Single Column, Multi-Column, and Filtered Statistics in SQL Server

Статистики в SQL Server теоретически просты: они помогают оптимизатору оценить, сколько строк может вернуть запрос.

На практике? Всё быстро становится странным. Особенно когда вы начинаете фильтровать по нескольким столбцам или задаётесь вопросом, почему оптимизатор думает, что вернутся миллионы строк, когда вы знаете, что их всего несколько сотен тысяч.

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

3.12.25

Восстановление данных: странные сбои SELECT при повреждении

Автор: Paul Randal, Data recovery: investigating weird SELECT failures around corruption

В списке рассылки MCM возникла интересная проблема с повреждением, и после того, как я её разобрал, подумал, что из этого получится хорошая статья в блоге на случай, если кто-то столкнётся с подобной проблемой.

В двух словах, проблема заключалась в таком повреждении, что простой запрос SELECT * завершался ошибкой, а запрос SELECT * с предложением ORDER BY работал.

Давайте разбираться!

1.12.25

Использование fn_dblog, fn_dump_dblog и восстановление с STOPBEFOREMARK до LSN

Автор: Paul Randal, Using fn_dblog, fn_dump_dblog, and restoring with STOPBEFOREMARK to an LSN

Я уже много писал в блоге о недокументированной функции fn_dblog, в написании которой я помогал (и мне ещё многое предстоит :-)), но вот одна функция, которую я ранее не упоминал в блоге: fn_dump_dblog (хотя я рассказывал о ней на конференциях).

Рассмотрим сценарий: кто-то удалил таблицу, и вы хотите выяснить, когда это произошло и, возможно, кто это сделал. Трассировка по умолчанию также переполнилась, поэтому вы больше не можете получить оттуда информацию об операции DDL.

28.11.25

Как работали бы индексы на читаемых вторичных репликах групп доступности (AG)?

Автор: Paul Randal, How would indexes on AG readable secondaries work?

В рассылке MVP появилось предложение ввести временные некластерные индексы на читаемых вторичных репликах AG — по аналогии с временной статистикой. Я ответил, что, на мой взгляд, реализовать это чрезвычайно трудно, и пообещал объяснить почему. Ниже — моя аргументация. Замечу: это не исчерпывающий перечень, а лишь основные проблемы, которые я вижу.