Welcome to TechNet Blogs Sign in | Join | Help

Построение индексов – часть 6: построение секционированного индекса (Partitioned Index)

Существуют две основных категории секционированных индексов:

  • Выровненные (когда базовая таблица и индекс используют одинаковые функции секционирования)
  • Невыровненные (когда базовая таблица и индекс используют разные функции секционирования (включая случай, когда базовая таблица вообще не секционирована, а индекс секционирован).

(см. Типы построения индексов - Часть 2 (секционированные индексы)) 

 

 

Построение выровненных секционированных индексов 

 

Последовательное построение выровненных секционированных индексов 

 

     NL

                /       \

             ПТС   Построитель

                           \

                        [Сортировка]

                             \

                          Сканирование

 

ПТС: Постоянный  табличный скан (the purpose of CTS is to provide partition IDs for index builder)

NL: Nested Loop (вложенный цикл)

 

ПТС предоставляет ID секций внутренней стороне Nested Loop-а, который строит индекс для каждой секции. Промежуточные структуры сортировки создаются для каждой секции, но так как мы создаем их последовательно (одна за одной) и окончательное дерево индекса мы строим последовательно для каждой секции, нам не нужно держать все эти промежуточные структуры сортировки одновременно.

 

Как это влияет на требования к свободному дисковому пространству:

-         В случае сортировки в пользовательской базе данных (установка по умолчанию) сортировка происходит в каждой filegroup для каждой соответствующей секции. Это означает, что каждая файловая группа должна иметь те же 2.2*(Размер секции) свободного дискового пространства для того, чтобы можно было построить индекс.

      Пример:

                  Имеются 3 секции расположенные в файловых группах FG1, FG2, FG3. Размер индексных данных (соответственно для каждой секции) – 1Gb, 2Gb и 3Gb. В этом случае потребуется: 2.2*1 = 2.2Gb свободного пространства в FG1; 2.2*2 = 4.4Gb свободного пространства в FG2, 2.2*3 = 6.6Gb свободного пространства в FG3. Таким образом, общий размер свободного дискового пространства, необходимого в этом случае - 9.9Gb.

 

-         В случае сортировки в tempdb (SORT_IN_TEMPDB = ON) свободное пространство в tempdb будет переиспользоваться для сортировки каждой секцию Так как сортировка секций происходит последовательно одна за одной, потребуется только 2.2*(Размер наибольшей секции) свободного дискового пространства в tempdb.

      Пример:

                  Возьмем пример рассмотренный выше: имеются 3 секции расположенные в файловых группах FG1, FG2, FG3. Размер индексных данных (соответственно для каждой секции) – 1Gb, 2Gb и 3Gb. В этом случае потребуется: 3.3Gb свободного дискового пространства в tempdb.

 

Некоторые соображения об использовании памяти:

 Так как в одно и тоже время существует только одна промежуточная структура сортировки, потребуется 40 страниц памяти (необходимая память), чтобы начать построение индекса. 40 страницэто минимальное требование.

Общее объем памяти = минимально требуемая память + дополнительная память*.

 

* дополнительная память высчитывается как размер  calculated as строки умноженный на  предполагаемое количество строк, предоставленное оптимизатором запросов.

 

Читайте в следующих постах о параллельном построении выровненного секционированного индекса J

С наступающим Новым Годом!

Несколько заранее, в связи с тем, что ухожу с завтрашнего дня в отпуск, хочу поздравить всех с наступающим Новым Годом!

 

Желаю всем удачи и счастья в новом году! А также – самых интересных проектов, самого безбагистого софта, самых довольных клиентов…

 

Постараюсь, в следующем году писать поживее и почаще. У меня еще есть, что сказать о SQL ServerJ. В общем, как говориться – оставайтесь с нами! 

Построение индексов – Часть 6. (План для индексирования представления без гистограмм)

Построитель …  

                                      |                

                                    Х

                   /                  |                 \

Сортировка… Сортировка …  Сортировка …

                   |                  |                 |

Сканирование  Сканирование  Сканирование

 

Если гистограммы не доступны на момент построения индекса (например, при построении индекса для представления) – т.е. мы не можем получить статистику о распределении данных (собрать статистику возможно только для «реального» объекта, и пока кластерный индекс для представления не построен, ее нет, поэтому выбирается другой план) – SQL Server не может воспользоваться планом построения индекса описанном в раньше (см. ноябрьские посты об интервальном секционировании). SQL Server выбирает в данном случае план с обычным параллельным сканированием, который ничего не знает о распределении данных.

 

Как это работает.

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

Почему этот план может быть относительно медленным. SQL Server строит дерево индекса последовательно, плюс некоторые дополнительные издержки на операцию ‘merge exchange’ (слияние промежуточных структур сортировки в одну).

 

 

Некоторые соображения об использовании памяти:

         

            При параллельном плане построения индекса SQL Server строит несколько сортировочных структур одновременно, следовательно, базовые требования к памяти становятся выше, а расчет выглядит несколько иначе, чем при последовательном построении.

Для расчета требуемой памяти учитывается 1) необходимая память, 2) дополнительная память.

Каждая структура сортировки требует 40 страниц памяти (необходимая память). 

Например, если уровень параллелизма – DOP = 2, строятся 2 структуры сортировки и требуется 80 страниц (каждая страница – 8KB) памяти, в то время как общая дополнительная память остается такой же, независимо от DOP (это происходит потому, что общее число строк не зависит от DOP).

Например, если последовательный план требует 500 страниц дополнительной памяти, то и параллельный план получит 500 страниц дополнительной памяти, а каждый исполнитель – 500/DOP страниц дополнительной памяти + 40 страниц необходимой памяти.

 

Читайте в следующих постах о построении секционированного индекса (Partitioned Index) J

Запоздалое вступление - Типы построения индексов - Часть 2 (секционированные индексы)

-         Построение секционированных или построение несекционированных индексов:

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

Выровненные секционированные индексы:

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

Для выравнивания с базовой таблицей индексу необязательно использовать функцию секционирования с тем же именем. Однако функции секционирования индекса и базовой таблицы не должны существенно различаться, то есть:

1) аргументы функции секционирования должны иметь один и тот же тип данных,

2) функции должны определять одинаковое количество секций и

3) функции должны определять для секций одинаковые граничные значения.

 

Если вы строите некластерный индекс на секционированной таблице  и не указываете функцию секционирования, то этот некластерный индекс будет секционированным и выровненным (см. пример).

Пример:

Create Partition Function pf (int)

as range right for values (NULL,  1,  100)

                 

Create Partition Scheme ps

as Partition pf

TO ([PRIMARY], [FileGroup1], [FileGroup1], [FileGroup1])

                 

Create table t (c1 int, c2 int)

on ps(c1)

                 

Create Index idx_t on t(c1)

 

Невыровненные секционированные индексы:

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

Вы можете превратить несекционированную таблицу в секционированную построив на ней секционированный кластерный индекс – это также будет невыровненное построение индекса (см. пример).

Пример:

Create Partition Function pf (int)

as range right for values (NULL,  1,  100)

                 

Create Partition Scheme ps

as Partition pf

TO ([PRIMARY], [FileGroup1], [FileGroup1], [FileGroup1])

                 

Create table t (c1 int, c2 int)

                 

Create clustered Index idx_t on t(c1)

on ps(c1)

 

Замечание: Если имеется секционированный кластерный индекс (пример выше) и вы его удаляете, то таблица останется секционированной в соответствии с той же схемой секционирования. Исключение составляет случай, когда вы указываете опцию MOVE TO во время удаления индекса.

Пример:

Drop Index idx_t on t

WITH(MOVE TO new_ps(c1))

 

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

Запоздалое вступление - Типы построения индексов - Часть 1

Коллеги! Мне тут было сделано справедливое замечание (offline J), что я начала рассказывать о различных планах построения индексов, не дав краткого предварительного обзора того, какие типы индексов (с точки зрения их построения) существуют и чем они отличаются. Например, фоновое построение индекса и секционированные индексы – это новые возможности SQL Server 2005, и не у всех была возможность с ними уже ознакомиться.

Исправляюсь, и публикую небольшой обзор:

 

-          Фоновое построение индекса или Автономное построение индекса:

В SQL Server 2005, вы можете создать, перестроить или удалить (удалить - только кластерный) индекс в фоновом (оперативном) режиме. Параметр ONLINE (ONLINE = ON) разрешает одновременный доступ пользователей к базовой таблице или данным кластеризованного индекса и всем связанным некластеризованным индексам во время выполнения этих операций с индексами. Например, пока пользователь перестраивает кластеризованный индекс, он и другие пользователи могут продолжать обновление базовых данных и осуществлять к ним запросы. При выполнении DDL-операций в автономном режиме (ONLINE = OFF – установка по умолчанию), таких как построение или перестроение кластеризованного индекса, эти операции удерживают монопольные блокировки на базовые данные и связанные индексы.

Рекомендуется выполнять оперативные операции с индексами в производственной среде, работающей 24 часа в сутки и семь дней в неделю, когда имеется насущная необходимость одновременных действий пользователей во время выполнения операций с индексами.

Пример:

Create index idx_t on t(c1, c2)

WITH (ONLINE = ON)

 

-         Последовательное построение индекса или  Параллельное построение индекса:

На многопроцессорных компьютерах при построении индексов могут использовать больше процессоров для выполнения сканирования и сортировки, связанных с построением индекса. Число процессоров, задействованных при выполнении одной индексной инструкции, определяется параметром конфигурации max degree of parallelism (устанавливается системной процедурой sp_configure: по умолчанию = 0 – использовать все доступные процессоры), опцией MAXDOP (устанавливается командой Create Index или Alter Index) , текущей рабочей нагрузкой и, в случае несекционированного индекса, распределением данных в первой ключевой колонке. Параметр max degree of parallelism ограничивает число процессоров, используемых при параллельном выполнении плана. Иными словами, он устанавливает потолок – использовать не больше данного числа процессоров, но можно меньше (исключение MAXDOP = 0 – использовать все доступные процессоры). Если компонент SQL Server определяет, что система загружена, степень параллелизма индексной операции автоматически уменьшается перед началом выполнения инструкции.

Пример:

Create index idx_t on t(c1, c2)

WITH (MAXDOP = 2)

-- ограничивает # используемых процессоров до 2.

 

      -         Построение Индекса с использованием пользовательской базы данных для хранения промежуточных результатов сортировки или с использованием   tempdb (SORT_IN_TEMPDB):

           

Я уже писала об этом в одном из предыдущих постов. Вкратце повторюсь.

При создании или перестроении индекса можно установить параметр SORT_IN_TEMPDB в значение ON, чтобы указать SQL Server базу tempdb для хранения промежуточных результатов сортировки, которые используются для построения индекса. Данный параметр увеличивает место на диске, временно занимаемое при построении индекса, но с его помощью можно сократить время, необходимое для создания или перестройки индекса (смотри сентябрьский пост «Использование опции sort_in_tempdb»). По умолчанию, данные промежуточной сортировки хранятся в той же базе данных, в которой находится индексируемая таблица.

Пример:

Create clustered Index idx_t on t(c1)

WITH (SORT_IN_TEMPDB = ON)

 

 

Завтра напишу про секционированные / несекционированные индексы.

Построение индексов – Часть 5.

Интервальное секционирование* (для высокопроизводительных машин).

 

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

 

             X

                     /                |                \

Построитель… Построитель …  Построитель …  

                    \                 |                 /

                        Обмен/Слияние

                   /                  |                 \

Сортировка… Сортировка …  Сортировка …

                   |                  |                 |

Сканирование  Сканирование  Сканирование

 

 

Этот план параллельного построения индексов выбирается обработчиком запросов когда выполняются следующие условия:

1)      Уровень параллелизма (DOPDegree of parallelism) – число процессоров, которые могут быть использованны для построения индекса > 8;

2)      Доступна статистика;

3)      Достаточно памяти (правило следующее: память необходимая для построения индекса должна составлять < 3% от общей памяти доступной обработчику запросов, при этом минимальная память необходимая для построения индекса = минимальная память на одну сортировочную структуру * число сортировочных структур.)

 

Этот план параллельного построения индекса может быть самым эффективным, но требует больше памяти (минимальный объем памяти необходимый для этого плана = #DOP*#DOP*40страниц, т.к. каждый исполнитель создает #DOP сортировочных структур). Можно использовать опцию MAXDOP инструкции Create Index чтобы ограничить уровень параллелизма (DOP) при построении индекса и, как результат, требования к объему памяти.

 

Как работает этот план?

Каждый исполнитель сканирует страницу данных их кучи параллельно. Когда один из исполнителей заканчивает очередную страницу, обработчик запросов получает следующую страницу данных. Порядок сканирования страниц каждым исполнителем в данном случае не важен и, как результат, исполнители не простаивают в ожидании следующей страницы данных (сравните с планом для машин малой мощности, где порядок сканирования важен и каждый исполнитель сканирует только предназначенные ему секции). Дополнительным преимуществом является то, что базовый объект сканируется один раз (сравните с планом для машин малой мощности, где объект сканируется несколько раз). 

После завершения сканирования создаются и заполняются #DOP сортировочных структур для каждого исполнителя.

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

После того как «обмен» завершен, каждый исполнитель строит свое собственное дерево и координирующий процесс осуществляет «сшивку» всех деревьев в общее дерево индекса (также как при использовании плана для машин малой мощности).

 

Выигрыш в производительности достигается здесь за счет того, что не приходиться сканировать целиком весь объект для каждого исполнителя, но в то же время некоторые потери производительности происходят из-за дополнительного обмена данными между исполнителями. Также (повторюсь) этот план требует больше памяти для своего исполнения.

 

В следующих сообщениях:

- План для индексирования представления;

- Требования к памяти при параллельном построении индексов;

...

Построение индексов – Часть 4.

Параллельное, автономное построение несекционированного индекса (Offline, Parallel, No Partitioning).

 

Существует 3 основных категории паралльных планов построения индекса:

 

1)      Интервальное секционирование (для машин малой мощности);

2)      Интервальное секционирование (для высокопроизводительных машин);

3)      План для индексирования представления без гистограм (No histogram Indexed view).

 

Интервальное секционирование* (для машин малой мощности).

 

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

 

             X

                     /                |                \

Построитель… Построитель …  Построитель …  

                   |                  |                 |

Сортировка… Сортировка …  Сортировка …

                    \                 |                /

       Сканирование (для каждого исполнителя (worker))

 

Этот план параллельного построения индексов выбирается обработчиком запросов когда выполняются следующие условия:

1)      Уровень параллелизма (DOPDegree of parallelism) – число процессоров, которые могут быть использованны для построения индекса < 8

или DOP > 8, но память требуемая для постоения индекса превышает определенный % общей доступной обработчику запросов памяти (см. в следущем посте - интервальное секционирование (для высокопроизводительных машин));

2)      Доступна статистика (в общем-то, все случаи, кроме индекситрованных представлений, дают возможность получить статистику; если она не существует на момент создания индекса, она будет сгенерирована).

 

Используя имеющуюся статистику обработчик запросов распределяет данные на N сегментов, где N = DOP * 3. Зная оценочное число строк для каждого сегмента объем работ делится на DOP секций между исполнителями – по одной секции на исполнителя (это делается для выравнивания нагрузки). Используя секционное сканирование каждый исполнитель получает данные принадлежащие к его секции, хотя для этого и приходится сканировать все данные для каждого исполнителя, т.е., если, например, DOP = 4, вся таблица будет просканирована 4 раза.

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

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

 

* Не путайте, пожалуйста, «интервальное секционирование (Range partition)» - тип параллельного плана построения индекса и «секционированный индекс (Partitioned Index)» - тип индекса.

 

В следующих сообщениях:

- Интервальное секционирование (для высокопроизводительных машин);

- План для индексирования представления;

- Требования к памяти при парллельном построении индексов;

...

Построение индексов – Часть 3. Использование опции Sort_In_Tempdb.

В предыдущем сообщении я упоминала использование опции Sort_In_Tempdb при создании индексов. Эта опция заставляет SQL Server использовать базу данных tempdb для хранения промежуточных результатов сортировки. Немнго подробнее о том, когда это может быть полезно...

 

Использование этой опции может ускорить процесс построения (перестроения) индекса, если база данных tempdb и пользовательская база данных (БД, в которой находится индексируемая таблица) находятся на разных физических дисках. В этом случае, операции чтения страниц данных из «кучи» (или имеющегося индекса) и записи промежуточных результатов сортировки (в tempdb) происходят на разых дисках и, следовательно, осуществляются более последовательно. Таким образом операции чтения и записи будут осуществляться более эффективно.

Дополнительное преимущество - экстенты вновь созданного индекса располагаются более непрерывно (индекс менее фрагментирован), что должно положительно сказаться на производительности запросов использующих этот индекс в дальнейшем.

 

Замечание №1: база данных tempdb должна иметь достаточно свободного пространства для хранения результатов промежуточной сортировки (см. предыдущее сообщение), если вы используете опцию Sort_In_Tempdb.

 

Замечание №2: Если сортировка может быть произведена в памяти или если сортировка не требуется, опция Sort_In_Tempdb будет проигнорированна.

Построение индексов – Часть 2.

Чтобы построить индекс необходимо сначала отсортировать heap. Таким образом, процесс построения индекса будет выглядеть следующим образом: сканирование «кучи», сортировка (если возможно – в оперативной памяти*) и собственно построение дерева индекса на основании результатов сортировки. Эти промежуточные результаты требуют дополнительного места (либо в памяти, либо на диске). SQL Server, тем не менее, освобождает каждый экстент структуры, используемой для хранения этих промежуточный результатов, как только все данные из него будут добавлены в дерево индекса. Таким образом, общий объем дискового пространства (в случае, если сортировка в памяти невозможна), необходимого для построения индекса уменьшается с 3х («куча» + сортировочная стрктура + дерево индекса) до 2,2х (приблизительно).

 

*SQL Server не гарантирует сортировку в памяти. Решение о том производить ли сортировку в памяти принимается на основе размера выделенной для создания индекса оперативной памяти, количества и размера строк.

 

Сортировка в оперативной памяти повышает производительность процесса построения индекса, но не является обязательной. SQL Server всегда может сбросить результаты промежуточной сортировки на диск.  SQL Server всегда будет стараться выделить достаточно памяти для сортировки в памяти, но при построении больших индексов, маловероятно, что удасться обойтись без сбрасывания данных на диск. По  умолчанию, SQL Server использует пользовательскую базу данных (базу данных, содержащую индексируемую таблицу) для сбрасывания промежуточных результатов сортировки; в случае, если при создании индекса указана опция sort_in_tempdb, для этих целей будет использована база данных tempdb.

 

Каждая структура, хранящая данные промежуточной сортировки (в случае параллельного построения индекса может понадобиться несколько таких структур одновременно) требует как минимум 40 страниц памяти и, если этот объем памяти не может быть предоставлен, операция завершится возвращением сообщения об ошибке.

 

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

Построение индексов – Часть 1.

Небольшое вступление...

 

При работе с большими базами данных время построения/перестроения индкса может стать узким местом. Особенно критично это для баз данных который должны быть доступны постоянно. Как организовать текущее обслуживание индексов в таких базах данных? Здесь необходимо ответить на несколько вопросов:

 

- Возможно ли сделать БД недоступной и работать с индексами автономно (Offline) или же необходимо обслуживать индексы в фоновом режиме (Online Index Build)?

- Насколько производительно посторение/ перестроения индекса и можно ли его как-то улучшить?

- Если обслуживание индекса происходит в фоновом режиме (Online), то как это повлияет на производительность пользовательских процессов происходящих параллельно в БД?

- Достаточно ли дополнительных ресурсов, которые потребуются для работы с индексами (дополнительная память, дополнительное дисковое пространство) и как можно минимизировать требования к таким ресурсам?

 

и т.д.

 

Стратегия построения индексов в SQL Server может быть различной и зависит от конкретных потребностей пользователя. Различные стратегии можно разделить на следующие (ортогональный) категории:

 

- Автономное построение индекса (Offline Index Build);

- Фоновое построение индекса (Online Index Build).

 

- Последовательное посторение индекса (Serial Index Build);

- Параллельное построение индекса (Parallel Index Build).

 

- Построение секционированного индекса (Partitioned Index):

          .Выравненного секционированного индекса (aligned Partitioned Index),

          .Невыравненного секционированного индекса (non-aligned Partitioned Index); 

- Построение несекционированного индекса (non-Partitioned Index).

 

- Использовать для промежуточных результатов сортировки пользовательскую базу данных (БД, в которой находится индексируемая таблица);

- Использовать для промежуточных результатов сортировки Tempdb.

 

 

На сегодня – все.

Надеюсь, следующий мой пост ДЕЙСТВИТЕЛЬНО будет посвящен стратегии автономного последовательного построения индекса без секционирования. J

Introduction...

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

Зовут меня Людмила Фокина. Родилась, выросла и получила образование в Питере. С 2000 года работаю в Microsoft в Редмонде в команде SQL Server. Соответственно, как уже догадался проницательный читатель, рассказывать в своем блоге я буду, в основном, о SQL Server-е; как о новых функциях последней его версии SQL Server 2005, так и о давно существующих, но, возможно, не слишком широко известных его функциональностях. Вобщем, о том, с чем я сталкиваюсь в своей работе -исполнение запросов, оптимизация запросов, T_SQL.

Как уже упоминали мои коллеги из Редмонда, пишущие свои блоги на русскм, существует определенная трудность с адекватным переводом технических терминов, так что если что-то будет выглядеть особенно коряво, you are welcome, как говориться  - поправляйте, уточняйте...

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

Ну, чтоже, начнем, пожалуй...

Мой следующий пост будет посвящен постейшему типу построения индекса в SQL Server – автономное (offline) последовательное (serial) без секционирования (no partitioning). Следите за рекламой :)

More Posts « Previous page
 
Page view tracker