InfoCity
InfoCity - виртуальный город компьютерной документации
Реклама на сайте







Размещение сквозной ссылки

 

Правда, о fill-factor в MS SQL Server

Kalen Delaney

Две недокументированные команды помогут разрешить загадку fill-factor

Индексы и fill factor

Сначала, мы должны понять основы того, как организованы индексы. SQL Server организовывает индексы как Би-дерево, с одной корневой страницей, являющейся отправной точкой для построения индекса. Корневая страница может иметь указатели на две или более страницы следующего уровня индекса, и, каждая из этих страниц, может иметь указатели на множество страниц следующего уровня. Последний уровень индекса - это уровень листьев, который должен содержать все индексные ключевые значения в сортируемой последовательности. В SQL Server 2000 эта последовательность может быть или возрастающей или в порядке убывания. Более ранние версии поддерживали все индексы в порядке возрастания. В кластерном индексе, уровень листьев - хранит данные, так что SQL Server хранит данные в отсортированном порядке. В не кластерном индексе, уровень листьев содержит указатели на данные. Fill factor - значение, которое Вы можете определить при создании индекса, чтобы сообщить SQL Server, насколько заполненными Вы хотите иметь страницы индекса. Вы можете определить fill factor в инструкции CREATE INDEX или когда Вы используете инструкцию CREATE TABLE или ALTER TABLE для определения первичного ключа или уникального ограничения на таблицу, после чего SQL Server автоматически построит индекс, и установит первичные ключи и уникальные ограничения. Конечно, Вы также можете определить fill factor, используя Enterprise Manager, при создании индекса или добавлении ограничений к таблице. Если Вы не определяете явно значение fill-factor, SQL Server установит значение fill factor по умолчанию. Чтобы определить, какое было принято значение fill factor по умолчанию, Вы можете выполнить следующую команду:

Вначале, нужно установить расширенный вывод конфигурационных значений:

EXEC sp_configure 'show advanced options', 1
GO
RECONFIGURE
GO

Затем, непосредственно смотрим значение по умолчанию 'fill factor':

EXEC sp_configure 'fill factor'
GO

В завершение, возвращаем изменённое значение назад:

EXEC sp_configure 'show advanced options', 0
GO
RECONFIGURE
GO

Если Вы не изменяли значение по умолчанию, Вы сможете увидеть в отчёте значение fill factor для параметра run_value (значение, используемое в настоящее время), установленное в "0":

Name………………minimum….maximum….config_value….run_value
---------------------------------------------------------------------------------------
fill factor (%)………0…………..100…………0………………0……….

fill factor установленный в "0" будет означать, что страницы индекса будут полностью заполнены, но в верхних уровнях индекса оставлено место для одной - двух индексных строк, которые могут быть добавлены позже. Фактически, Вы явно никогда не сможете присвоить fill factor значение "0" при создании индекса, потому что "0" является недопустимым значением для команды CREATE INDEX. Единственный способ получить fill factor равный "0" состоит в том, чтобы принять значение по умолчанию, если Вы не изменяли его до этого. Вы можете изменить значение fill factor по умолчанию, выполнив команду sp_configure и добавив второй параметр, который должен соответствовать желаемому, новому значению fill factor по умолчанию:

EXEC sp_configure 'fill factor', 80
GO
RECONFIGURE
GO

Вы должны остановить и перезапустить SQL Server для того, чтобы изменения вступили в силу. Новый fill factor будет действительно установлен, когда Вы увидите новое значение в столбце run_value.
Если Вы создаете индекс с fill factor = 80, страницы будут на 80 процентов заполнены, и верхние уровни индекса будут иметь достаточно места, оставленного в них для учёта одной или двух индексных строк.
Обратите внимание, что SQL Server не поддерживает оригинальное значение fill-factor, в момент добавления к таблице новых строк. fill factor только управляет степенью заполнения ваши страницы при первоначальном создании индекса. SQL Server хранит первоначальное значение fill factor в системной таблице sysindexes, в столбце OrigFillFactor. Если Вы выполняете команду DBCC DBREINDEX, которая перестраивает один или все индексы таблицы, определение fill factor равным "0" сообщает SQL Server, что необходимо перестроить индексы с оригинальным значением fill factor, и что индекс будет построен не обязательно со значением по умолчанию, которое Вы установили для вашего сервера.
Значение fill-factor может быть важно в среде, где выполняется очень много вставок. Уровень листьев индекса должен хранить все индексные, ключевые значения в сортируемой последовательности, так, что если кто-то будет вставлять новую строку в таблицу, индексное, ключевое значение в этой строке будет определять позицию строки в индексе (или таблице, если индекс кластерный). Например, если Вы имеете индекс по имени человека, вставка строки с именем "Marlin" потребует, чтобы SQL Server вставил новую индексную строку в ту же самую страницу с другими именами, которые начинаются на "Ma", возможно, между Margolin и Martin. Если страница, которой новая строка должна принадлежать, полностью заполнена, SQL Server разобьет её и свяжет с новой страницей в цепочку страницы. SQL Server переместит приблизительно половину строк из первоначальной, заполненной страницы в новую страницу. Мало того, что такое разделение страниц является ресурсёмкой операцией, которая может заметно сказаться на эффективности операций вставки, но вследствие того, что новая страница вероятнее всего окажется физически не непрерывной по отношению к первоначальной странице, Вы получите в результате фрагментацию индекса или таблицы.
Создание индекса с низким значением fill factor означает, что в вашей таблице зарезервировано место для последующего роста, что предотвращает разбиение страниц, откладывая, таким образом, связанные с этим проблемы. Однако, если ваши страницы заполнены только частично, чтобы хранить данные потребуется большее количество страниц и индекс может достичь весьма большого размера. Микрософт определил значение по умолчанию для fill-factor равное "0", как компромисс между наличием места для последующего роста и минимизацией размера таблицы и её индексов после создания. С fill factor = "0", уровень листьев будет заполнен, но страницы в верхних уровнях индекса, которые могут быть подвержены разбиению, если они станут заполненными, имеют некоторый резерв места для последующего роста.
В версиях SQL Server до 6.5, значение fill-factor = "100" подразумевало, что не только уровень листьев индекса, но и все уровни были бы полностью заполнены. Вообще, это значение используется только для таблиц, которые являются read-only (только для чтения). В SQL Server 6.5, Микрософт добавил новую опцию к команде CREATE INDEX. Если Вы также включаете опцию WITH PAD_Index, безотносительно значения fill-factor, Вы предпишете серверу устанавливать значение fill-factor всем уровням индекса, а не только уровню листьев. Так, создание индекса со значением fill-factor = "0" и включение опции PAD_Index, будет иметь тот же самый эффект, как использование значения fill-factor = "100". Но что будет, если fill factor = "100" с обычным значением PAD_Index?
Обратите внимание, что Вы можете определить значение fill-factor при определении первичного ключа или уникального ограничения на таблицу, потому что SQL Server автоматически строит индекс, чтобы поддержать эти ограничения. Однако, Вы не можете определить опцию PAD_Index одновременно с ограничением. Вы можете использовать её только в инструкции CREATE INDEX.

Загадка

Начинаясь с SQL Server 7.0, автор часто встречал такой вопрос: "Каково реальное различие между fill factor = "0" и fill factor = "100"?". Хотя SQL Server 2000 и 7.0 Books Online (BOL) сообщают, что fill factor = "100" означает, что все уровни индекса будут заполнены, много людей, очевидно, не думают, что это правда. Для исследования такого различия, автор использовал две недокументированные команды DBCC: DBCC IND и DBCC PAGE. Эти команды не перечислены в BOL, и Микрософт официально не поддерживает их, хотя статьи Микрософт иногда упоминают DBCC PAGE. Чтобы использовать эти недокументированные команды, Вы должны сначала установить флаг трассировки 3604, чтобы разрешить вывод недокументированных команд DBCC на экран клиента. DBCC IND, который требует три параметра, сообщает какие страницы принадлежат индексу. Первые два параметра: имя базы данных и имя таблицы; третий параметр устанавливает, какие результаты Вы хотите видеть в отчёте. Значение = "1", для третьего параметра степени подробность выводимой информации, говорит о том, что будут возвращены данные обо всех уровнях всех индексов в таблице. Код в Листинге №1 (см. в конце данной статьи) создает таблицу в 1000 строк в базе данных Pubs и генерирует последовательно увеличивающиеся целочисленные значения от 1 до 1000. Автор использует числовые значения, потому что они очень просто генерируются. Однако, он хранит их как символьные строки, потому что команда DBCC PAGE отображает символьные строки более ясно чем числовые значения, что удобно, если использовать команду DBCC PAGE для отображения полного содержания страниц.
После генерации 1000 строк, сценарий использует значение по умолчанию fill factor = 0, чтобы создать уникальный, кластерный индекс, затем используется DBCC IND, чтобы сгенерировать список всех страниц, которые принадлежат таблице и её индексам. DBCC IND возвращает 12-столбцов отчёта, но автору необходимы были только четыре из них:

- PagePID - идентификатор страниц, это значение будет использоваться во второй команде DBCC.
- IndexID - значение равное "0" устанавливается для страниц данных, "1" для страниц в верхних уровнях кластерного индекса, а большее чем "1" для не кластерных индексов.
- PageType - значение равное "1" устанавливается для страниц данных, "2" для индексных страниц, а "10" для страницы Index Allocation Map (IAM).
- IndexLevel - уровень индекса, на котором страница создана. Если IndexID равен "0", значит, IndexLevel также равен "0". Самое высокое значение IndexLevel у любого IndexID - для корневых страниц, причём, только одна страница будет иметь это максимальное значение IndexLevel.

Команда DBCC IND в сценарии Листинга №1 возвращает номера страниц для четырех страниц с PageType = 2; из них, три имеют IndexLevel = 0, а одна имеет IndexLevel = 1. Кроме того, если Вы работаете с базой данных, которая размещается более чем в одном файле, Вам будет также интересен столбец PageFID, который идентифицирует файл, содержащий страницу.

Примечание автора перевода: Если Вы используете для проверки приводимых в статье примеров кода вариант движка MSDE или у Вас не установлена база данных pubs, Вы можете отдельно установить её методом прикрепления из стандартного дистрибутива. Для MS SQL Server 2000 выглядеть это будет так: из дистрибутива, каталог …x86\DATA, скопируйте в нужное Вам расположение файлы pubs.mdf и pubs_log.ldf; снимите у этих файлов атрибут - только для чтения; в программе Enterprise Manager, посредством опции Databases\All Tasks\Attach Database прикрепите указанные файлы, откорректировав (если это необходимо) пути к их местоположению. После этого, вы получите сообщение об успешном прикреплении базы pubs и можете с ней работать.

Даже притом, что уровень листьев кластерного индекса хранит непосредственно данные, результат работы команды DBCC IND не рассматривает страницы данных как индексные страницы. Однако, эти будут именно те страницы данных, к которым относится значение fill factor, потому что они относятся к уровню листьев кластерного индекса. Вы можете идентифицировать эти страницы данных по следующей комбинации значений: PageType = 1, IndexID = 0, IndexLevel = 0.

Разгадка

Далее, для ответа на наш вопрос, выберем одну из страниц индекса и используем её, как параметр в команде DBCC PAGE. В SQL Server 2000 и 7.0 эта команда использует четыре параметры. Первый - это имя базы данных или идентификатор базы данных; второй - это номер файла; а третий - это номер страницы, полученный из отчёта DBCC IND. Четвертый параметр - это желательный формат отчёта. Например, значение четвёртого параметра, равное "0" устанавливает то, что Вы хотите видеть только колонтитул. Ниже представлена команда, которую выполнял автор статьи:

DBCC PAGE (pubs, 1, 285, 0)

Примечание автора перевода: третий параметр выбирайте из реальных результатов отчёта работы команды: DBCC IND(pubs, ff1, -1), полученного в вашем варианте установки базы pubs. Значение "285" может оказаться за рамками вашего распределения страниц.

Значение в колонтитуле, которое нам должно быть интересно, называется m_slotCnt. Оно сообщает число строк на заданной странице. Когда автор выполнил сценарий в Листинге №1 и затем использовал DBCC PAGE, чтобы посмотреть на одну из страниц данных, он увидел, что число строк на странице было равно 20-ти. Когда он аналогично выполнил DBCC PAGE для одной из индексных страниц на более низком уровне, чем корень, он увидел, что число строк там было равно 19-ти. Это было результат, который автор ожидал увидеть, т.е. страницы данных были заполнены строками, содержащими 390 байтов данных, плюс приблизительно 10 байт сверху, а значит, только 20 строк возможно разместить на одной странице, и страницы данных максимально заполнены. Строки индексов имеют тот же самый размер, потому что индекс строится на основе столбца случайных чисел (390), но вместо 20 индексных строк на странице, мы имеем только 19, потому что SQL Server зарезервировал место для одной дополнительной индексной строки.
Используя эти два инструментальных средства, DBCC IND и DBCC PAGE, автор смог ответить на вопрос о различие между fill factor = 0 и fill factor = 100. Выполняя тот же самый сценарий, но, явно устанавливая factor = 100, автор обнаружил, что число строк в страницах данных и индексных страницах было тем же самым, что и у кластерного индекса с fill factor = 0. Автор полагает, что дал Вам достаточно информации о том, как использовать эти инструментальные средства, чтобы Вы могли убедиться в полученных им результатах самостоятельно и смогли выполнить более глубокое исследование. Вы можете также узнать, что случается, если Вы установите опцию PAD_Index, при fill factor = 100.

LISTING 1: Script to Create Table and Index, Then Generate Page List

USE pubs
GO
CREATE TABLE ff1(col1 char(390) NULL)
GO

SET NOCOUNT ON
GO
DECLARE @i int
SET @i = 1
WHILE @i < 1001 BEGIN
  INSERT INTO ff1 SELECT CONVERT(char(390), @i)
  SET @i = @i + 1
END
GO
CREATE UNIQUE CLUSTERED INDEX indx1 on ff1(col1)
GO
DBCC TRACEON (3604)
GO
DBCC IND(pubs, ff1, -1)
GO


Реклама на InfoCity

Яндекс цитирования



Финансы: форекс для тебя








1999-2009 © InfoCity.kiev.ua