Освобождение неиспользуемого пространства таблицы SQL Server

11

У меня есть таблица в SQL Server 2012 Express с большим количеством неиспользуемого пространства.

Мне нужно освободить место в базе данных.

| ИМЯ | Ряды | ЗАБРОНИРОВАНО | ДАННЫЕ | INDEX_SIZE | UNUSED |
| ------------- | -------- | -------------- | ----------- --- | ------------ | -------------- |
| MyTableName | 158890 | 8928296 КБ | 5760944 КБ | 2248 КБ | 3165104 КБ |

Как мне получить SQL для выпуска 3165104KB?

Я уже попробовал:

Alter table MyTableName Rebuild
DBCC CLEANTABLE (MyDbName,"MyTableName ", 0)
ALTER INDEX ALL ON MyTableName REORGANIZE ; 
ALTER INDEX PK_Image ON MyTableName REBUILD WITH (ONLINE = OFF) 

Вот таблица:

CREATE TABLE [dbo].[MyTableName](
    [ImageID] [int] IDENTITY(1,1) NOT NULL,
    [DateScan] [datetime] NULL,
    [ScanImage] [image] NULL,
 CONSTRAINT [PK_Image] PRIMARY KEY CLUSTERED 
(
    [ImageID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, 
    ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

Единственное, что мы сделали, это заменили ScanImageв каждой строке намного меньшим изображением (это то, сколько там неиспользуемого пространства).

DermFrench
источник

Ответы:

10

Единственное, что мы сделали, - заменили ScanImageв каждом ряду изображение намного меньшего размера (так много неиспользуемого пространства)

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

Пример кода, который добился лучшего сокращения пространства для меня со структурой таблицы в вопросе:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

SET XACT_ABORT ON;

BEGIN TRAN

SELECT [ImageID],
       [ScanImage]
INTO   #Temp
FROM   [dbo].[MyTableName]

ALTER TABLE [dbo].[MyTableName]
  DROP COLUMN [ScanImage]

/*Allocation unit not removed until after this*/
ALTER INDEX PK_Image ON MyTableName REBUILD

ALTER TABLE [dbo].[MyTableName]
  ADD [ScanImage] IMAGE NULL

UPDATE [dbo].[MyTableName]
SET    [ScanImage] = T.[ScanImage]
FROM   [dbo].[MyTableName] M
       JOIN #Temp T
         ON M.ImageID = T.[ImageID]

DROP TABLE #Temp

COMMIT 

Все в транзакции, поэтому, если машина выйдет из строя, она будет откатана. Вероятно, может сделать с некоторой обработкой ошибок или, по крайней мере SET XACT_ABORT ON. Я использовал SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;для предотвращения любых одновременных изменений во время или после копирования и потери.

Количество страниц больших объектов, зарезервированных после уменьшения размера imageво всех строках, было следующим:

+ ------------------------------------------------- - + --------------------- + ------------------------- +
| Событие | lob_used_page_count | lob_reserved_page_count |
+ ------------------------------------------------- - + --------------------- + ------------------------- +
| Вставлено 10000 строк по 100000 байтов в каждой | 135005 | 135017 |
| Обновлены все строки до 10 000 байт данных изображения | 31251 | 135012 |
| Реорганизовать | 23687 | 25629 |
| Удалить и повторно добавить данные изображения | 13485 | 13489 |
+ ------------------------------------------------- - + --------------------- + ------------------------- +
Мартин Смит
источник
1
Или, если таблица большая, то BCP выводит данные, а затем BULK INSERT обратно во время обслуживания.
Кин Шах
6

Пытаться

ALTER INDEX PK_Image ON MyTableName REBUILD WITH (ONLINE = OFF)

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

Также возможно, что кластерный индекс определяется с FILLFACTOR менее 100%. Если установить коэффициент заполнения, например, 66%, 1/3 каждой страницы данных останется пустой для будущего использования. Если это проблема, вы можете изменить коэффициент заполнения, используяALTER INDEX PK_Image ON MyTableName REBUILD WITH (ONLINE = OFF, FILLFACTOR=100)

Если вы недавно удалили поле переменной длины из таблицы, вы также можете попробовать DBCC CLEANTABLE( Databasename, "MyTableName")

В Книге онлайн (BOL) есть отличная статья о перестройке индексов на http://technet.microsoft.com/en-us/library/ms188388%28v=sql.100%29.aspx

Макс Вернон
источник
2

Убедитесь, что режим восстановления БД установлен SIMPLE.

изменить столбец как VARBINARY(MAX).

Затем попробуйте скопировать данные в совершенно новую таблицу.

Проверьте новый размер таблицы, используя sp_spaceused "tablename". Если вас устраивает неиспользуемое пространство таблицы, то проверьте неиспользуемое пространство базы данных, используя ту же команду, не указывая имя таблицы. Это пространство все еще находится в файлах базы данных и не передается в ОС.

Вы можете удалить исходную таблицу и переименовать новую таблицу, или сделать то же самое снова, и использовать исходное имя таблицы, если вы не доверяете операции переименования (я не доверяю полностью).

Если это работает, то последний шаг прост: вы знаете, как сжать файлы и освободить неиспользуемое пространство.

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

Ануп Шах
источник
1

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

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

  1. Добавьте новый файл в файловую группу.
  2. Беги DBCC SHRINKFILE(file, EMPTYFILE). Так как вы сжимаете MDF, он в конечном итоге потерпит неудачу, поскольку системные метаданные не могут быть перемещены. Однако распределение пустых BLOB-объектов не перемещается.
  3. Беги DBCC SHRINKFILE(newfile,EMPTYFILE). Это переместит данные назад, минус избыточное пространство.
  4. Удалите новый файл (теперь пустой) из файловой группы.

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

ДКП
источник
-1

Реорганизуйте кластеризованный индекс - у него есть данные в узлах, так что ... он, вероятно, фрагментирован.

TomTom
источник
Я попытался запустить: ALTER INDEX ALL ON [MyTableName] REORGANIZE;
DermFrench
3
Перестрой его;) Не реорганизуй.
TomTom