Каковы допустимые сценарии использования для таблиц HEAP?


31

В настоящее время я выполняю некоторые операции импорта данных в устаревшую систему и обнаружил, что в этой системе не используется ни один кластеризованный индекс. Быстрый поиск в Google познакомил меня с концепцией таблиц HEAP, и теперь мне интересно, в каких сценариях использования таблица HEAP должна быть предпочтительнее кластеризованной таблицы?

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


1
Вы говорите о SQL Server?
a_horse_with_no_name

@a_horse_with_no_name да, я забыл упомянуть, что sry
marc.d

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


Ответы:


22

Единственное действительное использование для

  • промежуточные таблицы, используемые в процессах импорта / экспорта / ETL.
  • специальное, временное и краткосрочное резервное копирование таблиц с использованием SELECT * INTO..

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

Обратите внимание, что кластеризованный индекс обычно немного мал по сравнению с размером данных: данные являются самым низким уровнем структуры индекса.

Кучи таблиц также имеют проблемы. По крайней мере, это:

Также см


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

Хороший вопрос, кстати.
Зейн

1
Одна небольшая настройка - если вы делаете SELECT INTO для быстрого создания резервной копии небольшой таблицы перед внесением изменений, по умолчанию создается куча. Я бы сказал, что это правильное применение - но это просто придирки. Я бы хотел избавиться от этой кучи, как только узнал, что моя работа закончена.
Брент Озар

@BrentOzar: Согласен, я делаю это все время сам. Дух моего ответа - «долгосрочные и постоянные таблицы», но я
обновлю

9

Основные соображения

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

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

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

  • Индексы на кучах ссылаются на RID, которые являются 64-битными. Как уже упоминалось, некластеризованные индексы в кластеризованной таблице ссылаются на ключ кластеризации, который может быть меньше (32-битный INT), таким же (64-битный BIGINT) или больше (48-битный DATETIME2()плюс 32-битный INT, или 128-битный GUID). Очевидно, что более широкие ссылки делают для более крупных и более дорогих индексов.

Требования к пространству

С этими двумя таблицами:

CREATE TABLE TmpClustered
(
ID1 INT NOT NULL,
ID2 INT NOT NULL
)
ALTER TABLE TmpClustered ADD CONSTRAINT PK_Tmp1 PRIMARY KEY CLUSTERED (ID1)
CREATE UNIQUE INDEX UQ_Tmp1 ON TmpClustered (ID2)

CREATE TABLE TmpNonClustered
(
ID1 INT NOT NULL,
ID2 INT NOT NULL
)
ALTER TABLE TmpNonClustered ADD CONSTRAINT PK_Tmp2 PRIMARY KEY NONCLUSTERED (ID1)
CREATE UNIQUE INDEX UQ_Tmp2 ON TmpNonClustered (ID2)

... каждая из которых заполнена 8,7 М записями, для данных обоих требовалось 150 МБ; 120 МБ для индексов кластеризованной таблицы, 310 МБ для индексов некластеризованной таблицы. Это отражает тот факт, что кластеризованный индекс является более узким, чем RID, и что кластеризованный индекс в основном является «халявой». Без уникальных индексов ID2необходимое пространство индекса уменьшается до 155 МБ для некластеризованной таблицы (наполовину, как и следовало ожидать), но только до 150 КБ. для кластеризованного ПК - почти ничего.

Таким образом, некластеризованный индекс 32-битного поля в кластерной таблице с 32-битным индексом (всего 64 бита, номинально) занял 120 МБ, а индекс 32-битного поля в куче с 64-битным RID (всего 96 бит, номинально) занял 155 МБ, что немного меньше, чем увеличение на 50%, которое наивно ожидалось бы при переходе с 64-битных на 96-битные ключи, но, конечно, есть издержки, которые уменьшают эффективную разницу в размере.

Заполнение двух таблиц и создание их индексов заняло одинаковое количество времени для каждой таблицы. Выполняя простые тесты, включающие сканирование или поиск, я не обнаружил существенных различий в производительности между таблицами, что соответствует официальному документу Microsoft, с которым gbn тщательно связан. Упомянутая бумага показывает значительную разницу для одновременного доступа; Я не уверен, почему это происходит, надеюсь, кто-то с большим опытом, чем я с большими объемами OLTP-систем, может сказать нам.

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

Остатки

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

Как отметил @gbn, простого способа сжатия кучи не существует. Однако, если ваша таблица постепенно увеличивается со временем - очень распространенный случай - будет мало потерь, так как пространство, освобожденное удалениями, будет заполнено новыми данными.

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

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

TL; DR

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

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


5

Я думаю, что высказывание «Единственное допустимое использование - для промежуточных таблиц, используемых в процессах импорта / экспорта / ETL», является, по меньшей мере, ограничением. Вы должны взять ожидаемый вариант использования данной системы, а затем выбрать, основываясь на достоинствах кучи или индексации организованных таблиц (я знаю, термин Oracle, но он хорошо его описывает).

Наш склад загружает ~ 1,5 миллиарда строк в день и должен поддерживать одновременную запись и обработку, а также чтение. Реляционное хранилище поддерживает базу данных OLAP, и, таким образом, операции чтения, как правило, представляют собой сканирование таблицы. Генерируемые отчеты и последующие каналы также обычно недостаточно избирательны, поэтому любой индекс будет полезен. Система поддерживает скользящее окно данных, и, таким образом, после загрузки таблицы мы редко пишем в нее снова, учитывая довольно плохую реализацию разбиения таблиц, требующую блокировки Sch-M для разбиений раздела, переключателей и слияний по сравнению с блокировками Sch-S для чтения и т. Д. Система должна была использовать много таблиц, хотя у нас есть и несколько секционированных таблиц. Использование многих таблиц облегчает сегментацию данных и циклы очистки, а также уменьшает конкуренцию.

Таким образом, дополнительные издержки на индексированную организованную таблицу (кластеризованную таблицу) в некоторых произвольных столбцах (столбцах) по сравнению с возможностью bcp в кучу, обработкой разделов OLAP, выполнением некоторых запросов сканирования таблицы, а затем через 3 дня отбрасывают это означает, что это Это просто не стоит. Обратите внимание, что в нашем случае данные возвращаются из большого кластера сетки, поэтому нет никакого упорядочения данных, поэтому вставка в таблицу с кластеризованным индексом может привести к другим проблемам, таким как «горячие точки» и разбиения страниц и тому подобное.

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

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

[Edit] Я, вероятно, должен прояснить, что только наши неразделенные таблицы фактов являются кучами. Секционированные таблицы и таблицы измерений имеют кластеризованные индексы для поддержки эффективного поиска и т. Д. [Правка2] Исправлено от 2,5 до 1,5 миллиардов. Но эти два числа находятся рядом друг с другом. Что происходит при наборе ответов на телефоне, я думаю ...

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.