Как создать кластерный индекс на 100 ГБ таблицы


8

У меня есть таблица кучи, которая занимает около 104 ГБ дискового пространства с почти 3 миллиардами строк. Я пытаюсь создать кластерный индекс для этой таблицы в WeekEndingDateстолбце [ ]. У меня около 200 ГБ бесплатно в файле данных и около 280 ГБ бесплатно в базе данных tempdb.

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

CREATE CLUSTERED INDEX CX_WT_FOLD_HISTORY
ON WT_FOLD_HISTORY (WeekEndingDate ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = ON, 
IGNORE_DUP_KEY = OFF
, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, 
DATA_COMPRESSION = PAGE)

Я попробовал это и с SORT_IN_TEMPDB = ONи OFF. При ONего использовании заполняется база данных tempdb и вместе с OFFней заполняется диск с данными.

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

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

Вот моя оригинальная структура таблицы кучи:

CREATE TABLE [dbo].[WT_FOLD_HISTORY](
[WeekEndingDate] [varchar](50) NULL,
[Division] [varchar](50) NULL,
[Store] [varchar](50) NULL,
[SKUNumber] [varchar](50) NULL,
[UPC] [varchar](50) NULL,
[SalesUnits] [varchar](50) NULL,
[SalesCost] [varchar](50) NULL,
[SalesRetail] [varchar](50) NULL,
[InventoryUnits] [varchar](50) NULL,
[InventoryCost] [varchar](50) NULL,
[InventoryRetail] [varchar](50) NULL,
[OnOrderUnits] [varchar](50) NULL,
[OnOrderCost] [varchar](50) NULL,
[OnOrderRetail] [varchar](50) NULL,
[ReceiptUnits] [varchar](50) NULL,
[ReceiptCost] [varchar](50) NULL,
[ReceiptRetail] [varchar](50) NULL,
[PermanentMarkdowns] [varchar](50) NULL,
[ReturnsToVendor] [varchar](50) NULL,
[POSMarkdowns] [varchar](50) NULL,
[TimeFK] [smallint] NULL,
[LocationFK] [int] NULL,
[ItemFK] [int] NULL
) ON [AcademySports_DataFG1]

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

Может быть интересно узнать, почему некластерный индекс в этом случае неприемлем; [да, я знаю о различиях / преимуществах кластеризованных и некластеризованных ... просто любопытно, почему вы исключили некластеризованный индекс]; также, есть ли в таблице какие-либо некластеризованные индексы, и если да, то сколько места они используют? [интересно, может ли удаление текущих текущих некластеризованных индексов освободить достаточно места для создания кластеризованного индекса?]
markp-fuso

Вы пытались создать индекс с DATA_COMPRESSION=NONE? Если это работает, вы можете сжать потом.
Дан Гузман

Хороший вопрос. Я гуглю это. И прочитайте, вот что они сказали dba.stackexchange.com/questions/11956/… или stackoverflow.com/questions/2309889/… Это единственный правильный ответ.
KumarHarsh

1
Просто чтобы быть уверенным, не могли бы вы включить фактическое сообщение об ошибке, с которым не удается?
RDFozz

Ответы:


3

Если у вас есть краткосрочная потребность в дисковом пространстве, одним из вариантов будет:

  1. Временно уменьшите tempdb, освободив на диске столько места, сколько кажется безопасным.
  2. Создайте вторичный файл данных для БД, в которой находится таблица, на диске tempdb.
  3. Добавьте кластерный индекс в таблицу.
  4. Сократите вторичный файл, перенеся все данные из него.
  5. Удалите вторичный файл.
  6. Убедитесь, что файл tempdb имеет возможность расти до прежнего размера.
  7. Перестройте индексы в БД таблицы (удаление вторичного файла приведет к некоторой фрагментации).

ПРИМЕЧАНИЕ: как и предлагали другие, я бы делал это только после таких вещей, как временное удаление некластеризованных индексов из рассматриваемой таблицы. Это, в частности, позволит ускорить добавление кластеризованного индекса, поскольку некластеризованные индексы все равно придется перестраивать (при наличии кластеризованного индекса ключ индекса используется для поиска строк в самой таблице). ,

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

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


1

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

declare @rowcount int = 1;
while @rowcount > 0
begin
  delete top (5000) 
  from your_heap with(tablock) 
      output deleted.field1, ..., deleted.fieldN 
      into new_clustered_table;
  set @rowcount = @@rowcount;
end; 

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


Да, вы правы, я обновил свой ответ, но это была просто идея.
sepupic

0

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

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