11.8.26

Почему большие столбцы могут не влиять на логические чтения


Автор: Brent Ozar, Database Animations: Why Big Columns May Not Affect Logical Reads

Со временем таблицы — как и наша талия — имеют свойство увеличиваться. Мы постоянно добавляем всё новые и новые столбцы, один за другим, чтобы удовлетворить потребности приложений. Добавить «ещё один столбец» проще, чем выносить что-то в отдельную таблицу.

Когда вы работаете лишь с несколькими строками за раз, например, при вставке, обновлении, удалении или выборке одной строки по идентификатору, накладные расходы на дополнительные столбцы незначительны. SQL Server может нырнуть в эту одну строку и просто извлечь её, и поскольку она всё равно находится на одной странице размером 8 КБ, количество столбцов не влияет на операции с одной строкой.

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

Это лучше всего проиллюстрировать одной из моих Database Animations, показывающей разницу между индексом, содержащим только Id и DisplayName, и индексом, который включает набор широких строковых столбцов:


Посмотрите анимацию на сайте Брентозара: "Wide Rows Seek Vs Scan"

Меня забавляет финальный комментарий ИИ: «широкие столбцы бесплатно катаются на поиске» (wide columns ride free on seeks). Ну ладно. Это определённо звучит как то, что я мог бы сказать. (Я использую Claude Code для создания этих анимаций: мы вместе разрабатываем раскадровку, а затем он берёт на себя детали и удивляет меня такими мелочами).

По мере того как ваши строки становятся всё больше — либо из-за добавления столбцов, либо из-за расширения самих столбцов, таких как JSON и XML, или из-за того и другого, — SQL Server вынужден следить за длиной каждой строки. Если строка не помещается на страницу размером 8 КБ, SQL Server автоматически перемещает эти данные вне строки (off-row).

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

Если вы хотите действовать на опережение и уверены, что большинству операций эти большие столбцы не нужны, вы можете даже указать SQL Server, чтобы он по умолчанию хранил большие столбцы вне строки, даже если размер строки невелик. Ознакомьтесь с sp_tableoption:

EXECUTE sp_tableoption 'dbo.Users', 'large value types out of row', 1;

Давайте оживим. Слева у нас таблица, где все широкие столбцы остаются в строке, а справа мы использовали sp_tableoption, чтобы принудительно вынести их все вне строки, на собственные страницы, связанные указателем:


Посмотрите анимацию на сайте Брентозара: "Off Row Storage"

Пока вы не используете SELECT *, такая настройка имеет больше смысла, особенно для больших строковых столбцов, таких как JSON, XML и (N)VARCHAR(MAX), которые вы извлекаете только тогда, когда вытягиваете конкретные отдельные строки из базы данных. Столбец Users.AboutMe — отличный пример: мы не строим отчёты по содержимому AboutMe и не используем его для фильтрации, а просто выводим его при отображении страницы профиля конкретного пользователя.

Настройка sp_tableoption вступает в силу только для вновь вставленных или обновлённых строк. Если вы хотите применить её к данным, уже находящимся в таблицах, вам нужно будет выполнить перестроение индекса.

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

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